summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-03-16 05:22:07 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-03-16 05:22:07 +0000
commitcb5b5163fe5912de3e31665435e0a339dcb78f70 (patch)
tree2e3af60932ff888794bcad1c71cdedf72cfb252c /Graphics/GraphicsEngineVulkan
parentFixed issue with setting scissor rects in D3D12 backend (diff)
downloadDiligentCore-cb5b5163fe5912de3e31665435e0a339dcb78f70.tar.gz
DiligentCore-cb5b5163fe5912de3e31665435e0a339dcb78f70.zip
Added vulkan backend stub
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt181
-rw-r--r--Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h60
-rw-r--r--Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h139
-rw-r--r--Graphics/GraphicsEngineVulkan/include/CommandContext.h372
-rw-r--r--Graphics/GraphicsEngineVulkan/include/CommandListManager.h67
-rw-r--r--Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h61
-rw-r--r--Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h77
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h532
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h164
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h142
-rw-r--r--Graphics/GraphicsEngineVulkan/include/GenerateMips.h64
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h128
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h170
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RootSignature.h433
-rw-r--r--Graphics/GraphicsEngineVulkan/include/SamplerVkImpl.h57
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h82
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h309
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h418
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourcesVk.h95
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h80
-rw-r--r--Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h70
-rw-r--r--Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h62
-rw-r--r--Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h117
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanResourceBase.h55
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h56
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanTypeDefinitions.h189
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtils.h30
-rw-r--r--Graphics/GraphicsEngineVulkan/include/pch.h47
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/BufferViewVk.h47
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/BufferVk.h61
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h60
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h56
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h57
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/RenderDeviceFactoryVk.h122
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h82
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/SamplerVk.h50
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/ShaderResourceBindingVk.h45
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/ShaderVk.h50
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h65
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/TextureViewVk.h47
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/TextureVk.h56
-rw-r--r--Graphics/GraphicsEngineVulkan/readme.md11
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp43
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp493
-rw-r--r--Graphics/GraphicsEngineVulkan/src/CommandContext.cpp321
-rw-r--r--Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp109
-rw-r--r--Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp84
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DLLMain.cpp49
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp429
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp939
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp171
-rw-r--r--Graphics/GraphicsEngineVulkan/src/GenerateMips.cpp196
-rw-r--r--Graphics/GraphicsEngineVulkan/src/GraphicsEngineVk.def2
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp404
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp414
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp634
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RootSignature.cpp1033
-rw-r--r--Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp64
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp152
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp87
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp1093
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourcesVk.cpp93
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp89
-rw-r--r--Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp275
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp61
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp546
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanResourceBase.cpp30
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp302
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtils.cpp47
-rw-r--r--Graphics/GraphicsEngineVulkan/src/pch.cpp24
70 files changed, 13250 insertions, 0 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
new file mode 100644
index 00000000..d3eb99fc
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -0,0 +1,181 @@
+cmake_minimum_required (VERSION 3.10)
+
+project(GraphicsEngineVk CXX)
+
+set(INCLUDE
+ include/BufferVkImpl.h
+ include/BufferViewVkImpl.h
+ include/CommandContext.h
+ include/CommandListVkImpl.h
+ include/CommandListManager.h
+ include/CommandQueueVkImpl.h
+ include/VulkanResourceBase.h
+ include/VulkanTypeConversions.h
+ include/VulkanTypeDefinitions.h
+ include/VulkanUtils.h
+ include/DescriptorHeap.h
+ include/DeviceContextVkImpl.h
+ include/DynamicUploadHeap.h
+ include/GenerateMips.h
+ include/pch.h
+ include/PipelineStateVkImpl.h
+ include/RenderDeviceVkImpl.h
+ include/RootSignature.h
+ include/SamplerVkImpl.h
+ include/ShaderVkImpl.h
+ include/ShaderResourceBindingVkImpl.h
+ include/ShaderResourceCacheVk.h
+ include/ShaderResourceLayoutVk.h
+ include/ShaderResourcesVk.h
+ include/SwapChainVkImpl.h
+ include/TextureVkImpl.h
+ include/TextureViewVkImpl.h
+)
+
+set(INTERFACE
+ interface/BufferVk.h
+ interface/BufferViewVk.h
+ interface/CommandQueueVk.h
+ interface/DeviceContextVk.h
+ interface/PipelineStateVk.h
+ interface/RenderDeviceVk.h
+ interface/RenderDeviceFactoryVk.h
+ interface/SamplerVk.h
+ interface/ShaderVk.h
+ interface/ShaderResourceBindingVk.h
+ interface/SwapChainVk.h
+ interface/TextureVk.h
+ interface/TextureViewVk.h
+)
+
+
+set(SRC
+ src/BufferVkImpl.cpp
+ src/BufferViewVkImpl.cpp
+ src/CommandContext.cpp
+ src/CommandListManager.cpp
+ src/CommandQueueVkImpl.cpp
+ src/VulkanResourceBase.cpp
+ src/VulkanTypeConversions.cpp
+ src/VulkanUtils.cpp
+ src/DescriptorHeap.cpp
+ src/DeviceContextVkImpl.cpp
+ src/DynamicUploadHeap.cpp
+ src/GenerateMips.cpp
+ src/PipelineStateVkImpl.cpp
+ src/RenderDeviceVkImpl.cpp
+ src/RenderDeviceFactoryVk.cpp
+ src/RootSignature.cpp
+ src/SamplerVkImpl.cpp
+ src/ShaderVkImpl.cpp
+ src/ShaderResourceBindingVkImpl.cpp
+ src/ShaderResourceCacheVk.cpp
+ src/ShaderResourceLayoutVk.cpp
+ src/ShaderResourcesVk.cpp
+ src/SwapChainVkImpl.cpp
+ src/TextureVkImpl.cpp
+ src/TextureViewVkImpl.cpp
+)
+
+#set(SHADERS
+# shaders/GenerateMips/GenerateMipsGammaCS.hlsl
+# shaders/GenerateMips/GenerateMipsGammaOddCS.hlsl
+# shaders/GenerateMips/GenerateMipsGammaOddXCS.hlsl
+# shaders/GenerateMips/GenerateMipsGammaOddYCS.hlsl
+# shaders/GenerateMips/GenerateMipsLinearCS.hlsl
+# shaders/GenerateMips/GenerateMipsLinearOddCS.hlsl
+# shaders/GenerateMips/GenerateMipsLinearOddXCS.hlsl
+# shaders/GenerateMips/GenerateMipsLinearOddYCS.hlsl
+#)
+#
+#set_source_files_properties(${SHADERS} PROPERTIES
+# VS_SHADER_TYPE Compute
+# VS_SHADER_ENTRYPOINT main
+# VS_SHADER_MODEL 5.0
+# VS_SHADER_VARIABLE_NAME "g_p%(Filename)"
+# VS_SHADER_OUTPUT_HEADER_FILE "${CMAKE_CURRENT_BINARY_DIR}/CompiledShaders/GenerateMips/%(Filename).h"
+# #VS_SHADER_FLAGS "/O3"
+#)
+
+add_library(GraphicsEngineVkInterface INTERFACE)
+target_include_directories(GraphicsEngineVkInterface
+INTERFACE
+ interface
+)
+target_link_libraries(GraphicsEngineVkInterface
+INTERFACE
+ GraphicsEngineInterface
+)
+
+add_library(GraphicsEngineVk-static STATIC
+ ${SRC} ${INTERFACE} ${INCLUDE} ${SHADERS}
+ readme.md
+ #shaders/GenerateMips/GenerateMipsCS.hlsli
+)
+
+add_library(GraphicsEngineVk-shared SHARED
+ ${SRC} ${INTERFACE} ${INCLUDE} ${SHADERS}
+ src/DLLMain.cpp
+ src/GraphicsEngineVk.def
+ readme.md
+ #shaders/GenerateMips/GenerateMipsCS.hlsli
+)
+
+target_include_directories(GraphicsEngineVk-static
+PRIVATE
+ #${CMAKE_CURRENT_BINARY_DIR}/CompiledShaders
+ include
+)
+
+target_include_directories(GraphicsEngineVk-shared
+PRIVATE
+ #${CMAKE_CURRENT_BINARY_DIR}/CompiledShaders
+ include
+)
+
+set(PRIVATE_DEPENDENCIES
+ BuildSettings
+ Common
+ TargetPlatform
+ GraphicsEngine
+)
+
+set(PUBLIC_DEPENDENCIES
+ GraphicsEngineVkInterface
+)
+
+target_link_libraries(GraphicsEngineVk-static PRIVATE ${PRIVATE_DEPENDENCIES} PUBLIC ${PUBLIC_DEPENDENCIES})
+
+target_link_libraries(GraphicsEngineVk-shared PRIVATE ${PRIVATE_DEPENDENCIES} PUBLIC ${PUBLIC_DEPENDENCIES})
+target_compile_definitions(GraphicsEngineVk-shared PUBLIC ENGINE_DLL=1)
+
+# Set output name to GraphicsEngineVk_{32|64}{r|d}
+set_dll_output_name(GraphicsEngineVk-shared GraphicsEngineVk)
+
+set_common_target_properties(GraphicsEngineVk-shared)
+set_common_target_properties(GraphicsEngineVk-static)
+
+source_group("src" FILES ${SRC})
+
+source_group("dll" FILES
+ src/DLLMain.cpp
+ src/GraphicsEngineVk.def
+)
+
+source_group("include" FILES ${INCLUDE})
+source_group("interface" FILES ${INTERFACE})
+#source_group("shaders" FILES
+# ${SHADERS}
+# shaders/GenerateMips/GenerateMipsCS.hlsli
+#)
+
+set_target_properties(GraphicsEngineVk-static PROPERTIES
+ FOLDER Core/Graphics
+)
+set_target_properties(GraphicsEngineVk-shared PROPERTIES
+ FOLDER Core/Graphics
+)
+
+set_source_files_properties(
+ readme.md PROPERTIES HEADER_FILE_ONLY TRUE
+)
diff --git a/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h
new file mode 100644
index 00000000..3c6770ef
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h
@@ -0,0 +1,60 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::BufferViewVkImpl class
+
+#include "BufferViewVk.h"
+#include "RenderDeviceVk.h"
+#include "BufferViewBase.h"
+#include "DescriptorHeap.h"
+
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+/// Implementation of the Diligent::IBufferViewVk interface
+class BufferViewVkImpl : public BufferViewBase<IBufferViewVk>
+{
+public:
+ typedef BufferViewBase<IBufferViewVk> TBufferViewBase;
+
+ BufferViewVkImpl( IReferenceCounters *pRefCounters,
+ IRenderDevice *pDevice,
+ const BufferViewDesc& ViewDesc,
+ class IBuffer *pBuffer,
+ DescriptorHeapAllocation &&HandleAlloc,
+ bool bIsDefaultView);
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface );
+
+ //virtual Vk_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override{return m_DescriptorHandle.GetCpuHandle();}
+
+protected:
+ // Allocation in a CPU-only descriptor heap
+ DescriptorHeapAllocation m_DescriptorHandle;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h
new file mode 100644
index 00000000..f4cc6c96
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.h
@@ -0,0 +1,139 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::BufferVkImpl class
+
+#include "BufferVk.h"
+#include "RenderDeviceVk.h"
+#include "BufferBase.h"
+#include "BufferViewVkImpl.h"
+#include "VulkanResourceBase.h"
+#include "DynamicUploadHeap.h"
+
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+
+/// Implementation of the Diligent::IBufferVk interface
+class BufferVkImpl : public BufferBase<IBufferVk, BufferViewVkImpl, FixedBlockMemoryAllocator>, public VulkanResourceBase
+{
+public:
+ typedef BufferBase<IBufferVk, BufferViewVkImpl, FixedBlockMemoryAllocator> TBufferBase;
+ BufferVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &BuffViewObjMemAllocator,
+ class RenderDeviceVkImpl *pDeviceVk,
+ const BufferDesc& BuffDesc,
+ const BufferData &BuffData = BufferData());
+ BufferVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &BuffViewObjMemAllocator,
+ class RenderDeviceVkImpl *pDeviceVk,
+ const BufferDesc& BuffDesc,
+ void *pVkBuffer);
+ ~BufferVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+
+ virtual void UpdateData( IDeviceContext *pContext, Uint32 Offset, Uint32 Size, const PVoid pData )override;
+ virtual void CopyData( IDeviceContext *pContext, IBuffer *pSrcBuffer, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size )override;
+ virtual void Map( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags, PVoid &pMappedData )override;
+ virtual void Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags )override;
+
+#ifdef _DEBUG
+ void DbgVerifyDynamicAllocation(Uint32 ContextId);
+#endif
+
+ /*virtual IVkResource *GetVkBuffer(size_t &DataStartByteOffset, Uint32 ContextId)override final
+ {
+ auto *pVkResource = GetVkResource();
+ if(pVkResource != nullptr)
+ {
+ VERIFY(m_Desc.Usage != USAGE_DYNAMIC || (m_Desc.BindFlags | (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) != 0, "Expected non-dynamic buffer or a buffer with SRV or UAV bind flags");
+ DataStartByteOffset = 0;
+ return pVkResource;
+ }
+ else
+ {
+ VERIFY(m_Desc.Usage == USAGE_DYNAMIC, "Dynamic buffer is expected");
+
+#ifdef _DEBUG
+ DbgVerifyDynamicAllocation(ContextId);
+#endif
+ DataStartByteOffset = m_DynamicData[ContextId].Offset;
+ return m_DynamicData[ContextId].pBuffer;
+ }
+ }
+ */
+
+ virtual void* GetNativeHandle()override final
+ {
+ return nullptr;
+#if 0
+ VERIFY(GetVkResource() != nullptr, "The buffer is dynamic and has no pointer to Vk resource");
+ size_t DataStartByteOffset = 0;
+ auto *pVkBuffer = GetVkBuffer(DataStartByteOffset, 0);
+ VERIFY(DataStartByteOffset == 0, "0 offset expected");
+ return pVkBuffer;
+#endif
+ }
+/*
+ virtual void SetVkResourceState(Vk_RESOURCE_STATES state)override final{ SetState(state); }
+
+ Vk_GPU_VIRTUAL_ADDRESS GetGPUAddress(Uint32 ContextId)
+ {
+ if(m_Desc.Usage == USAGE_DYNAMIC)
+ {
+#ifdef _DEBUG
+ DbgVerifyDynamicAllocation(ContextId);
+#endif
+ return m_DynamicData[ContextId].GPUAddress;
+ }
+ else
+ {
+ return GetVkResource()->GetGPUVirtualAddress();
+ }
+ }
+
+ Vk_CPU_DESCRIPTOR_HANDLE GetCBVHandle(){return m_CBVDescriptorAllocation.GetCpuHandle();}
+ */
+private:
+ virtual void CreateViewInternal( const struct BufferViewDesc &ViewDesc, IBufferView **ppView, bool bIsDefaultView )override;
+/*
+ void CreateUAV( struct BufferViewDesc &UAVDesc, Vk_CPU_DESCRIPTOR_HANDLE UAVDescriptor );
+ void CreateSRV( struct BufferViewDesc &SRVDesc, Vk_CPU_DESCRIPTOR_HANDLE SRVDescriptor );
+ void CreateCBV( Vk_CPU_DESCRIPTOR_HANDLE CBVDescriptor );
+ DescriptorHeapAllocation m_CBVDescriptorAllocation;
+
+#ifdef _DEBUG
+ std::vector< std::pair<MAP_TYPE, Uint32>, STDAllocatorRawMem<std::pair<MAP_TYPE, Uint32>> > m_DbgMapType;
+#endif
+
+ friend class DeviceContextVkImpl;
+ // Array of dynamic allocations for every device context
+ std::vector<DynamicAllocation, STDAllocatorRawMem<DynamicAllocation> > m_DynamicData;*/
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/CommandContext.h b/Graphics/GraphicsEngineVulkan/include/CommandContext.h
new file mode 100644
index 00000000..a33b4213
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/CommandContext.h
@@ -0,0 +1,372 @@
+/* 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 "D3D12ResourceBase.h"
+#include "TextureViewVk.h"
+#include "TextureVk.h"
+#include "BufferVk.h"
+#include "DescriptorHeap.h"
+
+namespace Diligent
+{
+//
+//
+//struct DWParam
+//{
+// DWParam( FLOAT f ) : Float(f) {}
+// DWParam( UINT u ) : Uint(u) {}
+// DWParam( INT i ) : Int(i) {}
+//
+// void operator= ( FLOAT f ) { Float = f; }
+// void operator= ( UINT u ) { Uint = u; }
+// void operator= ( INT i ) { Int = i; }
+//
+// union
+// {
+// FLOAT Float;
+// UINT Uint;
+// INT Int;
+// };
+//};
+
+
+class CommandContext
+{
+public:
+
+ CommandContext( IMemoryAllocator &MemAllocator,
+ class CommandListManager& CmdListManager,
+ GPUDescriptorHeap GPUDescriptorHeaps[],
+ const Uint32 DynamicDescriptorAllocationChunkSize[]);
+
+ ~CommandContext(void);
+/*
+ // Submit the command buffer and reset it. This is encouraged to keep the GPU busy and reduce latency.
+ // Taking too long to build command lists and submit them can idle the GPU.
+ ID3D12GraphicsCommandList* Close(ID3D12CommandAllocator **ppAllocator);
+ void Reset( CommandListManager& CmdListManager );
+
+ class GraphicsContext& AsGraphicsContext();
+ class ComputeContext& AsComputeContext();
+
+ void ClearUAVFloat( ITextureViewD3D12 *pTexView, const float* Color );
+ void ClearUAVUint( ITextureViewD3D12 *pTexView, const UINT *Color );
+
+ void CopyResource(ID3D12Resource *pDstRes, ID3D12Resource *pSrcRes)
+ {
+ m_pCommandList->CopyResource(pDstRes, pSrcRes);
+ }
+
+ void TransitionResource(ITextureD3D12 *pTexture, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false);
+ void TransitionResource(IBufferD3D12 *pBuffer, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false);
+ //void BeginResourceTransition(GpuResource& Resource, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false);
+ void FlushResourceBarriers();
+
+ struct ShaderDescriptorHeaps
+ {
+ ID3D12DescriptorHeap* pSrvCbvUavHeap;
+ ID3D12DescriptorHeap* pSamplerHeap;
+ ShaderDescriptorHeaps(ID3D12DescriptorHeap* _pSrvCbvUavHeap = nullptr, ID3D12DescriptorHeap* _pSamplerHeap = nullptr) :
+ pSrvCbvUavHeap(_pSrvCbvUavHeap),
+ pSamplerHeap(_pSamplerHeap)
+ {}
+ bool operator == (const ShaderDescriptorHeaps& rhs)const
+ {
+ return pSrvCbvUavHeap == rhs.pSrvCbvUavHeap && pSamplerHeap == rhs.pSamplerHeap;
+ }
+ operator bool()const
+ {
+ return pSrvCbvUavHeap != nullptr || pSamplerHeap != nullptr;
+ }
+ };
+ void SetDescriptorHeaps( ShaderDescriptorHeaps& Heaps );
+
+ void ExecuteIndirect(ID3D12CommandSignature *pCmdSignature, ID3D12Resource *pBuff, Uint64 ArgsOffset)
+ {
+ FlushResourceBarriers();
+ m_pCommandList->ExecuteIndirect(pCmdSignature, 1, pBuff, ArgsOffset, nullptr, 0);
+ }
+
+ void SetID(const Char* ID) { m_ID = ID; }
+ ID3D12GraphicsCommandList *GetCommandList(){return m_pCommandList;}
+
+ void DiscardDynamicDescriptors(Uint64 FenceValue);
+ DescriptorHeapAllocation AllocateDynamicGPUVisibleDescriptor( D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1 );
+
+ void InsertUAVBarrier(D3D12ResourceBase& Resource, IDeviceObject &Object, bool FlushImmediate = false);
+
+ void SetPipelineState( ID3D12PipelineState* pPSO )
+ {
+ if (pPSO != m_pCurPipelineState)
+ {
+ m_pCommandList->SetPipelineState(m_pCurPipelineState = pPSO);
+ }
+ }
+
+protected:
+ void TransitionResource(D3D12ResourceBase& Resource, IDeviceObject &Object, D3D12_RESOURCE_STATES NewState, bool FlushImmediate);
+ void InsertAliasBarrier(D3D12ResourceBase& Before, D3D12ResourceBase& After, IDeviceObject &BeforeObj, IDeviceObject &AfterObj, bool FlushImmediate = false);
+
+ CComPtr<ID3D12GraphicsCommandList> m_pCommandList;
+ CComPtr<ID3D12CommandAllocator> m_pCurrentAllocator;
+
+ ID3D12PipelineState* m_pCurPipelineState = nullptr;
+ ID3D12RootSignature* m_pCurGraphicsRootSignature = nullptr;
+ ID3D12RootSignature* m_pCurComputeRootSignature = nullptr;
+
+ static constexpr int MaxPendingBarriers = 16;
+ std::vector<D3D12_RESOURCE_BARRIER, STDAllocatorRawMem<D3D12_RESOURCE_BARRIER> > m_PendingResourceBarriers;
+ // We must make sure that all referenced objects are alive until barriers are executed
+ // Keeping reference to ID3D12Resource is not sufficient!
+ // TextureD3D12Impl::~TextureD3D12Impl() and BufferD3D12Impl::~BufferD3D12Impl()
+ // are responsible for putting the D3D12 resource in the release queue
+ std::vector< RefCntAutoPtr<IDeviceObject>, STDAllocatorRawMem<RefCntAutoPtr<IDeviceObject>> > m_PendingBarrierObjects;
+
+ ShaderDescriptorHeaps m_BoundDescriptorHeaps;
+
+ // Every context must use its own allocator that maintains individual list of retired descriptor heaps to
+ // avoid interference with other command contexts
+ // The heaps can only be discarded after the command list is submitted for execution
+ DynamicSuballocationsManager m_DynamicGPUDescriptorAllocator[2];
+
+ String m_ID;
+
+ D3D12_PRIMITIVE_TOPOLOGY m_PrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ */
+};
+
+
+class GraphicsContext : public CommandContext
+{
+public:
+ /*
+ void ClearRenderTarget( ITextureViewD3D12 *pRTV, const float *Color );
+ void ClearDepthStencil( ITextureViewD3D12 *pDSV, D3D12_CLEAR_FLAGS ClearFlags, float Depth, UINT8 Stencil );
+
+ void SetRootSignature( ID3D12RootSignature *pRootSig )
+ {
+ if (pRootSig != m_pCurGraphicsRootSignature)
+ {
+ m_pCommandList->SetGraphicsRootSignature(m_pCurGraphicsRootSignature = pRootSig);
+ }
+ }
+
+ void SetRenderTargets( UINT NumRTVs, ITextureViewD3D12** ppRTVs, ITextureViewD3D12* pDSV );
+
+ void SetViewports( UINT NumVPs, const D3D12_VIEWPORT* pVPs )
+ {
+ m_pCommandList->RSSetViewports(NumVPs, pVPs);
+ }
+
+ void SetScissorRects( UINT NumRects, const D3D12_RECT* pRects )
+ {
+ m_pCommandList->RSSetScissorRects(NumRects, pRects);
+ }
+
+ void SetStencilRef( UINT StencilRef )
+ {
+ m_pCommandList->OMSetStencilRef( StencilRef );
+ }
+
+ void SetBlendFactor( const float* BlendFactor )
+ {
+ m_pCommandList->OMSetBlendFactor( BlendFactor );
+ }
+
+ void SetPrimitiveTopology( D3D12_PRIMITIVE_TOPOLOGY Topology )
+ {
+ if(m_PrimitiveTopology != Topology)
+ {
+ m_PrimitiveTopology = Topology;
+ m_pCommandList->IASetPrimitiveTopology(Topology);
+ }
+ }
+
+ void SetConstants( UINT RootIndex, UINT NumConstants, const void* pConstants )
+ {
+ m_pCommandList->SetGraphicsRoot32BitConstants( RootIndex, NumConstants, pConstants, 0 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X )
+ {
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, X.Uint, 0 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X, DWParam Y )
+ {
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, X.Uint, 0 );
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, Y.Uint, 1 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X, DWParam Y, DWParam Z )
+ {
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, X.Uint, 0 );
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, Y.Uint, 1 );
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, Z.Uint, 2 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X, DWParam Y, DWParam Z, DWParam W )
+ {
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, X.Uint, 0 );
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, Y.Uint, 1 );
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, Z.Uint, 2 );
+ m_pCommandList->SetGraphicsRoot32BitConstant( RootIndex, W.Uint, 3 );
+ }
+
+ void SetConstantBuffer( UINT RootIndex, D3D12_GPU_VIRTUAL_ADDRESS CBV )
+ {
+ m_pCommandList->SetGraphicsRootConstantBufferView(RootIndex, CBV);
+ }
+
+ void SetDescriptorTable( UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle )
+ {
+ m_pCommandList->SetGraphicsRootDescriptorTable( RootIndex, FirstHandle );
+ }
+
+ void SetIndexBuffer( const D3D12_INDEX_BUFFER_VIEW& IBView )
+ {
+ m_pCommandList->IASetIndexBuffer(&IBView);
+ }
+
+ void SetVertexBuffers( UINT StartSlot, UINT Count, const D3D12_VERTEX_BUFFER_VIEW VBViews[] )
+ {
+ m_pCommandList->IASetVertexBuffers(StartSlot, Count, VBViews);
+ }
+
+ void Draw(UINT VertexCountPerInstance, UINT InstanceCount,
+ UINT StartVertexLocation, UINT StartInstanceLocation)
+ {
+ FlushResourceBarriers();
+ m_pCommandList->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation);
+ }
+
+ void DrawIndexed(UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation,
+ INT BaseVertexLocation, UINT StartInstanceLocation)
+ {
+ FlushResourceBarriers();
+ m_pCommandList->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation);
+ }
+ */
+};
+
+class ComputeContext : public CommandContext
+{
+/*
+public:
+
+ void SetRootSignature( ID3D12RootSignature *pRootSig )
+ {
+ if (pRootSig != m_pCurComputeRootSignature)
+ {
+ m_pCommandList->SetComputeRootSignature(m_pCurComputeRootSignature = pRootSig);
+ }
+ }
+
+ void SetConstants( UINT RootIndex, UINT NumConstants, const void* pConstants )
+ {
+ m_pCommandList->SetComputeRoot32BitConstants( RootIndex, NumConstants, pConstants, 0 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X )
+ {
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, X.Uint, 0 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X, DWParam Y )
+ {
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, X.Uint, 0 );
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, Y.Uint, 1 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X, DWParam Y, DWParam Z )
+ {
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, X.Uint, 0 );
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, Y.Uint, 1 );
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, Z.Uint, 2 );
+ }
+
+ void SetConstants( UINT RootIndex, DWParam X, DWParam Y, DWParam Z, DWParam W )
+ {
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, X.Uint, 0 );
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, Y.Uint, 1 );
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, Z.Uint, 2 );
+ m_pCommandList->SetComputeRoot32BitConstant( RootIndex, W.Uint, 3 );
+ }
+
+
+ void SetConstantBuffer( UINT RootIndex, D3D12_GPU_VIRTUAL_ADDRESS CBV )
+ {
+ m_pCommandList->SetComputeRootConstantBufferView(RootIndex, CBV);
+ }
+
+ void SetDescriptorTable( UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle )
+ {
+ m_pCommandList->SetComputeRootDescriptorTable( RootIndex, FirstHandle );
+ }
+
+ void Dispatch( size_t GroupCountX = 1, size_t GroupCountY = 1, size_t GroupCountZ = 1 )
+ {
+ FlushResourceBarriers();
+ m_pCommandList->Dispatch((UINT)GroupCountX, (UINT)GroupCountY, (UINT)GroupCountZ);
+ }
+ */
+};
+
+/*
+inline GraphicsContext& CommandContext::AsGraphicsContext()
+{
+ return static_cast<GraphicsContext&>(*this);
+}
+
+inline ComputeContext& CommandContext::AsComputeContext()
+{
+ return static_cast<ComputeContext&>(*this);
+}
+
+inline void CommandContext::SetDescriptorHeaps( ShaderDescriptorHeaps& Heaps )
+{
+#ifdef _DEBUG
+ VERIFY(Heaps.pSrvCbvUavHeap != nullptr || Heaps.pSamplerHeap != nullptr, "At least one heap is expected to be set");
+ VERIFY(Heaps.pSrvCbvUavHeap == nullptr || Heaps.pSrvCbvUavHeap->GetDesc().Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, "Invalid heap type provided in pSrvCbvUavHeap");
+ VERIFY(Heaps.pSamplerHeap == nullptr || Heaps.pSamplerHeap->GetDesc().Type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, "Invalid heap type provided in pSamplerHeap");
+#endif
+
+ if (!(Heaps == m_BoundDescriptorHeaps))
+ {
+ m_BoundDescriptorHeaps = Heaps;
+
+ ID3D12DescriptorHeap **ppHeaps = reinterpret_cast<ID3D12DescriptorHeap**>(&Heaps);
+ UINT NumHeaps = (ppHeaps[0] != nullptr ? 1 : 0) + (ppHeaps[1] != nullptr ? 1 : 0);
+ if(ppHeaps[0] == nullptr)
+ ++ppHeaps;
+
+ m_pCommandList->SetDescriptorHeaps(NumHeaps, ppHeaps);
+ }
+}
+*/
+} \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/include/CommandListManager.h b/Graphics/GraphicsEngineVulkan/include/CommandListManager.h
new file mode 100644
index 00000000..461e7116
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/CommandListManager.h
@@ -0,0 +1,67 @@
+/* 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/CommandListVkImpl.h b/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h
new file mode 100644
index 00000000..d42700d8
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/CommandListVkImpl.h
@@ -0,0 +1,61 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::CommandListD3D12Impl class
+
+#include "CommandListBase.h"
+
+namespace Diligent
+{
+
+/// Implementation of the Diligent::ICommandList interface
+class CommandListD3D12Impl : public CommandListBase<ICommandList>
+{
+public:
+ typedef CommandListBase<ICommandList> TCommandListBase;
+ CommandListD3D12Impl(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, class CommandContext* pCmdContext) :
+ TCommandListBase(pRefCounters, pDevice),
+ m_pCmdContext(pCmdContext)
+ {
+ }
+
+ ~CommandListD3D12Impl()
+ {
+ VERIFY(m_pCmdContext == nullptr, "Destroying command list that was never executed");
+ }
+
+ CommandContext* Close()
+ {
+ CommandContext* pCmdContext = m_pCmdContext;
+ m_pCmdContext = nullptr;
+ return pCmdContext;
+ }
+
+private:
+ CommandContext* m_pCmdContext = nullptr;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h b/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h
new file mode 100644
index 00000000..7bc4f7f5
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/CommandQueueVkImpl.h
@@ -0,0 +1,77 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::CommandQueueVkImpl class
+
+#include "CommandQueueVk.h"
+#include "ObjectBase.h"
+
+namespace Diligent
+{
+
+/// Implementation of the Diligent::ICommandQueueVk interface
+class CommandQueueVkImpl : public ObjectBase<ICommandQueueVk>
+{
+public:
+ typedef ObjectBase<ICommandQueueVk> TBase;
+
+ CommandQueueVkImpl(IReferenceCounters *pRefCounters, void *pVkNativeCmdQueue, void *pVkFence);
+ ~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; }
+
+ // Executes a given command list
+ virtual UINT64 ExecuteCommandList(IVkGraphicsCommandList* commandList)override final;
+
+ virtual IVkCommandQueue* GetVkCommandQueue()override final { return m_pVkCmdQueue; }
+
+ virtual void IdleGPU()override final;
+
+ virtual Uint64 GetCompletedFenceValue()override final;
+
+private:
+ // A value that will be signaled by the command queue next
+ Atomics::AtomicInt64 m_NextFenceValue;
+
+ // Last fence value completed by the GPU
+ volatile Uint64 m_LastCompletedFenceValue = 0;
+
+ CComPtr<IVkCommandQueue> m_pVkCmdQueue;
+
+ // The fence is signaled right after the command list has been
+ // submitted to the command queue for execution.
+ // All command lists 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 = {};
+ */
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h b/Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h
new file mode 100644
index 00000000..b48fa909
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h
@@ -0,0 +1,532 @@
+/* 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.
+ */
+
+// Descriptor heap management utilities.
+// See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-descriptor-heaps/ for details
+
+#pragma once
+
+#include <mutex>
+#include <vector>
+#include <queue>
+#include <string>
+#include <set>
+//#include "ObjectBase.h"
+//#include "VariableSizeGPUAllocationsManager.h"
+
+namespace Diligent
+{
+
+class DescriptorHeapAllocation;
+class DescriptorHeapAllocationManager;
+class RenderDeviceD3D12Impl;
+//
+class IDescriptorAllocator
+{
+public:
+ // Allocate Count descriptors
+ virtual DescriptorHeapAllocation Allocate( uint32_t Count ) = 0;
+ virtual void Free(DescriptorHeapAllocation&& Allocation) = 0;
+ virtual Uint32 GetDescriptorSize()const = 0;
+};
+
+
+// The class represents descriptor heap allocation (continuous descriptor range in a descriptor heap)
+//
+// m_FirstCpuHandle
+// |
+// | ~ ~ ~ ~ ~ X X X X X X X ~ ~ ~ ~ ~ ~ | D3D12 Descriptor Heap
+// |
+// m_FirstGpuHandle
+//
+class DescriptorHeapAllocation
+{
+public:
+#if 0
+ // Creates null allocation
+ DescriptorHeapAllocation() :
+ m_NumHandles(1), // One null descriptor handle
+ m_pDescriptorHeap(nullptr),
+ m_DescriptorSize(0)
+ {
+ m_FirstCpuHandle.ptr = 0;
+ m_FirstGpuHandle.ptr = 0;
+ }
+
+ // Initializes non-null allocation
+ DescriptorHeapAllocation( IDescriptorAllocator *pAllocator,
+ ID3D12DescriptorHeap *pHeap,
+ D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle,
+ D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle,
+ Uint32 NHandles,
+ Uint16 AllocationManagerId = static_cast<Uint16>(-1) ) :
+ m_FirstCpuHandle(CpuHandle),
+ m_FirstGpuHandle(GpuHandle),
+ m_pAllocator(pAllocator),
+ m_NumHandles(NHandles),
+ m_pDescriptorHeap(pHeap),
+ m_AllocationManagerId(AllocationManagerId)
+ {
+ VERIFY_EXPR(m_pAllocator != nullptr && m_pDescriptorHeap != nullptr);
+ auto DescriptorSize = m_pAllocator->GetDescriptorSize();
+ VERIFY(DescriptorSize < std::numeric_limits<Uint16>::max(), "DescriptorSize exceeds allowed limit");
+ m_DescriptorSize = static_cast<Uint16>( DescriptorSize );
+ }
+
+ // Move constructor (copy is not allowed)
+ DescriptorHeapAllocation(DescriptorHeapAllocation &&Allocation) :
+ m_FirstCpuHandle(Allocation.m_FirstCpuHandle),
+ m_FirstGpuHandle(Allocation.m_FirstGpuHandle),
+ m_NumHandles(Allocation.m_NumHandles),
+ m_pAllocator(std::move(Allocation.m_pAllocator)),
+ m_AllocationManagerId(std::move(Allocation.m_AllocationManagerId)),
+ m_pDescriptorHeap(std::move(Allocation.m_pDescriptorHeap) ),
+ m_DescriptorSize(std::move(Allocation.m_DescriptorSize) )
+ {
+ Allocation.m_pAllocator = nullptr;
+ Allocation.m_FirstCpuHandle.ptr = 0;
+ Allocation.m_FirstGpuHandle.ptr = 0;
+ Allocation.m_NumHandles = 0;
+ Allocation.m_pDescriptorHeap = nullptr;
+ Allocation.m_DescriptorSize = 0;
+ Allocation.m_AllocationManagerId = static_cast<Uint16>(-1);
+ }
+
+ // Move assignment (assignment is not allowed)
+ DescriptorHeapAllocation& operator = (DescriptorHeapAllocation &&Allocation)
+ {
+ m_FirstCpuHandle = Allocation.m_FirstCpuHandle;
+ m_FirstGpuHandle = Allocation.m_FirstGpuHandle;
+ m_NumHandles = Allocation.m_NumHandles;
+ m_pAllocator = std::move(Allocation.m_pAllocator);
+ m_AllocationManagerId = std::move(Allocation.m_AllocationManagerId);
+ m_pDescriptorHeap = std::move(Allocation.m_pDescriptorHeap);
+ m_DescriptorSize = std::move(Allocation.m_DescriptorSize);
+
+ Allocation.m_FirstCpuHandle.ptr = 0;
+ Allocation.m_FirstGpuHandle.ptr = 0;
+ Allocation.m_NumHandles = 0;
+ Allocation.m_pAllocator = nullptr;
+ Allocation.m_pDescriptorHeap = nullptr;
+ Allocation.m_DescriptorSize = 0;
+ Allocation.m_AllocationManagerId = static_cast<Uint16>(-1);
+
+ return *this;
+ }
+
+ // Destructor automatically releases this allocation through the allocator
+ ~DescriptorHeapAllocation()
+ {
+ if(!IsNull() && m_pAllocator)
+ m_pAllocator->Free(std::move(*this));
+ // Allocation must have been disposed by the allocator
+ VERIFY(IsNull(), "Non-null descriptor is being destroyed");
+ }
+
+ // Returns CPU descriptor handle at the specified offset
+ D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Uint32 Offset = 0) const
+ {
+ VERIFY_EXPR(Offset >= 0 && Offset < m_NumHandles);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE CPUHandle = m_FirstCpuHandle;
+ if (Offset != 0)
+ {
+ CPUHandle.ptr += m_DescriptorSize * Offset;
+ }
+ return CPUHandle;
+ }
+
+ // Returns GPU descriptor handle at the specified offset
+ D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Uint32 Offset = 0) const
+ {
+ VERIFY_EXPR(Offset >= 0 && Offset < m_NumHandles);
+ D3D12_GPU_DESCRIPTOR_HANDLE GPUHandle = m_FirstGpuHandle;
+ if (Offset != 0)
+ {
+ GPUHandle.ptr += m_DescriptorSize * Offset;
+ }
+ return GPUHandle;
+ }
+
+ // Returns pointer to D3D12 descriptor heap that contains this allocation
+ ID3D12DescriptorHeap *GetDescriptorHeap(){return m_pDescriptorHeap;}
+
+ size_t GetNumHandles()const{return m_NumHandles;}
+
+ bool IsNull() const { return m_FirstCpuHandle.ptr == 0; }
+ bool IsShaderVisible() const { return m_FirstGpuHandle.ptr != 0; }
+ size_t GetAllocationManagerId(){return m_AllocationManagerId;}
+ UINT GetDescriptorSize()const{return m_DescriptorSize;}
+
+private:
+ // No copies, only moves are allowed
+ DescriptorHeapAllocation(const DescriptorHeapAllocation&) = delete;
+ DescriptorHeapAllocation& operator= (const DescriptorHeapAllocation&) = delete;
+
+ // First CPU descriptor handle in this allocation
+ D3D12_CPU_DESCRIPTOR_HANDLE m_FirstCpuHandle = {0};
+
+ // First GPU descriptor handle in this allocation
+ D3D12_GPU_DESCRIPTOR_HANDLE m_FirstGpuHandle = {0};
+
+ // Keep strong reference to the parent heap to make sure it is alive while allocation is alive - TOO EXPENSIVE
+ //RefCntAutoPtr<IDescriptorAllocator> m_pAllocator;
+
+ // Pointer to the descriptor heap allocator that created this allocation
+ IDescriptorAllocator* m_pAllocator = nullptr;
+
+ // Pointer to the D3D12 descriptor heap that contains descriptors in this allocation
+ ID3D12DescriptorHeap* m_pDescriptorHeap = nullptr;
+
+ // Number of descriptors in the allocation
+ Uint32 m_NumHandles = 0;
+
+ // Allocation manager ID. One allocator may support several
+ // allocation managers. This field is required to identify
+ // the manager within the allocator that was used to create
+ // this allocation
+ Uint16 m_AllocationManagerId = static_cast<Uint16>(-1);
+
+ // Descriptor size
+ Uint16 m_DescriptorSize = 0;
+#endif
+};
+
+
+// The class performs suballocations within one D3D12 descriptor heap.
+// It uses VariableSizeGPUAllocationsManager to manage free space in the heap
+//
+// | X X X X O O O X X O O X O O O O | D3D12 descriptor heap
+//
+// X - used descriptor
+// O - available descriptor
+//
+class DescriptorHeapAllocationManager
+{
+public:
+#if 0
+ // Creates a new D3D12 descriptor heap
+ DescriptorHeapAllocationManager(IMemoryAllocator &Allocator,
+ RenderDeviceD3D12Impl *pDeviceD3D12Impl,
+ IDescriptorAllocator *pParentAllocator,
+ size_t ThisManagerId,
+ const D3D12_DESCRIPTOR_HEAP_DESC &HeapDesc);
+
+ // Uses subrange of descriptors in the existing D3D12 descriptor heap
+ // that starts at offset FirstDescriptor and uses NumDescriptors descriptors
+ DescriptorHeapAllocationManager(IMemoryAllocator &Allocator,
+ RenderDeviceD3D12Impl *pDeviceD3D12Impl,
+ IDescriptorAllocator *pParentAllocator,
+ size_t ThisManagerId,
+ ID3D12DescriptorHeap *pd3d12DescriptorHeap,
+ Uint32 FirstDescriptor,
+ Uint32 NumDescriptors);
+
+
+ // = default causes compiler error when instantiating std::vector::emplace_back() in Visual Studio 2015 (Version 14.0.23107.0 D14REL)
+ DescriptorHeapAllocationManager(DescriptorHeapAllocationManager&& rhs) :
+ m_FreeBlockManager(std::move(rhs.m_FreeBlockManager)),
+ m_HeapDesc(rhs.m_HeapDesc),
+ m_pd3d12DescriptorHeap(std::move(rhs.m_pd3d12DescriptorHeap)),
+ m_FirstCPUHandle(rhs.m_FirstCPUHandle),
+ m_FirstGPUHandle(rhs.m_FirstGPUHandle),
+ m_DescriptorSize(rhs.m_DescriptorSize),
+ m_NumDescriptorsInAllocation(rhs.m_NumDescriptorsInAllocation),
+ // Mutex is not movable
+ //m_AllocationMutex(std::move(rhs.m_AllocationMutex))
+ m_pDeviceD3D12Impl(rhs.m_pDeviceD3D12Impl),
+ m_pParentAllocator(rhs.m_pParentAllocator),
+ m_ThisManagerId(rhs.m_ThisManagerId)
+ {
+ rhs.m_FirstCPUHandle.ptr = 0;
+ rhs.m_FirstGPUHandle.ptr = 0;
+ rhs.m_DescriptorSize = 0;
+ rhs.m_NumDescriptorsInAllocation = 0;
+ rhs.m_HeapDesc.NumDescriptors = 0;
+ rhs.m_pDeviceD3D12Impl = nullptr;
+ rhs.m_pParentAllocator = nullptr;
+ rhs.m_ThisManagerId = static_cast<size_t>(-1);
+ }
+
+ // No copies or move-assignments
+ DescriptorHeapAllocationManager& operator = (DescriptorHeapAllocationManager&& rhs) = delete;
+ DescriptorHeapAllocationManager(const DescriptorHeapAllocationManager&) = delete;
+ DescriptorHeapAllocationManager& operator = (const DescriptorHeapAllocationManager&) = delete;
+
+ ~DescriptorHeapAllocationManager();
+
+ // Allocates Count descriptors
+ DescriptorHeapAllocation Allocate( uint32_t Count );
+
+ // Releases descriptor heap allocation.
+ // Note that the allocation is not released immediately, but
+ // added to the release queue in the allocations manager
+ void Free(DescriptorHeapAllocation&& Allocation);
+
+ // Releases all stale allocation used by completed command lists
+ // The method takes the last known completed fence value N
+ // and releases all allocations whose associated fence value n <= N
+ void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue);
+
+ size_t GetNumAvailableDescriptors()const{return m_FreeBlockManager.GetFreeSize();}
+ size_t GetNumStaleDescriptors()const { return m_FreeBlockManager.GetStaleAllocationsSize(); }
+ Uint32 GetMaxDescriptors()const { return m_NumDescriptorsInAllocation; }
+
+private:
+ // Allocations manager used to handle descriptor allocations within the heap
+ VariableSizeGPUAllocationsManager m_FreeBlockManager;
+
+ // Heap description
+ D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc;
+
+ // Strong reference to D3D12 descriptor heap object
+ CComPtr<ID3D12DescriptorHeap> m_pd3d12DescriptorHeap;
+
+ // First CPU descriptor handle in the available descriptor range
+ D3D12_CPU_DESCRIPTOR_HANDLE m_FirstCPUHandle = {0};
+
+ // First GPU descriptor handle in the available descriptor range
+ D3D12_GPU_DESCRIPTOR_HANDLE m_FirstGPUHandle = {0};
+
+ UINT m_DescriptorSize = 0;
+
+ // Number of descriptors in the allocation.
+ // If this manager was initialized as a subrange in the existing heap,
+ // this value may be different from m_HeapDesc.NumDescriptors
+ Uint32 m_NumDescriptorsInAllocation = 0;
+
+ std::mutex m_AllocationMutex;
+ RenderDeviceD3D12Impl *m_pDeviceD3D12Impl = nullptr;
+ IDescriptorAllocator *m_pParentAllocator = nullptr;
+
+ // External ID assigned to this descriptor allocations manager
+ size_t m_ThisManagerId = static_cast<size_t>(-1);
+#endif
+};
+
+// CPU descriptor heap is intended to provide storage for resource view descriptor handles
+// It contains a pool of DescriptorHeapAllocationManager object instances, where every instance manages
+// its own CPU-only D3D12 descriptor heap:
+//
+// m_HeapPool[0] m_HeapPool[1] m_HeapPool[2]
+// | X X X X X X X X |, | X X X O O X X O |, | X O O O O O O O |
+//
+// X - used descriptor m_AvailableHeaps = {1,2}
+// O - available descriptor
+//
+// Allocation routine goes through the list of managers that have available descriptors and tries to process
+// the request using every manager. If there are no available managers or no manager was able to handle the request,
+// the function creates a new descriptor heap manager and lets it handle the request
+//
+// Render device contains four CPUDescriptorHeap object instances (one for each D3D12 heap type). The heaps are accessed
+// when a texture or a buffer view is created.
+//
+class CPUDescriptorHeap : public IDescriptorAllocator
+{
+#if 0
+public:
+ // Initializes the heap
+ CPUDescriptorHeap(IMemoryAllocator &Allocator,
+ RenderDeviceD3D12Impl *pDeviceD3D12Impl,
+ Uint32 NumDescriptorsInHeap,
+ D3D12_DESCRIPTOR_HEAP_TYPE Type,
+ D3D12_DESCRIPTOR_HEAP_FLAGS Flags);
+
+ CPUDescriptorHeap(const CPUDescriptorHeap&) = delete;
+ CPUDescriptorHeap(CPUDescriptorHeap&&) = delete;
+ CPUDescriptorHeap& operator = (const CPUDescriptorHeap&) = delete;
+ CPUDescriptorHeap& operator = (CPUDescriptorHeap&&) = delete;
+
+ ~CPUDescriptorHeap();
+
+ virtual DescriptorHeapAllocation Allocate( uint32_t Count )override;
+ virtual void Free(DescriptorHeapAllocation&& Allocation)override;
+ virtual Uint32 GetDescriptorSize()const override{return m_DescriptorSize;}
+
+ // Releases all stale allocation used by completed command lists
+ // The method takes the last known completed fence value N
+ // and releases all allocations whose associated fence value n <= N
+ void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue);
+
+protected:
+
+ // Pool of descriptor heap managers
+ std::vector<DescriptorHeapAllocationManager, STDAllocatorRawMem<DescriptorHeapAllocationManager> > m_HeapPool;
+ // Indices of available descriptor heap managers
+ std::set<size_t, std::less<size_t>, STDAllocatorRawMem<size_t> > m_AvailableHeaps;
+ IMemoryAllocator &m_MemAllocator;
+
+ std::mutex m_AllocationMutex;
+
+ D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc;
+ RenderDeviceD3D12Impl *m_pDeviceD3D12Impl;
+ UINT m_DescriptorSize;
+
+ // Maximum heap size during the application lifetime - for statistic purposes
+ Uint32 m_MaxHeapSize = 0;
+ Uint32 m_MaxStaleSize = 0;
+ Uint32 m_CurrentSize = 0; // This size does not count stale allocation
+#endif
+};
+
+// GPU descriptor heap provides storage for shader-visible descriptors
+// The heap contains single D3D12 descriptor heap that is broken into two parts.
+// The first part stores static and mutable resource descriptor handles.
+// The second part is intended to provide temporary storage for dynamic resources
+// Space for dynamic resources is allocated in chunks, and then descriptors are suballocated within every
+// chunk. DynamicSuballocationsManager facilitates this process
+//
+//
+// static and mutable handles || dynamic space
+// || chunk 0 chunk 1 chunk 2 unused
+// | X O O X X O X O O O O X X X X O || | X X X O | | X X O O | | O O O O | O O O O ||
+// | |
+// suballocation suballocation
+// within chunk 0 within chunk 1
+//
+// Render device contains two GPUDescriptorHeap instances (CBV_SRV_UAV and SAMPLER). The heaps
+// are used to allocate GPU-visible descriptors for shader resource binding objects. The heaps
+// are also used by the command contexts (through DynamicSuballocationsManager to allocated dynamic descriptors)
+//
+// _______________________________________________________________________________________________________________________________
+// | Render Device |
+// | |
+// | m_CPUDescriptorHeaps[CBV_SRV_UAV] | X X X X X X X X |, | X X X X X X X X |, | X O O X O O O O | |
+// | m_CPUDescriptorHeaps[SAMPLER] | X X X X O O O X |, | X O O X O O O O | |
+// | m_CPUDescriptorHeaps[RTV] | X X X O O O O O |, | O O O O O O O O | |
+// | m_CPUDescriptorHeaps[DSV] | X X X O X O X O | |
+// | ctx1 ctx2 |
+// | m_GPUDescriptorHeaps[CBV_SRV_UAV] | X O O X X O X O O O O X X X X O || | X X X O | | X X O O | | O O O O | O O O O || |
+// | m_GPUDescriptorHeaps[SAMPLER] | X X O O X O X X X O O X O O O O || | X X O O | | X O O O | | O O O O | O O O O || |
+// | |
+// |_______________________________________________________________________________________________________________________________|
+//
+// ________________________________________________ ________________________________________________
+// |Device Context 1 | |Device Context 2 |
+// | | | |
+// | m_DynamicGPUDescriptorAllocator[CBV_SRV_UAV] | | m_DynamicGPUDescriptorAllocator[CBV_SRV_UAV] |
+// | m_DynamicGPUDescriptorAllocator[SAMPLER] | | m_DynamicGPUDescriptorAllocator[SAMPLER] |
+// |________________________________________________| |________________________________________________|
+//
+class GPUDescriptorHeap : public IDescriptorAllocator
+{
+public:
+#if 0
+ GPUDescriptorHeap(IMemoryAllocator &Allocator,
+ RenderDeviceD3D12Impl *pDevice,
+ Uint32 NumDescriptorsInHeap,
+ Uint32 NumDynamicDescriptors,
+ D3D12_DESCRIPTOR_HEAP_TYPE Type,
+ D3D12_DESCRIPTOR_HEAP_FLAGS Flags);
+#endif
+ GPUDescriptorHeap(const GPUDescriptorHeap&) = delete;
+ GPUDescriptorHeap(GPUDescriptorHeap&&) = delete;
+ GPUDescriptorHeap& operator = (const GPUDescriptorHeap&) = delete;
+ GPUDescriptorHeap& operator = (GPUDescriptorHeap&&) = delete;
+
+ ~GPUDescriptorHeap();
+
+ virtual DescriptorHeapAllocation Allocate( uint32_t Count )override;
+ virtual void Free(DescriptorHeapAllocation&& Allocation)override;
+ virtual Uint32 GetDescriptorSize()const override{return 0/*m_DescriptorSize*/;}
+#if 0
+ DescriptorHeapAllocation AllocateDynamic( uint32_t Count );
+
+ // Releases all stale allocation used by completed command lists
+ // The method takes the last known completed fence value N
+ // and releases all allocations whose associated fence value n <= N
+ void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue);
+
+ const D3D12_DESCRIPTOR_HEAP_DESC &GetHeapDesc()const{return m_HeapDesc;}
+ Uint32 GetMaxStaticDescriptors()const { return m_HeapAllocationManager.GetMaxDescriptors(); }
+ Uint32 GetMaxDynamicDescriptors()const { return m_DynamicAllocationsManager.GetMaxDescriptors(); }
+
+protected:
+
+ D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc;
+ CComPtr<ID3D12DescriptorHeap> m_pd3d12DescriptorHeap;
+
+ UINT m_DescriptorSize = 0;
+
+ std::mutex m_AllocMutex, m_DynAllocMutex;
+ // Allocation manager for static/mutable part
+ DescriptorHeapAllocationManager m_HeapAllocationManager;
+
+ // Allocation manager for dynamic part
+ DescriptorHeapAllocationManager m_DynamicAllocationsManager;
+
+ RenderDeviceD3D12Impl *m_pDeviceD3D12;
+ Uint32 m_CurrentSize = 0;
+ // Maximum static/mutable part size during the application lifetime - for statistic purposes
+ Uint32 m_MaxHeapSize = 0;
+ Uint32 m_MaxStaleSize = 0;
+ Uint32 m_CurrentDynamicSize = 0;
+ // Maximum dynamic part size during the application lifetime - for statistic purposes
+ Uint32 m_MaxDynamicSize = 0;
+ Uint32 m_MaxDynamicStaleSize = 0;
+#endif
+};
+
+
+// The class facilitates allocation of dynamic descriptor handles. It requests a chunk of heap
+// from the master GPU descriptor heap and then performs linear suballocation within the chunk
+// At the end of the frame all allocations are disposed.
+
+// static and mutable handles || dynamic space
+// || chunk 0 chunk 2
+// | || | X X X O | | O O O O | || GPU Descriptor Heap
+// | |
+// m_Suballocations[0] m_Suballocations[1]
+//
+class DynamicSuballocationsManager : public IDescriptorAllocator
+{
+#if 0
+public:
+ DynamicSuballocationsManager(IMemoryAllocator &Allocator, GPUDescriptorHeap& ParentGPUHeap, Uint32 DynamicChunkSize);
+
+ DynamicSuballocationsManager(const DynamicSuballocationsManager&) = delete;
+ DynamicSuballocationsManager(DynamicSuballocationsManager&&) = delete;
+ DynamicSuballocationsManager& operator = (const DynamicSuballocationsManager&) = delete;
+ DynamicSuballocationsManager& operator = (DynamicSuballocationsManager&&) = delete;
+
+ void DiscardAllocations(Uint64 /*FenceValue*/);
+
+ virtual DescriptorHeapAllocation Allocate( Uint32 Count )override;
+ virtual void Free(DescriptorHeapAllocation&& Allocation)override;
+
+ virtual Uint32 GetDescriptorSize()const override{return m_ParentGPUHeap.GetDescriptorSize();}
+
+private:
+ // List of chunks allocated from the master GPU descriptor heap. All chunks are disposed at the end
+ // of the frame
+ std::vector<DescriptorHeapAllocation, STDAllocatorRawMem<DescriptorHeapAllocation> > m_Suballocations;
+
+ Uint32 m_CurrentSuballocationOffset = 0;
+ Uint32 m_DynamicChunkSize = 0;
+
+ // Parent GPU descriptor heap that is used to allocate chunks
+ GPUDescriptorHeap &m_ParentGPUHeap;
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
new file mode 100644
index 00000000..34b58149
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
@@ -0,0 +1,164 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::DeviceContextVkImpl class
+
+#include "DeviceContextVk.h"
+#include "DeviceContextBase.h"
+#include "GenerateMips.h"
+
+#ifdef _DEBUG
+# define VERIFY_CONTEXT_BINDINGS
+#endif
+
+namespace Diligent
+{
+
+/// Implementation of the Diligent::IDeviceContext interface
+class DeviceContextVkImpl : public DeviceContextBase<IDeviceContextVk>
+{
+public:
+ typedef DeviceContextBase<IDeviceContextVk> TDeviceContextBase;
+
+ DeviceContextVkImpl(IReferenceCounters *pRefCounters, class RenderDeviceVkImpl *pDevice, bool bIsDeferred, const EngineVkAttribs &Attribs, Uint32 ContextId);
+ ~DeviceContextVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override final;
+
+ virtual void SetPipelineState(IPipelineState *pPipelineState)override final;
+
+ virtual void TransitionShaderResources(IPipelineState *pPipelineState, IShaderResourceBinding *pShaderResourceBinding)override final;
+
+ virtual void CommitShaderResources(IShaderResourceBinding *pShaderResourceBinding, Uint32 Flags)override final;
+
+ virtual void SetStencilRef(Uint32 StencilRef)override final;
+
+ virtual void SetBlendFactors(const float* pBlendFactors = nullptr)override final;
+
+ virtual void SetVertexBuffers( Uint32 StartSlot, Uint32 NumBuffersSet, IBuffer **ppBuffers, Uint32 *pStrides, Uint32 *pOffsets, Uint32 Flags )override final;
+
+ virtual void InvalidateState()override final;
+
+ virtual void SetIndexBuffer( IBuffer *pIndexBuffer, Uint32 ByteOffset )override final;
+
+ virtual void SetViewports( Uint32 NumViewports, const Viewport *pViewports, Uint32 RTWidth, Uint32 RTHeight )override final;
+
+ virtual void SetScissorRects( Uint32 NumRects, const Rect *pRects, Uint32 RTWidth, Uint32 RTHeight )override final;
+
+ virtual void SetRenderTargets( Uint32 NumRenderTargets, ITextureView *ppRenderTargets[], ITextureView *pDepthStencil )override final;
+
+ virtual void Draw( DrawAttribs &DrawAttribs )override final;
+
+ virtual void DispatchCompute( const DispatchComputeAttribs &DispatchAttrs )override final;
+
+ virtual void ClearDepthStencil( ITextureView *pView, Uint32 ClearFlags, float fDepth, Uint8 Stencil)override final;
+
+ virtual void ClearRenderTarget( ITextureView *pView, const float *RGBA )override final;
+
+ virtual void Flush()override final;
+
+ virtual void FinishCommandList(class ICommandList **ppCommandList)override final;
+
+ virtual void ExecuteCommandList(class ICommandList *pCommandList)override final;
+
+#if 0
+ virtual void TransitionTextureState(ITexture *pTexture, Vk_RESOURCE_STATES State)override final;
+
+ virtual void TransitionBufferState(IBuffer *pBuffer, Vk_RESOURCE_STATES State)override final;
+
+ ///// Clears the state caches. This function is called once per frame
+ ///// (before present) to release all outstanding objects
+ ///// that are only kept alive by references in the cache
+ //void ClearShaderStateCache();
+
+ ///// Number of different shader types (Vertex, Pixel, Geometry, Domain, Hull, Compute)
+ //static constexpr int NumShaderTypes = 6;
+
+ void UpdateBufferRegion(class BufferVkImpl *pBuffVk, struct DynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes);
+ void UpdateBufferRegion(class BufferVkImpl *pBuffVk, const void *pData, Uint64 DstOffset, Uint64 NumBytes);
+ void CopyBufferRegion(class BufferVkImpl *pSrcBuffVk, class BufferVkImpl *pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes);
+ void CopyTextureRegion(class TextureVkImpl *pSrcTexture, Uint32 SrcSubResIndex, const Vk_BOX *pVkSrcBox,
+ class TextureVkImpl *pDstTexture, Uint32 DstSubResIndex, Uint32 DstX, Uint32 DstY, Uint32 DstZ);
+ void CopyTextureRegion(IBuffer *pSrcBuffer, Uint32 SrcStride, Uint32 SrcDepthStride, class TextureVkImpl *pTextureVk, Uint32 DstSubResIndex, const Box &DstBox);
+#endif
+ void GenerateMips(class TextureViewVkImpl *pTexView);
+
+#if 0
+ struct DynamicAllocation AllocateDynamicSpace(size_t NumBytes);
+
+ Uint32 GetContextId()const{return m_ContextId;}
+
+ size_t GetNumCommandsInCtx()const { return m_NumCommandsInCurCtx; }
+
+private:
+ void CommitVkIndexBuffer(VALUE_TYPE IndexType);
+ void CommitVkVertexBuffers(class GraphicsContext &GraphCtx);
+ void TransitionVkVertexBuffers(class GraphicsContext &GraphCtx);
+ void CommitRenderTargets();
+ void CommitViewports();
+ void CommitScissorRects(class GraphicsContext &GraphCtx, bool ScissorEnable);
+#endif
+ void Flush(bool RequestNewCmdCtx);
+#if 0
+ friend class SwapChainVkImpl;
+ inline class CommandContext* RequestCmdContext()
+ {
+ // Make sure that the number of commands in the context is at least one,
+ // so that the context cannot be disposed by Flush()
+ m_NumCommandsInCurCtx = m_NumCommandsInCurCtx != 0 ? m_NumCommandsInCurCtx : 1;
+ return m_pCurrCmdCtx;
+ }
+#endif
+ size_t m_NumCommandsInCurCtx = 0;
+#if 0
+ const Uint32 m_NumCommandsToFlush = 192;
+ CommandContext* m_pCurrCmdCtx = nullptr;
+
+ CComPtr<IVkResource> m_CommittedVkIndexBuffer;
+ VALUE_TYPE m_CommittedIBFormat = VT_UNDEFINED;
+ Uint32 m_CommittedVkIndexDataStartOffset = 0;
+
+ CComPtr<IVkCommandSignature> m_pDrawIndirectSignature;
+ CComPtr<IVkCommandSignature> m_pDrawIndexedIndirectSignature;
+ CComPtr<IVkCommandSignature> m_pDispatchIndirectSignature;
+
+ GenerateMipsHelper m_MipsGenerator;
+ class DynamicUploadHeap* m_pUploadHeap = nullptr;
+
+ /// Flag indicating if currently committed Vk vertex buffers are up to date
+ bool m_bCommittedVkVBsUpToDate = false;
+
+ /// Flag indicating if currently committed D3D11 index buffer is up to date
+ bool m_bCommittedVkIBUpToDate = false;
+
+ class ShaderResourceCacheVk *m_pCommittedResourceCache = nullptr;
+
+ FixedBlockMemoryAllocator m_CmdListAllocator;
+ const Uint32 m_ContextId;
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h b/Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h
new file mode 100644
index 00000000..b6b24ed1
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/DynamicUploadHeap.h
@@ -0,0 +1,142 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+#include "RingBuffer.h"
+
+namespace Diligent
+{
+
+// Constant blocks must be multiples of 16 constants @ 16 bytes each
+#define DEFAULT_ALIGN 256
+
+struct DynamicAllocation
+{
+#if 0
+ DynamicAllocation(ID3D12Resource *pBuff = nullptr, size_t ThisOffset = 0, size_t ThisSize = 0)
+ : pBuffer(pBuff), Offset(ThisOffset), Size(ThisSize) {}
+
+ //CComPtr<ID3D12Resource> pBuffer; // The D3D buffer associated with this memory.
+ ID3D12Resource *pBuffer = nullptr; // The D3D buffer associated with this memory.
+ size_t Offset = 0; // Offset from start of buffer resource
+ size_t Size = 0; // Reserved size of this allocation
+ void* CPUAddress = 0; // The CPU-writeable address
+ D3D12_GPU_VIRTUAL_ADDRESS GPUAddress = 0; // The GPU-visible address
+#ifdef _DEBUG
+ Uint64 FrameNum = static_cast<Uint64>(-1);
+#endif
+#endif
+};
+
+class GPURingBuffer : public RingBuffer
+{
+public:
+#if 0
+ GPURingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, ID3D12Device *pd3d12Device, bool AllowCPUAccess);
+
+ GPURingBuffer(GPURingBuffer&& rhs) :
+ RingBuffer(std::move(rhs)),
+ m_CpuVirtualAddress(rhs.m_CpuVirtualAddress),
+ m_GpuVirtualAddress(rhs.m_GpuVirtualAddress),
+ m_pBuffer(std::move(rhs.m_pBuffer))
+ {
+ rhs.m_CpuVirtualAddress = nullptr;
+ rhs.m_GpuVirtualAddress = 0;
+ rhs.m_pBuffer.Release();
+ }
+
+ GPURingBuffer& operator =(GPURingBuffer&& rhs)
+ {
+ Destroy();
+
+ static_cast<RingBuffer&>(*this) = std::move(rhs);
+ m_CpuVirtualAddress = rhs.m_CpuVirtualAddress;
+ m_GpuVirtualAddress = rhs.m_GpuVirtualAddress;
+ m_pBuffer = std::move(rhs.m_pBuffer);
+ rhs.m_CpuVirtualAddress = 0;
+ rhs.m_GpuVirtualAddress = 0;
+
+ return *this;
+ }
+
+ ~GPURingBuffer();
+
+ DynamicAllocation Allocate(size_t SizeInBytes)
+ {
+ auto Offset = RingBuffer::Allocate(SizeInBytes);
+ if (Offset != RingBuffer::InvalidOffset)
+ {
+ DynamicAllocation DynAlloc(m_pBuffer, Offset, SizeInBytes);
+ DynAlloc.GPUAddress = m_GpuVirtualAddress + Offset;
+ DynAlloc.CPUAddress = m_CpuVirtualAddress;
+ if(DynAlloc.CPUAddress)
+ DynAlloc.CPUAddress = reinterpret_cast<char*>(DynAlloc.CPUAddress) + Offset;
+ return DynAlloc;
+ }
+ else
+ {
+ return DynamicAllocation(nullptr, 0, 0);
+ }
+ }
+
+ GPURingBuffer(const GPURingBuffer&) = delete;
+ GPURingBuffer& operator =(GPURingBuffer&) = delete;
+
+private:
+ void Destroy();
+
+ void* m_CpuVirtualAddress;
+ D3D12_GPU_VIRTUAL_ADDRESS m_GpuVirtualAddress;
+ CComPtr<ID3D12Resource> m_pBuffer;
+#endif
+};
+
+class DynamicUploadHeap
+{
+public:
+#if 0
+ DynamicUploadHeap(IMemoryAllocator &Allocator, bool bIsCPUAccessible, class RenderDeviceD3D12Impl* pDevice, size_t InitialSize);
+
+ DynamicUploadHeap(const DynamicUploadHeap&)=delete;
+ DynamicUploadHeap(DynamicUploadHeap&&)=delete;
+ DynamicUploadHeap& operator=(const DynamicUploadHeap&)=delete;
+ DynamicUploadHeap& operator=(DynamicUploadHeap&&)=delete;
+
+ DynamicAllocation Allocate( size_t SizeInBytes, size_t Alignment = DEFAULT_ALIGN );
+
+ void FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue);
+
+private:
+ const bool m_bIsCPUAccessible;
+ // When a chunk of dynamic memory is requested, the heap first tries to allocate the memory in the largest GPU buffer.
+ // If allocation fails, a new ring buffer is created that provides enough space and requests memory from that buffer.
+ // Only the largest buffer is used for allocation and all other buffers are released when GPU is done with corresponding frames
+ std::vector<GPURingBuffer, STDAllocatorRawMem<GPURingBuffer> > m_RingBuffers;
+ IMemoryAllocator &m_Allocator;
+ RenderDeviceD3D12Impl* m_pDeviceD3D12 = nullptr;
+ //std::mutex m_Mutex;
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/GenerateMips.h b/Graphics/GraphicsEngineVulkan/include/GenerateMips.h
new file mode 100644
index 00000000..5f10e5d1
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/GenerateMips.h
@@ -0,0 +1,64 @@
+/* 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.
+ */
+
+
+// The source code in this file is derived from ColorBuffer.h and GraphicsCore.h developed by Minigraph
+// Original source files header:
+
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+// Developed by Minigraph
+//
+// Author: James Stanard
+//
+
+
+#pragma once
+
+/// \file
+/// Implementation of mipmap generation routines
+
+
+namespace Diligent
+{
+ class GenerateMipsHelper
+ {
+#if 0
+ public:
+ GenerateMipsHelper(ID3D12Device *pd3d12Device);
+
+ void GenerateMips(class RenderDeviceD3D12Impl *pRenderDeviceD3D12, class TextureViewD3D12Impl *pTexView, class CommandContext &Ctx);
+
+ private:
+ CComPtr<ID3D12RootSignature> m_pGenerateMipsRS;
+ CComPtr<ID3D12PipelineState> m_pGenerateMipsLinearPSO[4];
+ CComPtr<ID3D12PipelineState> m_pGenerateMipsGammaPSO[4];
+#endif
+ };
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
new file mode 100644
index 00000000..762511ba
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h
@@ -0,0 +1,128 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::PipelineStateVkImpl class
+
+#include "RenderDeviceVk.h"
+#include "PipelineStateVk.h"
+#include "PipelineStateBase.h"
+#include "RootSignature.h"
+#include "ShaderResourceLayoutVk.h"
+#include "AdaptiveFixedBlockAllocator.h"
+
+/// Namespace for the Direct3D11 implementation of the graphics engine
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+/// Implementation of the Diligent::IRenderDeviceVk interface
+class PipelineStateVkImpl : public PipelineStateBase<IPipelineStateVk, IRenderDeviceVk>
+{
+public:
+ typedef PipelineStateBase<IPipelineStateVk, IRenderDeviceVk> TPipelineStateBase;
+
+ PipelineStateVkImpl( IReferenceCounters *pRefCounters, class RenderDeviceVkImpl *pDeviceVk, const PipelineStateDesc &PipelineDesc );
+ ~PipelineStateVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface );
+
+ //virtual IVkPipelineState *GetVkPipelineState()const override final{return m_pVkPSO;}
+
+ virtual void BindShaderResources( IResourceMapping *pResourceMapping, Uint32 Flags )override;
+
+ virtual void CreateShaderResourceBinding( IShaderResourceBinding **ppShaderResourceBinding )override;
+
+ virtual bool IsCompatibleWith(const IPipelineState *pPSO)const override final;
+
+ //virtual IVkRootSignature *GetVkRootSignature()const override final{return m_RootSig.GetVkRootSignature(); }
+
+ //ShaderResourceCacheVk* CommitAndTransitionShaderResources(IShaderResourceBinding *pShaderResourceBinding,
+ // class CommandContext &Ctx,
+ // bool CommitResources,
+ // bool TransitionResources)const;
+
+ //const RootSignature& GetRootSignature()const{return m_RootSig;}
+
+ //const ShaderResourceLayoutVk& GetShaderResLayout(SHADER_TYPE ShaderType)const;
+
+ //bool dbgContainsShaderResources()const;
+
+ //IMemoryAllocator &GetResourceCacheDataAllocator(){return m_ResourceCacheDataAllocator;}
+ //IMemoryAllocator &GetShaderResourceLayoutDataAllocator(Uint32 ActiveShaderInd)
+ //{
+ // VERIFY_EXPR(ActiveShaderInd < m_NumShaders);
+ // auto *pAllocator = m_ResLayoutDataAllocators.GetAllocator(ActiveShaderInd);
+ // return pAllocator != nullptr ? *pAllocator : GetRawAllocator();
+ //}
+
+ //IShaderVariable *GetDummyShaderVar(){return &m_DummyVar;}
+
+private:
+
+#if 0
+ void ParseShaderResourceLayout(IShader *pShader);
+
+ /// Vk device
+ CComPtr<IVkPipelineState> m_pVkPSO;
+ RootSignature m_RootSig;
+ DummyShaderVariable m_DummyVar;
+
+ // Looks like there may be a bug in msvc: when allocators are declared as
+ // an array and if an exception is thrown from constructor, the app crashes
+ class ResLayoutDataAllocators
+ {
+ public:
+ ~ResLayoutDataAllocators()
+ {
+ for(size_t i=0; i < _countof(m_pAllocators); ++i)
+ if(m_pAllocators[i] != nullptr)
+ DESTROY_POOL_OBJECT(m_pAllocators[i]);
+ }
+ void Init(Uint32 NumActiveShaders, Uint32 SRBAllocationGranularity)
+ {
+ VERIFY_EXPR(NumActiveShaders <= _countof(m_pAllocators) );
+ for(Uint32 i=0; i < NumActiveShaders; ++i)
+ m_pAllocators[i] = NEW_POOL_OBJECT(AdaptiveFixedBlockAllocator, "Shader resource layout data allocator", GetRawAllocator(), SRBAllocationGranularity);
+ }
+ AdaptiveFixedBlockAllocator *GetAllocator(Uint32 ActiveShaderInd)
+ {
+ VERIFY_EXPR(ActiveShaderInd < _countof(m_pAllocators) );
+ return m_pAllocators[ActiveShaderInd];
+ }
+ private:
+ AdaptiveFixedBlockAllocator *m_pAllocators[5] = {};
+ }m_ResLayoutDataAllocators; // Allocators must be defined before default SRB
+
+ ShaderResourceLayoutVk* m_pShaderResourceLayouts[6] = {};
+ AdaptiveFixedBlockAllocator m_ResourceCacheDataAllocator; // Use separate allocator for every shader stage
+
+ // Do not use strong reference to avoid cyclic references
+ // Default SRB must be defined after allocators
+ std::unique_ptr<class ShaderResourceBindingVkImpl, STDDeleter<ShaderResourceBindingVkImpl, FixedBlockMemoryAllocator> > m_pDefaultShaderResBinding;
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
new file mode 100644
index 00000000..a385d950
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h
@@ -0,0 +1,170 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::RenderDeviceVkImpl class
+
+#include "RenderDeviceVk.h"
+#include "RenderDeviceBase.h"
+#include "DescriptorHeap.h"
+#include "CommandListManager.h"
+#include "CommandContext.h"
+#include "DynamicUploadHeap.h"
+#include "Atomics.h"
+#include "CommandQueueVk.h"
+
+/// Namespace for the Direct3D11 implementation of the graphics engine
+namespace Diligent
+{
+
+/// Implementation of the Diligent::IRenderDeviceVk interface
+class RenderDeviceVkImpl : public RenderDeviceBase<IRenderDeviceVk>
+{
+public:
+ typedef RenderDeviceBase<IRenderDeviceVk> TRenderDeviceBase;
+
+ RenderDeviceVkImpl( IReferenceCounters *pRefCounters, IMemoryAllocator &RawMemAllocator, const EngineVkAttribs &CreationAttribs, void *pVkDevice, ICommandQueueVk *pCmdQueue, Uint32 NumDeferredContexts );
+ ~RenderDeviceVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override final;
+
+ virtual void CreatePipelineState( const PipelineStateDesc &PipelineDesc, IPipelineState **ppPipelineState )override final;
+
+ virtual void CreateBuffer(const BufferDesc& BuffDesc, const BufferData &BuffData, IBuffer **ppBuffer)override final;
+
+ virtual void CreateShader(const ShaderCreationAttribs &ShaderCreationAttribs, IShader **ppShader)override final;
+
+ virtual void CreateTexture(const TextureDesc& TexDesc, const TextureData &Data, ITexture **ppTexture)override final;
+
+ //void CreateTexture(const TextureDesc& TexDesc, IVkResource *pVkTexture, class TextureVkImpl **ppTexture);
+
+ virtual void CreateSampler(const SamplerDesc& SamplerDesc, ISampler **ppSampler)override final;
+
+ //virtual IVkDevice* GetVkDevice()override final{return m_pVkDevice;}
+
+ //virtual void CreateTextureFromD3DResource(IVkResource *pVkTexture, ITexture **ppTexture)override final;
+
+ //virtual void CreateBufferFromD3DResource(IVkResource *pVkBuffer, const BufferDesc& BuffDesc, IBuffer **ppBuffer)override final;
+
+/*
+ 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
+ {
+ return m_pCommandQueue->GetNextFenceValue();
+ }
+
+ 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 SafeReleaseVkObject(IVkObject* pObj);
+ void FinishFrame(bool ReleaseAllResources);
+ virtual void FinishFrame()override final { FinishFrame(false); }
+
+ DynamicUploadHeap* RequestUploadHeap();
+ void ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap);
+ */
+private:
+#if 0
+ virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat );
+ void ProcessReleaseQueue(Uint64 CompletedFenceValue);
+ void DiscardStaleVkObjects(Uint64 CmdListNumber, Uint64 FenceValue);
+
+ /// Vk device
+ CComPtr<IVkDevice> m_pVkDevice;
+ RefCntAutoPtr<ICommandQueueVk> m_pCommandQueue;
+
+ EngineVkAttribs m_EngineAttribs;
+
+ CPUDescriptorHeap m_CPUDescriptorHeaps[Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
+ GPUDescriptorHeap m_GPUDescriptorHeaps[2]; // Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV == 0
+ // Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER == 1
+
+ const Uint32 m_DynamicDescriptorAllocationChunkSize[2];
+
+ std::mutex m_CmdQueueMutex;
+
+ Atomics::AtomicInt64 m_FrameNumber;
+ Atomics::AtomicInt64 m_NextCmdListNumber;
+
+ // 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
+ //
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+
+ //
+ // CPU
+ // Last Reference
+ // of resource X
+ // |
+ // | Submit Cmd Submit Cmd Submit Cmd
+ // | List N List N+1 List N+2
+ // V | | |
+ // NextFenceValue | * N | N+1 | N+2 |
+ //
+ //
+ // CompletedFenceValue | N-3 | N-2 | N-1 | N |
+ // . . . . .
+ // -----------------------------.--------------.---------------.-------------------.----------------.-------------
+ // . . . . .
+ //
+ // GPU | Cmd List N-2 | Cmd List N-1 | Cmd List N | Cmd List N+1 |
+ // |
+ // |
+ // Resource X can
+ // be released
+
+ CommandListManager m_CmdListManager;
+
+ 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::mutex m_ReleaseQueueMutex;
+ typedef std::pair<Uint64, CComPtr<IVkObject> > ReleaseQueueElemType;
+ std::deque< ReleaseQueueElemType, STDAllocatorRawMem<ReleaseQueueElemType> > m_VkObjReleaseQueue;
+
+ std::mutex m_StaleObjectsMutex;
+ std::deque< ReleaseQueueElemType, STDAllocatorRawMem<ReleaseQueueElemType> > m_StaleVkObjects;
+
+ std::mutex m_UploadHeapMutex;
+ typedef std::unique_ptr<DynamicUploadHeap, STDDeleterRawMem<DynamicUploadHeap> > UploadHeapPoolElemType;
+ std::vector< UploadHeapPoolElemType, STDAllocatorRawMem<UploadHeapPoolElemType> > m_UploadHeaps;
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/RootSignature.h b/Graphics/GraphicsEngineVulkan/include/RootSignature.h
new file mode 100644
index 00000000..7545f54b
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/RootSignature.h
@@ -0,0 +1,433 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::RootSignature class
+#include "ShaderBase.h"
+#include "ShaderResourceLayoutVk.h"
+
+namespace Diligent
+{
+
+#if 0
+SHADER_TYPE ShaderTypeFromShaderVisibility(Vk_SHADER_VISIBILITY ShaderVisibility);
+Vk_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType);
+Vk_DESCRIPTOR_HEAP_TYPE dbgHeapTypeFromRangeType(Vk_DESCRIPTOR_RANGE_TYPE RangeType);
+
+class RootParameter
+{
+public:
+
+ RootParameter(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) :
+ m_RootIndex(RootIndex),
+ m_ShaderVarType(VarType)
+ {
+ VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV || ParameterType == Vk_ROOT_PARAMETER_TYPE_SRV || ParameterType == Vk_ROOT_PARAMETER_TYPE_UAV, "Unexpected parameter type - verify argument list");
+ m_RootParam.ParameterType = ParameterType;
+ m_RootParam.ShaderVisibility = Visibility;
+ m_RootParam.Descriptor.ShaderRegister = Register;
+ m_RootParam.Descriptor.RegisterSpace = RegisterSpace;
+ }
+
+ RootParameter( Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, UINT NumDwords, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) :
+ m_RootIndex(RootIndex),
+ m_ShaderVarType(VarType)
+ {
+ VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, "Unexpected parameter type - verify argument list");
+ m_RootParam.ParameterType = ParameterType;
+ m_RootParam.ShaderVisibility = Visibility;
+ m_RootParam.Constants.Num32BitValues = NumDwords;
+ m_RootParam.Constants.ShaderRegister = Register;
+ m_RootParam.Constants.RegisterSpace = RegisterSpace;
+ }
+
+ RootParameter( Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT NumRanges, Vk_DESCRIPTOR_RANGE *pRanges, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) :
+ m_RootIndex(RootIndex),
+ m_ShaderVarType(VarType)
+ {
+ VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Unexpected parameter type - verify argument list");
+ VERIFY_EXPR(pRanges != nullptr);
+ m_RootParam.ParameterType = ParameterType;
+ m_RootParam.ShaderVisibility = Visibility;
+ m_RootParam.DescriptorTable.NumDescriptorRanges = NumRanges;
+ m_RootParam.DescriptorTable.pDescriptorRanges = pRanges;
+#ifdef _DEBUG
+ for(Uint32 r=0; r < NumRanges; ++r)
+ pRanges[r].RangeType = static_cast<Vk_DESCRIPTOR_RANGE_TYPE>(-1);
+#endif
+ }
+
+ RootParameter(const RootParameter &RP):
+ m_RootParam( RP.m_RootParam),
+ m_DescriptorTableSize(RP.m_DescriptorTableSize),
+ m_ShaderVarType(RP.m_ShaderVarType),
+ m_RootIndex(RP.m_RootIndex)
+ {
+ VERIFY(m_RootParam.ParameterType != Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Use another constructor to copy descriptor table");
+ }
+
+ RootParameter(const RootParameter &RP, UINT NumRanges, Vk_DESCRIPTOR_RANGE *pRanges):
+ m_RootParam( RP.m_RootParam),
+ m_DescriptorTableSize(RP.m_DescriptorTableSize),
+ m_ShaderVarType(RP.m_ShaderVarType),
+ m_RootIndex(RP.m_RootIndex)
+ {
+ VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table");
+ VERIFY(NumRanges >= m_RootParam.DescriptorTable.NumDescriptorRanges, "New table must be larger than source one");
+ auto &DstTbl = m_RootParam.DescriptorTable;
+ DstTbl.NumDescriptorRanges = NumRanges;
+ DstTbl.pDescriptorRanges = pRanges;
+ const auto &SrcTbl = RP.m_RootParam.DescriptorTable;
+ memcpy(pRanges, SrcTbl.pDescriptorRanges, SrcTbl.NumDescriptorRanges * sizeof(Vk_DESCRIPTOR_RANGE));
+#ifdef _DEBUG
+ {
+ Uint32 dbgTableSize = 0;
+ for (Uint32 r = 0; r < SrcTbl.NumDescriptorRanges; ++r)
+ {
+ const auto &Range = SrcTbl.pDescriptorRanges[r];
+ dbgTableSize = std::max(dbgTableSize, Range.OffsetInDescriptorsFromTableStart + Range.NumDescriptors);
+ }
+ VERIFY(dbgTableSize == m_DescriptorTableSize, "Incorrect descriptor table size");
+
+ for (Uint32 r = SrcTbl.NumDescriptorRanges; r < DstTbl.NumDescriptorRanges; ++r)
+ pRanges[r].RangeType = static_cast<Vk_DESCRIPTOR_RANGE_TYPE>(-1);
+ }
+#endif
+ }
+
+ RootParameter& operator = (const RootParameter &RP) = delete;
+ RootParameter& operator = (RootParameter &&RP) = delete;
+
+ void SetDescriptorRange( UINT RangeIndex, Vk_DESCRIPTOR_RANGE_TYPE Type, UINT Register, UINT Count, UINT Space = 0, UINT OffsetFromTableStart = Vk_DESCRIPTOR_RANGE_OFFSET_APPEND)
+ {
+ VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected");
+ auto &Tbl = m_RootParam.DescriptorTable;
+ VERIFY(RangeIndex < Tbl.NumDescriptorRanges, "Invalid descriptor range index");
+ Vk_DESCRIPTOR_RANGE &range = const_cast<Vk_DESCRIPTOR_RANGE &>(Tbl.pDescriptorRanges[RangeIndex]);
+ VERIFY(range.RangeType == static_cast<Vk_DESCRIPTOR_RANGE_TYPE>(-1), "Descriptor range has already been initialized. m_DescriptorTableSize may be updated incorrectly");
+ range.RangeType = Type;
+ range.NumDescriptors = Count;
+ range.BaseShaderRegister = Register;
+ range.RegisterSpace = Space;
+ range.OffsetInDescriptorsFromTableStart = OffsetFromTableStart;
+ m_DescriptorTableSize = std::max(m_DescriptorTableSize, OffsetFromTableStart + Count);
+ }
+
+ SHADER_VARIABLE_TYPE GetShaderVariableType()const{ return m_ShaderVarType; }
+ Uint32 GetDescriptorTableSize()const
+ {
+ VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected");
+ return m_DescriptorTableSize;
+ }
+ Vk_SHADER_VISIBILITY GetShaderVisibility()const{return m_RootParam.ShaderVisibility;}
+ Vk_ROOT_PARAMETER_TYPE GetParameterType()const{return m_RootParam.ParameterType;}
+
+ Uint32 GetRootIndex()const{return m_RootIndex;}
+
+ operator const Vk_ROOT_PARAMETER&()const{return m_RootParam;}
+
+ bool operator == (const RootParameter&rhs)const
+ {
+ if (m_ShaderVarType != rhs.m_ShaderVarType ||
+ m_DescriptorTableSize != rhs.m_DescriptorTableSize ||
+ m_RootIndex != rhs.m_RootIndex)
+ return false;
+
+ if (m_RootParam.ParameterType != rhs.m_RootParam.ParameterType ||
+ m_RootParam.ShaderVisibility != rhs.m_RootParam.ShaderVisibility)
+ return false;
+
+ switch(m_RootParam.ParameterType)
+ {
+ case Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+ {
+ const auto &tbl0 = m_RootParam.DescriptorTable;
+ const auto &tbl1 = rhs.m_RootParam.DescriptorTable;
+ if(tbl0.NumDescriptorRanges != tbl1.NumDescriptorRanges)
+ return false;
+ for(UINT r=0; r < tbl0.NumDescriptorRanges; ++r)
+ {
+ const auto &rng0 = tbl0.pDescriptorRanges[r];
+ const auto &rng1 = tbl1.pDescriptorRanges[r];
+ if( memcmp(&rng0, &rng1, sizeof(rng0)) != 0)
+ return false;
+ }
+ }
+ break;
+
+ case Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+ {
+ const auto &cnst0 = m_RootParam.Constants;
+ const auto &cnst1 = rhs.m_RootParam.Constants;
+ if (memcmp(&cnst0, &cnst1, sizeof(cnst0)) != 0)
+ return false;
+ }
+ break;
+
+ case Vk_ROOT_PARAMETER_TYPE_CBV:
+ case Vk_ROOT_PARAMETER_TYPE_SRV:
+ case Vk_ROOT_PARAMETER_TYPE_UAV:
+ {
+ const auto &dscr0 = m_RootParam.Descriptor;
+ const auto &dscr1 = rhs.m_RootParam.Descriptor;
+ if (memcmp(&dscr0, &dscr1, sizeof(dscr0)) != 0)
+ return false;
+ }
+ break;
+
+ default: UNEXPECTED("Unexpected root parameter type");
+ }
+
+ return true;
+ }
+
+ bool operator != (const RootParameter&rhs)const
+ {
+ return !(*this == rhs);
+ }
+
+ size_t GetHash()const
+ {
+ size_t hash = ComputeHash(m_ShaderVarType, m_DescriptorTableSize, m_RootIndex);
+ HashCombine(hash, m_RootParam.ParameterType, m_RootParam.ShaderVisibility);
+
+ switch (m_RootParam.ParameterType)
+ {
+ case Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+ {
+ const auto &tbl = m_RootParam.DescriptorTable;
+ HashCombine(hash, tbl.NumDescriptorRanges);
+ for (UINT r = 0; r < tbl.NumDescriptorRanges; ++r)
+ {
+ const auto &rng = tbl.pDescriptorRanges[r];
+ HashCombine(hash, rng.BaseShaderRegister, rng.NumDescriptors, rng.OffsetInDescriptorsFromTableStart, rng.RangeType, rng.RegisterSpace);
+ }
+ }
+ break;
+
+ case Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+ {
+ const auto &cnst = m_RootParam.Constants;
+ HashCombine(hash, cnst.Num32BitValues, cnst.RegisterSpace, cnst.ShaderRegister);
+ }
+ break;
+
+ case Vk_ROOT_PARAMETER_TYPE_CBV:
+ case Vk_ROOT_PARAMETER_TYPE_SRV:
+ case Vk_ROOT_PARAMETER_TYPE_UAV:
+ {
+ const auto &dscr = m_RootParam.Descriptor;
+ HashCombine(hash, dscr.RegisterSpace, dscr.ShaderRegister);
+ }
+ break;
+
+ default: UNEXPECTED("Unexpected root parameter type");
+ }
+
+ return hash;
+ }
+
+private:
+
+ SHADER_VARIABLE_TYPE m_ShaderVarType = static_cast<SHADER_VARIABLE_TYPE>(-1);
+ Vk_ROOT_PARAMETER m_RootParam = {};
+ Uint32 m_DescriptorTableSize = 0;
+ Uint32 m_RootIndex = static_cast<Uint32>(-1);
+};
+
+
+
+/// Implementation of the Diligent::RootSignature class
+class RootSignature
+{
+public:
+ RootSignature();
+
+ void AllocateStaticSamplers(IShader* const *ppShaders, Uint32 NumShaders);
+
+ void Finalize(IVkDevice *pVkDevice);
+
+ IVkRootSignature* GetVkRootSignature()const{return m_pVkRootSignature;}
+ void InitResourceCache(class RenderDeviceVkImpl *pDeviceVkImpl, class ShaderResourceCacheVk& ResourceCache, IMemoryAllocator &CacheMemAllocator)const;
+
+ void InitStaticSampler(SHADER_TYPE ShaderType, const String &TextureName, const D3DShaderResourceAttribs &ShaderResAttribs);
+
+ void AllocateResourceSlot(SHADER_TYPE ShaderType, const D3DShaderResourceAttribs &ShaderResAttribs, Vk_DESCRIPTOR_RANGE_TYPE RangeType, Uint32 &RootIndex, Uint32 &OffsetFromTableStart);
+
+ // This method should be thread-safe as it does not modify any object state
+ void (RootSignature::*CommitDescriptorHandles)(class RenderDeviceVkImpl *pRenderDeviceVk,
+ ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx,
+ bool IsCompute)const = nullptr;
+
+ void (RootSignature::*TransitionAndCommitDescriptorHandles)(class RenderDeviceVkImpl *pRenderDeviceVk,
+ ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx,
+ bool IsCompute)const = nullptr;
+
+ void TransitionResources(ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx)const;
+
+ void CommitRootViews(ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx,
+ bool IsCompute,
+ Uint32 ContextId)const;
+
+ Uint32 GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE VarType)const
+ {
+ VERIFY_EXPR(VarType >= 0 && VarType < SHADER_VARIABLE_TYPE_NUM_TYPES);
+ return m_TotalSrvCbvUavSlots[VarType];
+ }
+ Uint32 GetTotalSamplerSlots(SHADER_VARIABLE_TYPE VarType)const
+ {
+ VERIFY_EXPR(VarType >= 0 && VarType < SHADER_VARIABLE_TYPE_NUM_TYPES);
+ return m_TotalSamplerSlots[VarType];
+ }
+
+ bool IsSameAs(const RootSignature& RS)const
+ {
+ return m_RootParams == RS.m_RootParams;
+ }
+ size_t GetHash()const
+ {
+ return m_RootParams.GetHash();
+ }
+
+private:
+#ifdef _DEBUG
+ void dbgVerifyRootParameters()const;
+#endif
+
+ Uint32 m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_NUM_TYPES];
+ Uint32 m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_NUM_TYPES];
+
+ CComPtr<IVkRootSignature> m_pVkRootSignature;
+
+ class RootParamsManager
+ {
+ public:
+ RootParamsManager(IMemoryAllocator &MemAllocator);
+
+ RootParamsManager(const RootParamsManager&) = delete;
+ RootParamsManager& operator= (const RootParamsManager&) = delete;
+ RootParamsManager(RootParamsManager&&) = delete;
+ RootParamsManager& operator= (RootParamsManager&&) = delete;
+
+ Uint32 GetNumRootTables()const{return m_NumRootTables;}
+ Uint32 GetNumRootViews()const{return m_NumRootViews;}
+
+ const RootParameter& GetRootTable(Uint32 TableInd)const
+ {
+ VERIFY_EXPR(TableInd < m_NumRootTables);
+ return m_pRootTables[TableInd];
+ }
+
+ RootParameter& GetRootTable(Uint32 TableInd)
+ {
+ VERIFY_EXPR(TableInd < m_NumRootTables);
+ return m_pRootTables[TableInd];
+ }
+
+ const RootParameter& GetRootView(Uint32 ViewInd)const
+ {
+ VERIFY_EXPR(ViewInd < m_NumRootViews);
+ return m_pRootViews[ViewInd];
+ }
+
+ RootParameter& GetRootView(Uint32 ViewInd)
+ {
+ VERIFY_EXPR(ViewInd < m_NumRootViews);
+ return m_pRootViews[ViewInd];
+ }
+
+ void AddRootView(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType);
+ void AddRootTable(Uint32 RootIndex, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType, Uint32 NumRangesInNewTable = 1);
+ void AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges = 1);
+
+ template<class TOperation>
+ void ProcessRootTables(TOperation)const;
+
+ bool operator == (const RootParamsManager& RootParams)const;
+ size_t GetHash()const;
+
+ private:
+ size_t GetRequiredMemorySize(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges)const;
+ Vk_DESCRIPTOR_RANGE* Extend(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges, Uint32 RootTableToAddRanges = static_cast<Uint32>(-1));
+
+ IMemoryAllocator &m_MemAllocator;
+ std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pMemory;
+ Uint32 m_NumRootTables = 0;
+ Uint32 m_NumRootViews = 0;
+ Uint32 m_TotalDescriptorRanges = 0;
+ RootParameter *m_pRootTables = nullptr;
+ RootParameter *m_pRootViews = nullptr;
+ };
+
+ static constexpr Uint8 InvalidRootTableIndex = static_cast<Uint8>(-1);
+
+ // The array below contains array index of a CBV/SRV/UAV root table
+ // in m_RootParams (NOT the Root Index!), for every variable type
+ // (static, mutable, dynamic) and every shader type,
+ // or -1, if the table is not yet assigned to the combination
+ Uint8 m_SrvCbvUavRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6];
+ // This array contains the same data for Sampler root table
+ Uint8 m_SamplerRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6];
+
+ RootParamsManager m_RootParams;
+
+ struct StaticSamplerAttribs
+ {
+ StaticSamplerDesc SamplerDesc;
+ UINT ShaderRegister = static_cast<UINT>(-1);
+ UINT ArraySize = 0;
+ UINT RegisterSpace = 0;
+ Vk_SHADER_VISIBILITY ShaderVisibility = static_cast<Vk_SHADER_VISIBILITY>(-1);
+
+ StaticSamplerAttribs(){}
+ StaticSamplerAttribs(const StaticSamplerDesc& SamDesc, Vk_SHADER_VISIBILITY Visibility) :
+ SamplerDesc(SamDesc),
+ ShaderVisibility(Visibility)
+ {}
+ };
+ // Note: sizeof(m_StaticSamplers) == 56 (MS compiler, release x64)
+ std::vector<StaticSamplerAttribs, STDAllocatorRawMem<StaticSamplerAttribs> > m_StaticSamplers;
+
+ IMemoryAllocator &m_MemAllocator;
+
+ // Commits descriptor handles for static and mutable variables
+ template<bool PerformResourceTransitions>
+ void CommitDescriptorHandlesInternal_SM(class RenderDeviceVkImpl *pRenderDeviceVk,
+ ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx,
+ bool IsCompute)const;
+ template<bool PerformResourceTransitions>
+ // Commits descriptor handles for static, mutable, and dynamic variables
+ void CommitDescriptorHandlesInternal_SMD(class RenderDeviceVkImpl *pRenderDeviceVk,
+ ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx,
+ bool IsCompute)const;
+};
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/SamplerVkImpl.h b/Graphics/GraphicsEngineVulkan/include/SamplerVkImpl.h
new file mode 100644
index 00000000..9ed871e2
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/SamplerVkImpl.h
@@ -0,0 +1,57 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::SamplerVkImpl class
+
+#include "SamplerVk.h"
+#include "RenderDeviceVk.h"
+#include "SamplerBase.h"
+#include "DescriptorHeap.h"
+
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+/// Implementation of the Diligent::ISamplerVk interface
+class SamplerVkImpl : public SamplerBase<ISamplerVk, IRenderDeviceVk>
+{
+public:
+ typedef SamplerBase<ISamplerVk, IRenderDeviceVk> TSamplerBase;
+
+ SamplerVkImpl(IReferenceCounters *pRefCounters, class RenderDeviceVkImpl *pRenderDeviceVk, const SamplerDesc& SamplerDesc);
+ ~SamplerVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+
+ //virtual Vk_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override{ return m_Descriptor.GetCpuHandle(); }
+
+private:
+ friend class ShaderVkImpl;
+ /// Vk sampler
+ DescriptorHeapAllocation m_Descriptor;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h
new file mode 100644
index 00000000..a669ac5d
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.h
@@ -0,0 +1,82 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::ShaderResourceBindingVkImpl class
+
+#include "ShaderResourceBindingVk.h"
+#include "RenderDeviceVk.h"
+#include "ShaderResourceBindingBase.h"
+#include "ShaderBase.h"
+#include "ShaderResourceCacheVk.h"
+#include "ShaderResourceLayoutVk.h"
+
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+/// Implementation of the Diligent::IShaderResourceBindingVk interface
+class ShaderResourceBindingVkImpl : public ShaderResourceBindingBase<IShaderResourceBindingVk>
+{
+public:
+ typedef ShaderResourceBindingBase<IShaderResourceBindingVk> TBase;
+ ShaderResourceBindingVkImpl(IReferenceCounters *pRefCounters, class PipelineStateVkImpl *pPSO, bool IsPSOInternal);
+ ~ShaderResourceBindingVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+
+ virtual void BindResources(Uint32 ShaderFlags, IResourceMapping *pResMapping, Uint32 Flags)override;
+
+ virtual IShaderVariable *GetVariable(SHADER_TYPE ShaderType, const char *Name)override;
+
+/* ShaderResourceLayoutVk& GetResourceLayout(SHADER_TYPE ResType)
+ {
+ auto ShaderInd = GetShaderTypeIndex(ResType);
+ auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
+ VERIFY(ResLayoutInd >= 0, "Shader resource layout is not initialized");
+ VERIFY_EXPR(ResLayoutInd < (Int32)m_NumShaders);
+ return m_pResourceLayouts[ResLayoutInd];
+ }
+ ShaderResourceCacheVk& GetResourceCache(){return m_ShaderResourceCache;}
+
+#ifdef VERIFY_SHADER_BINDINGS
+ void dbgVerifyResourceBindings(const PipelineStateVkImpl *pPSO);
+#endif
+
+ bool StaticResourcesInitialized()const{return m_bStaticResourcesInitialized;}
+ void InitializeStaticResources(const PipelineStateVkImpl *pPSO);
+
+private:
+
+ ShaderResourceCacheVk m_ShaderResourceCache;
+ ShaderResourceLayoutVk* m_pResourceLayouts = nullptr;
+ // Resource layout index in m_ResourceLayouts[] array for every shader stage
+ Int8 m_ResourceLayoutIndex[6] = {-1, -1, -1, -1, -1, -1};
+ bool m_bStaticResourcesInitialized = false;
+ Uint32 m_NumShaders = 0;
+*/
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h
new file mode 100644
index 00000000..91f709b8
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h
@@ -0,0 +1,309 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::ShaderResourceCacheD3D12 class
+
+// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache/
+
+// Shader resource cache stores D3D12 resources in a continuous chunk of memory:
+//
+//
+// __________________________________________________________
+// m_pMemory | m_pResources, m_NumResources == m |
+// | | |
+// V | V
+// | RootTable[0] | .... | RootTable[Nrt-1] | Res[0] | ... | Res[n-1] | .... | Res[0] | ... | Res[m-1] |
+// | A \
+// | | \
+// |________________________________________________| \RefCntAutoPtr
+// m_pResources, m_NumResources == n \_________
+// | Object |
+// ---------
+//
+// Nrt = m_NumTables
+//
+//
+// The cache is also assigned decriptor heap space to store shader visible descriptor handles (for non-dynamic resources).
+//
+//
+// DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV
+// | DescrptHndl[0] ... DescrptHndl[n-1] | DescrptHndl[0] ... DescrptHndl[m-1] |
+// A A
+// | |
+// | TableStartOffset | TableStartOffset
+// | |
+// | RootTable[0] | RootTable[1] | RootTable[2] | .... | RootTable[Nrt] |
+// | |
+// | TableStartOffset | InvalidDescriptorOffset
+// | |
+// V V
+// | DescrptHndl[0] ... DescrptHndl[n-1] | X
+// DESCRIPTOR_HEAP_TYPE_SAMPLER
+//
+//
+//
+// The allocation is inexed by the offset from the beginning of the root table
+// Each root table is assigned the space to store exactly m_NumResources resources
+// Dynamic resources are not assigned space in the descriptor heap allocation.
+//
+//
+//
+// | RootTable[i] | Res[0] ... Res[n-1] |
+// \
+// TableStartOffset\____
+// \
+// V
+// ..... | DescrptHndl[0] ... DescrptHndl[n-1] | ....
+//
+
+#include "DescriptorHeap.h"
+
+namespace Diligent
+{
+#if 0
+enum class CachedResourceType : Int32
+{
+ Unknown = -1,
+ CBV = 0,
+ TexSRV,
+ BufSRV,
+ TexUAV,
+ BufUAV,
+ Sampler,
+ NumTypes
+};
+
+class ShaderResourceCacheD3D12
+{
+public:
+ // This enum is used for debug purposes only
+ enum DbgCacheContentType
+ {
+ StaticShaderResources,
+ SRBResources
+ };
+
+ ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType)
+#ifdef _DEBUG
+ : m_DbgContentType(dbgContentType)
+#endif
+ {
+ }
+
+ ~ShaderResourceCacheD3D12();
+
+ void Initialize(IMemoryAllocator &MemAllocator, Uint32 NumTables, Uint32 TableSizes[]);
+
+ static constexpr Uint32 InvalidDescriptorOffset = static_cast<Uint32>(-1);
+
+ //http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Cache-Structure
+ struct Resource
+ {
+ CachedResourceType Type = CachedResourceType::Unknown;
+ // CPU descriptor handle of a cached resource in CPU-only descriptor heap
+ // Note that for dynamic resources, this is the only available CPU descriptor handle
+ D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0};
+ RefCntAutoPtr<IDeviceObject> pObject;
+ };
+
+ class RootTable
+ {
+ public:
+ RootTable(Uint32 NumResources, Resource *pResources) :
+ m_NumResources(NumResources),
+ m_pResources(pResources)
+ {}
+
+ inline Resource& GetResource(Uint32 OffsetFromTableStart,
+ const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType,
+ const SHADER_TYPE dbgRefShaderType)
+ {
+ VERIFY(m_dbgHeapType == dbgDescriptorHeapType, "Incosistent descriptor heap type" );
+ VERIFY(m_dbgShaderType == dbgRefShaderType, "Incosistent shader type" );
+
+ VERIFY(OffsetFromTableStart < m_NumResources, "Root table at index is not large enough to store descriptor at offset ", OffsetFromTableStart );
+ return m_pResources[OffsetFromTableStart];
+ }
+
+ inline Uint32 GetSize()const{return m_NumResources; }
+
+ // Offset from the start of the descriptor heap allocation to the start of the table
+ Uint32 m_TableStartOffset = InvalidDescriptorOffset;
+
+#ifdef _DEBUG
+ void SetDebugAttribs(Uint32 MaxOffset,
+ const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType,
+ const SHADER_TYPE dbgRefShaderType)
+ {
+ VERIFY_EXPR(m_NumResources == MaxOffset);
+ m_dbgHeapType = dbgDescriptorHeapType;
+ m_dbgShaderType = dbgRefShaderType;
+ }
+
+ D3D12_DESCRIPTOR_HEAP_TYPE DbgGetHeapType()const{return m_dbgHeapType;}
+#endif
+
+ const Uint32 m_NumResources = 0;
+ private:
+
+#ifdef _DEBUG
+ D3D12_DESCRIPTOR_HEAP_TYPE m_dbgHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES;
+ SHADER_TYPE m_dbgShaderType = SHADER_TYPE_UNKNOWN;
+#endif
+
+ Resource* const m_pResources = nullptr;
+ };
+
+ inline RootTable& GetRootTable(Uint32 RootIndex)
+ {
+ VERIFY_EXPR(RootIndex < m_NumTables);
+ return reinterpret_cast<RootTable*>(m_pMemory)[RootIndex];
+ }
+
+ inline Uint32 GetNumRootTables()const{return m_NumTables; }
+
+ void SetDescriptorHeapSpace(DescriptorHeapAllocation &&CbcSrvUavHeapSpace, DescriptorHeapAllocation &&SamplerHeapSpace)
+ {
+ VERIFY(m_SamplerHeapSpace.GetCpuHandle().ptr == 0 && m_CbvSrvUavHeapSpace.GetCpuHandle().ptr == 0, "Space has already been allocated in GPU descriptor heaps");
+#ifdef _DEBUG
+ Uint32 NumSamplerDescriptors = 0, NumSrvCbvUavDescriptors = 0;
+ for (Uint32 rt = 0; rt < m_NumTables; ++rt)
+ {
+ auto &Tbl = GetRootTable(rt);
+ if(Tbl.m_TableStartOffset != InvalidDescriptorOffset)
+ {
+ if(Tbl.DbgGetHeapType() == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
+ {
+ VERIFY(Tbl.m_TableStartOffset == NumSrvCbvUavDescriptors, "Descriptor space allocation is not continuous");
+ NumSrvCbvUavDescriptors = std::max(NumSrvCbvUavDescriptors, Tbl.m_TableStartOffset + Tbl.GetSize());
+ }
+ else
+ {
+ VERIFY(Tbl.m_TableStartOffset == NumSamplerDescriptors, "Descriptor space allocation is not continuous");
+ NumSamplerDescriptors = std::max(NumSamplerDescriptors, Tbl.m_TableStartOffset + Tbl.GetSize());
+ }
+ }
+ }
+ VERIFY(NumSrvCbvUavDescriptors == CbcSrvUavHeapSpace.GetNumHandles() || NumSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.GetCpuHandle(0).ptr == 0, "Unexpected descriptor heap allocation size" );
+ VERIFY(NumSamplerDescriptors == SamplerHeapSpace.GetNumHandles() || NumSamplerDescriptors == 0 && SamplerHeapSpace.GetCpuHandle(0).ptr == 0, "Unexpected descriptor heap allocation size" );
+#endif
+
+ m_CbvSrvUavHeapSpace = std::move(CbcSrvUavHeapSpace);
+ m_SamplerHeapSpace = std::move(SamplerHeapSpace);
+ }
+
+ ID3D12DescriptorHeap* GetSrvCbvUavDescriptorHeap(){return m_CbvSrvUavHeapSpace.GetDescriptorHeap();}
+ ID3D12DescriptorHeap* GetSamplerDescriptorHeap() {return m_SamplerHeapSpace.GetDescriptorHeap();}
+
+ // Returns CPU descriptor handle of a shader visible descriptor heap allocation
+ template<D3D12_DESCRIPTOR_HEAP_TYPE HeapType>
+ D3D12_CPU_DESCRIPTOR_HANDLE GetShaderVisibleTableCPUDescriptorHandle(Uint32 RootParamInd, Uint32 OffsetFromTableStart = 0)
+ {
+ auto &RootParam = GetRootTable(RootParamInd);
+ VERIFY(HeapType == RootParam.DbgGetHeapType(), "Invalid descriptor heap type");
+
+ D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0};
+ // Descriptor heap allocation is not assigned for dynamic resources or
+ // in a special case when resource cache is used to store static
+ // variable assignments for a shader. It is also not assigned to root views
+ if( RootParam.m_TableStartOffset != InvalidDescriptorOffset )
+ {
+ VERIFY(OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range");
+ if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER )
+ {
+ VERIFY_EXPR(!m_SamplerHeapSpace.IsNull());
+ CPUDescriptorHandle = m_SamplerHeapSpace.GetCpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
+ }
+ else if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV )
+ {
+ VERIFY_EXPR(!m_CbvSrvUavHeapSpace.IsNull());
+ CPUDescriptorHandle = m_CbvSrvUavHeapSpace.GetCpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
+ }
+ else
+ {
+ UNEXPECTED("Unexpected descriptor heap type");
+ }
+ }
+
+ return CPUDescriptorHandle;
+ }
+
+ // Returns GPU descriptor handle of a shader visible descriptor table
+ template<D3D12_DESCRIPTOR_HEAP_TYPE HeapType>
+ D3D12_GPU_DESCRIPTOR_HANDLE GetShaderVisibleTableGPUDescriptorHandle(Uint32 RootParamInd, Uint32 OffsetFromTableStart = 0)
+ {
+ auto &RootParam = GetRootTable(RootParamInd);
+ VERIFY(RootParam.m_TableStartOffset != InvalidDescriptorOffset, "GPU descriptor handle must never be requested for dynamic resources");
+ VERIFY(OffsetFromTableStart < RootParam.m_NumResources, "Offset is out of range");
+
+ D3D12_GPU_DESCRIPTOR_HANDLE GPUDescriptorHandle = {0};
+ VERIFY( HeapType == RootParam.DbgGetHeapType(), "Invalid descriptor heap type");
+ if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER )
+ {
+ VERIFY_EXPR(!m_SamplerHeapSpace.IsNull());
+ GPUDescriptorHandle = m_SamplerHeapSpace.GetGpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
+ }
+ else if( HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV )
+ {
+ VERIFY_EXPR(!m_CbvSrvUavHeapSpace.IsNull());
+ GPUDescriptorHandle = m_CbvSrvUavHeapSpace.GetGpuHandle(RootParam.m_TableStartOffset + OffsetFromTableStart);
+ }
+ else
+ {
+ UNEXPECTED("Unexpected descriptor heap type");
+ }
+
+ return GPUDescriptorHandle;
+ }
+
+#ifdef _DEBUG
+ // Only for debug purposes: indicates what types of resources are stored in the cache
+ DbgCacheContentType DbgGetContentType()const{return m_DbgContentType;}
+#endif
+
+private:
+ ShaderResourceCacheD3D12(const ShaderResourceCacheD3D12&) = delete;
+ ShaderResourceCacheD3D12(ShaderResourceCacheD3D12&&) = delete;
+ ShaderResourceCacheD3D12& operator = (const ShaderResourceCacheD3D12&) = delete;
+ ShaderResourceCacheD3D12& operator = (ShaderResourceCacheD3D12&&) = delete;
+
+ // Allocation in a GPU-visible sampler descriptor heap
+ DescriptorHeapAllocation m_SamplerHeapSpace;
+
+ // Allocation in a GPU-visible CBV/SRV/UAV descriptor heap
+ DescriptorHeapAllocation m_CbvSrvUavHeapSpace;
+
+ IMemoryAllocator *m_pAllocator=nullptr;
+ void *m_pMemory = nullptr;
+ Uint32 m_NumTables = 0;
+
+#ifdef _DEBUG
+ // Only for debug purposes: indicates what types of resources are stored in the cache
+ const DbgCacheContentType m_DbgContentType;
+#endif
+};
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h
new file mode 100644
index 00000000..151daba7
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h
@@ -0,0 +1,418 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::ShaderResourceLayoutVk class
+
+// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout/
+
+// All resources are stored in a single continuous chunk of memory using the following layout:
+//
+// m_ResourceBuffer m_Samplers
+// | |
+// | SRV_CBV_UAV[0] ... SRV_CBV_UAV[s-1] | SRV_CBV_UAV[s] ... SRV_CBV_UAV[s+m-1] | SRV_CBV_UAV[s+m] ... SRV_CBV_UAV[s+m+d-1] || Sampler[0] ... Sampler[s'-1] | Sampler[s'] ... Sampler[s'+m'-1] | Sampler[s'+m'] ... Sampler[s'+m'+d'-1] ||
+// | | | || | | ||
+// | SHADER_VARIABLE_TYPE_STATIC | SHADER_VARIABLE_TYPE_MUTABLE | SHADER_VARIABLE_TYPE_DYNAMIC || SHADER_VARIABLE_TYPE_STATIC | SHADER_VARIABLE_TYPE_MUTABLE | SHADER_VARIABLE_TYPE_DYNAMIC ||
+// | | | ||
+//
+// s == m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_STATIC]
+// m == m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_MUTABLE]
+// d == m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_DYNAMIC]
+//
+// s' == m_NumSamplers[SHADER_VARIABLE_TYPE_STATIC]
+// m' == m_NumSamplers[SHADER_VARIABLE_TYPE_MUTABLE]
+// d' == m_NumSamplers[SHADER_VARIABLE_TYPE_DYNAMIC]
+//
+//
+// Memory buffer is allocated through the allocator provided by the pipeline state. If allocation granularity > 1, fixed block
+// memory allocator is used. This ensures that all resources from different shader resource bindings reside in
+// continuous memory. If allocation granularity == 1, raw allocator is used.
+//
+//
+// Every SRV_CBV_UAV and Sampler structure holds a reference to D3DShaderResourceAttribs structure from ShaderResources.
+// ShaderResourceLayoutVk holds shared pointer to ShaderResourcesVk instance. Note that ShaderResources::SamplerId
+// references a sampler in ShaderResources, while SRV_CBV_UAV::SamplerId references a sampler in ShaderResourceLayoutVk,
+// and the two are not the same
+//
+//
+// ________________SamplerId____________________
+// | |
+// _________________ ______________|_____________________________________________V________
+// | | unique_ptr | | | | | | |
+// | ShaderResources |--------------->| CBs | TexSRVs | TexUAVs | BufSRVs | BufUAVs | Samplers |
+// |_________________| |________|___________|___________|___________|___________|____________|
+// A A A A
+// | \ / \
+// |shared_ptr Ref Ref Ref
+// ________|__________________ ________\________________________/_________________________\_________________________________________
+// | | unique_ptr | | | | | | |
+// | ShaderResourceLayoutVk |--------------->| SRV_CBV_UAV[0] | SRV_CBV_UAV[1] | ... | Sampler[0] | Sampler[1] | ... |
+// |___________________________| |___________________|_________________|_______________|__________________|_________________|__________|
+// | | | A | /
+// | Raw ptr | |___________________SamplerId________________________| | /
+// | | / /
+// | \ / /
+// ________V_________________ ________V_______________________________________________________V____V__
+// | | | |
+// | ShaderResourceCacheVk |---------------->| Resources |
+// |__________________________| |________________________________________________________________________|
+//
+// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Figure2
+// Resources in the resource cache are identified by the root index and offset in the descriptor table
+//
+//
+// ShaderResourceLayoutVk is used as follows:
+// * Every pipeline state object (PipelineStateVkImpl) maintains shader resource layout for every active shader stage
+// ** These resource layouts are not bound to a resource cache and are used as reference layouts for shader resource binding objects
+// ** All variable types are preserved
+// ** Root indices and descriptor table offsets are assigned during the initialization
+// ** Resource cache is not assigned
+// * Every shader object (ShaderVkImpl) contains shader resource layout that facilitates management of static shader resources
+// ** The resource layout defines artificial layout and is bound to a resource cache that actually holds references to resources
+// ** Resource cache is assigned and initialized
+// * Every shader resource binding object (ShaderResourceBindingVkImpl) encompasses shader resource layout for every active shader
+// stage in the parent pipeline state
+// ** Resource layouts are initialized by clonning reference layouts from the pipeline state object and are bound to the resource
+// cache that holds references to resources set by the application
+// ** All shader variable types are clonned
+// ** Resource cache is assigned, but not initialized; Initialization is performed by the root signature
+//
+
+// Set this define to 1 to use unordered_map to store shader variables.
+// Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64).
+#define USE_VARIABLE_HASH_MAP 0
+
+#include "unordered_map"
+
+#include "ShaderBase.h"
+#include "ShaderBase.h"
+#include "HashUtils.h"
+#include "ShaderResourcesVk.h"
+#include "ShaderResourceCacheVk.h"
+//#include "ShaderVariable.h"
+
+#ifdef _DEBUG
+# define VERIFY_SHADER_BINDINGS
+#endif
+
+namespace Diligent
+{
+
+/// Diligent::ShaderResourceLayoutVk class
+// sizeof(ShaderResourceLayoutVk)==80 (MS compiler, x64)
+class ShaderResourceLayoutVk
+{
+public:
+#if 0
+ ShaderResourceLayoutVk(IObject &Owner, IMemoryAllocator &ResourceLayoutDataAllocator);
+
+ // This constructor is used by ShaderResourceBindingVkImpl to clone layout from the reference layout in PipelineStateVkImpl.
+ // Root indices and descriptor table offsets must be correct. Resource cache is assigned, but not initialized.
+ ShaderResourceLayoutVk(IObject &Owner,
+ const ShaderResourceLayoutVk& SrcLayout,
+ IMemoryAllocator &ResourceLayoutDataAllocator,
+ const SHADER_VARIABLE_TYPE *AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ ShaderResourceCacheVk &ResourceCache);
+
+ ShaderResourceLayoutVk(const ShaderResourceLayoutVk&) = delete;
+ ShaderResourceLayoutVk(ShaderResourceLayoutVk&&) = delete;
+ ShaderResourceLayoutVk& operator =(const ShaderResourceLayoutVk&) = delete;
+ ShaderResourceLayoutVk& operator =(ShaderResourceLayoutVk&&) = delete;
+
+ ~ShaderResourceLayoutVk();
+
+ // The method is called by
+ // - ShaderVkImpl class instance to initialize static resource layout and initialize shader resource cache
+ // to hold static resources
+ // - PipelineStateVkImpl class instance to reference all types of resources (static, mutable, dynamic).
+ // Root indices and descriptor table offsets are assigned during the initialization;
+ // no shader resource cache is provided
+ void Initialize(IVkDevice *pVkDevice,
+ const std::shared_ptr<const ShaderResourcesVk>& pSrcResources,
+ IMemoryAllocator &LayoutDataAllocator,
+ const SHADER_VARIABLE_TYPE *VarTypes,
+ Uint32 NumAllowedTypes,
+ ShaderResourceCacheVk *pResourceCache,
+ class RootSignature *pRootSig);
+
+ // sizeof(SRV_CBV_UAV) == 32 (x64)
+ struct SRV_CBV_UAV : ShaderVariableD3DBase<ShaderResourceLayoutVk>
+ {
+ SRV_CBV_UAV(const SRV_CBV_UAV&) = delete;
+ SRV_CBV_UAV(SRV_CBV_UAV&&) = delete;
+ SRV_CBV_UAV& operator = (const SRV_CBV_UAV&) = delete;
+ SRV_CBV_UAV& operator = (SRV_CBV_UAV&&) = delete;
+
+ static constexpr Uint32 ResTypeBits = 3;
+ static constexpr Uint32 RootIndBits = 16-ResTypeBits;
+ static constexpr Uint32 RootIndMask = (1 << RootIndBits)-1;
+ static constexpr Uint32 ResTypeMask = (1 << ResTypeBits)-1;
+
+ static constexpr Uint16 InvalidRootIndex = RootIndMask;
+ static constexpr Uint16 MaxRootIndex = RootIndMask-1;
+
+ static constexpr Uint32 InvalidSamplerId = 0xFFFF;
+ static constexpr Uint32 MaxSamplerId = InvalidSamplerId-1;
+ static constexpr Uint32 InvalidOffset = static_cast<Uint32>(-1);
+
+ static_assert( static_cast<int>(CachedResourceType::NumTypes) <= ResTypeMask, "3 bits is not enough to store CachedResourceType");
+
+ const Uint32 OffsetFromTableStart;
+
+ // Special copy constructor. Note that sampler ID refers to the ID of the sampler
+ // within THIS layout, and may not be the same as in original layout
+ SRV_CBV_UAV(ShaderResourceLayoutVk &ParentLayout, const SRV_CBV_UAV &rhs, Uint32 SamId ) :
+ ResType_RootIndex(rhs.ResType_RootIndex),
+ SamplerId(static_cast<Uint16>(SamId)),
+ OffsetFromTableStart(rhs.OffsetFromTableStart),
+ ShaderVariableD3DBase<ShaderResourceLayoutVk>(ParentLayout, rhs.Attribs)
+ {
+ VERIFY(SamId == InvalidSamplerId || SamId <= MaxSamplerId, "Sampler id exceeds max allowed value (", MaxSamplerId, ")" );
+ VERIFY(rhs.m_ParentResLayout.m_pResources == m_ParentResLayout.m_pResources, "Incosistent resource references");
+ VERIFY(IsValidOffset(), "Offset must be valid" );
+ VERIFY(IsValidRootIndex(), "Root index must be valid" );
+ }
+
+ SRV_CBV_UAV(ShaderResourceLayoutVk &ParentLayout,
+ const D3DShaderResourceAttribs &_Attribs,
+ CachedResourceType ResType,
+ Uint32 RootIndex,
+ Uint32 _OffsetFromTableStart,
+ Uint32 _SamplerId) :
+ ResType_RootIndex( (static_cast<Uint16>(ResType) << RootIndBits) | (RootIndex & RootIndMask)),
+ SamplerId( static_cast<Uint16>(_SamplerId) ),
+ OffsetFromTableStart(_OffsetFromTableStart),
+ ShaderVariableD3DBase<ShaderResourceLayoutVk>(ParentLayout, _Attribs)
+ {
+ VERIFY(RootIndex == InvalidRootIndex || RootIndex <= MaxRootIndex, "Root index exceeds max allowed value (", MaxRootIndex, ")" );
+ VERIFY(IsValidOffset(), "Offset must be valid" );
+ VERIFY(SamplerId == InvalidSamplerId || SamplerId <= MaxSamplerId, "Sampler id exceeds max allowed value (", MaxSamplerId, ")" );
+ }
+
+ bool IsBound(Uint32 ArrayIndex);
+
+ // Non-virtual function
+ void BindResource(IDeviceObject *pObject, Uint32 ArrayIndex, const ShaderResourceLayoutVk *dbgResLayout);
+ virtual void Set(IDeviceObject *pObject)override final{ BindResource(pObject, 0, nullptr); }
+
+ virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final
+ {
+ for(Uint32 Elem = 0; Elem < NumElements; ++Elem)
+ BindResource(ppObjects[Elem], FirstElement+Elem, nullptr);
+ }
+
+ bool IsValidSampler() const{return GetSamplerId() != InvalidSamplerId;}
+ bool IsValidRootIndex()const{return GetRootIndex() != InvalidRootIndex;}
+ bool IsValidOffset() const{return OffsetFromTableStart != InvalidOffset; }
+
+ CachedResourceType GetResType()const
+ {
+ return static_cast<CachedResourceType>( (ResType_RootIndex >> RootIndBits) & ResTypeMask );
+ }
+ Uint32 GetRootIndex()const
+ {
+ return ResType_RootIndex & RootIndMask;
+ }
+
+ Uint32 GetSamplerId()const
+ {
+ return SamplerId;
+ }
+
+ private:
+ const Uint16 ResType_RootIndex; // bit
+ // | 0 1 .... 12 | 13 14 15 |
+ // | | |
+ // | Root index | ResType |
+ const Uint16 SamplerId;
+
+ void CacheCB(IDeviceObject *pBuffer,
+ ShaderResourceCacheVk::Resource& DstRes,
+ Uint32 ArrayInd,
+ Vk_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle);
+
+ template<typename TResourceViewType,
+ typename TViewTypeEnum,
+ typename TBindSamplerProcType>
+ void CacheResourceView(IDeviceObject *pView,
+ ShaderResourceCacheVk::Resource& DstRes,
+ Uint32 ArrayIndex,
+ Vk_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle,
+ TViewTypeEnum dbgExpectedViewType,
+ TBindSamplerProcType BindSamplerProc);
+ };
+
+ // sizeof(Sampler) == 24 (x64)
+ struct Sampler
+ {
+ Sampler(const Sampler&) = delete;
+ Sampler(Sampler&&) = delete;
+ Sampler& operator = (const Sampler&) = delete;
+ Sampler& operator = (Sampler&&) = delete;
+
+ const D3DShaderResourceAttribs &Attribs;
+ ShaderResourceLayoutVk &m_ParentResLayout;
+
+ static constexpr Uint32 InvalidRootIndex = static_cast<Uint32>(-1);
+ static constexpr Uint32 InvalidOffset = static_cast<Uint32>(-1);
+
+ const Uint32 RootIndex;
+ const Uint32 OffsetFromTableStart;
+
+ Sampler(ShaderResourceLayoutVk &ParentLayout, const Sampler& Sam):
+ Attribs(Sam.Attribs),
+ m_ParentResLayout(ParentLayout),
+ RootIndex(Sam.RootIndex),
+ OffsetFromTableStart(Sam.OffsetFromTableStart)
+ {
+ VERIFY(Sam.m_ParentResLayout.m_pResources == m_ParentResLayout.m_pResources, "Incosistent resource references");
+ VERIFY(IsValidRootIndex(), "Root index must be valid" );
+ VERIFY(IsValidOffset(), "Offset must be valid" );
+ }
+
+ Sampler(ShaderResourceLayoutVk &ParentResLayout, const D3DShaderResourceAttribs &_Attribs, Uint32 _RootIndex, Uint32 _OffsetFromTableStart) :
+ RootIndex(_RootIndex),
+ OffsetFromTableStart(_OffsetFromTableStart),
+ Attribs(_Attribs),
+ m_ParentResLayout(ParentResLayout)
+ {
+ VERIFY(IsValidRootIndex(), "Root index must be valid" );
+ VERIFY(IsValidOffset(), "Offset must be valid" );
+ }
+
+ bool IsValidRootIndex()const{return RootIndex != InvalidRootIndex;}
+ bool IsValidOffset() const{return OffsetFromTableStart != InvalidOffset; }
+
+ void CacheSampler(class ITextureViewVk *pTexViewVk, Uint32 ArrayIndex, Vk_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle);
+ };
+
+
+ void CopyStaticResourceDesriptorHandles(const ShaderResourceLayoutVk &SrcLayout);
+
+ // dbgResourceCache is only used for sanity check and as a remainder that the resource cache must be alive
+ // while Layout is alive
+ void BindResources( IResourceMapping* pResourceMapping, Uint32 Flags, const ShaderResourceCacheVk *dbgResourceCache );
+
+ IShaderVariable* GetShaderVariable( const Char* Name );
+
+#ifdef VERIFY_SHADER_BINDINGS
+ void dbgVerifyBindings()const;
+#endif
+
+ IObject& GetOwner(){return m_Owner;}
+
+private:
+ void InitVariablesHashMap();
+
+ Sampler &GetAssignedSampler(const SRV_CBV_UAV &TexSrv);
+
+ const Char* GetShaderName()const;
+
+ // There is no need to use shared ptr as referenced resource cache is either part of the
+ // parent ShaderVkImpl object or ShaderResourceBindingVkImpl object
+ ShaderResourceCacheVk *m_pResourceCache;
+
+ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer;
+ Sampler* m_Samplers = nullptr;
+ Uint16 m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0};
+ Uint16 m_NumSamplers [SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0};
+
+ Uint32 GetSrvCbvUavOffset(SHADER_VARIABLE_TYPE VarType, Uint32 r)const
+ {
+ VERIFY_EXPR( r < m_NumCbvSrvUav[VarType] );
+ static_assert(SHADER_VARIABLE_TYPE_STATIC == 0, "SHADER_VARIABLE_TYPE_STATIC == 0 expected");
+ r += (VarType > SHADER_VARIABLE_TYPE_STATIC) ? m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_STATIC] : 0;
+ static_assert(SHADER_VARIABLE_TYPE_MUTABLE == 1, "SHADER_VARIABLE_TYPE_MUTABLE == 1 expected");
+ r += (VarType > SHADER_VARIABLE_TYPE_MUTABLE) ? m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_MUTABLE] : 0;
+ return r;
+ }
+ SRV_CBV_UAV& GetSrvCbvUav(SHADER_VARIABLE_TYPE VarType, Uint32 r)
+ {
+ VERIFY_EXPR( r < m_NumCbvSrvUav[VarType] );
+ auto* CbvSrvUav = reinterpret_cast<SRV_CBV_UAV*>(m_ResourceBuffer.get());
+ return CbvSrvUav[GetSrvCbvUavOffset(VarType,r)];
+ }
+ const SRV_CBV_UAV& GetSrvCbvUav(SHADER_VARIABLE_TYPE VarType, Uint32 r)const
+ {
+ VERIFY_EXPR( r < m_NumCbvSrvUav[VarType] );
+ auto* CbvSrvUav = reinterpret_cast<SRV_CBV_UAV*>(m_ResourceBuffer.get());
+ return CbvSrvUav[GetSrvCbvUavOffset(VarType,r)];
+ }
+ SRV_CBV_UAV& GetSrvCbvUav(Uint32 r)
+ {
+ VERIFY_EXPR( r < GetTotalSrvCbvUavCount() );
+ auto* CbvSrvUav = reinterpret_cast<SRV_CBV_UAV*>(m_ResourceBuffer.get());
+ return CbvSrvUav[r];
+ }
+
+ Uint32 GetSamplerOffset(SHADER_VARIABLE_TYPE VarType, Uint32 s)const
+ {
+ VERIFY_EXPR( s < m_NumSamplers[VarType] );
+ static_assert(SHADER_VARIABLE_TYPE_STATIC == 0, "SHADER_VARIABLE_TYPE_STATIC == 0 expected");
+ s += (VarType > SHADER_VARIABLE_TYPE_STATIC) ? m_NumSamplers[SHADER_VARIABLE_TYPE_STATIC] : 0;
+ static_assert(SHADER_VARIABLE_TYPE_MUTABLE == 1, "SHADER_VARIABLE_TYPE_MUTABLE == 1 expected");
+ s += (VarType > SHADER_VARIABLE_TYPE_MUTABLE) ? m_NumSamplers[SHADER_VARIABLE_TYPE_MUTABLE] : 0;
+ return s;
+ }
+ Sampler& GetSampler(SHADER_VARIABLE_TYPE VarType, Uint32 s)
+ {
+ VERIFY_EXPR( s < m_NumSamplers[VarType] );
+ return m_Samplers[GetSamplerOffset(VarType,s)];
+ }
+ const Sampler& GetSampler(SHADER_VARIABLE_TYPE VarType, Uint32 s)const
+ {
+ VERIFY_EXPR( s < m_NumSamplers[VarType] );
+ return m_Samplers[GetSamplerOffset(VarType,s)];
+ }
+ Uint32 GetTotalSrvCbvUavCount()const
+ {
+ static_assert(SHADER_VARIABLE_TYPE_NUM_TYPES == 3, "Did you add new variable type?");
+ return m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_STATIC] + m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_MUTABLE] + m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_DYNAMIC];
+ }
+ Uint32 GetTotalSamplerCount()const
+ {
+ static_assert(SHADER_VARIABLE_TYPE_NUM_TYPES == 3, "Did you add new variable type?");
+ return m_NumSamplers[SHADER_VARIABLE_TYPE_STATIC] + m_NumSamplers[SHADER_VARIABLE_TYPE_MUTABLE] + m_NumSamplers[SHADER_VARIABLE_TYPE_DYNAMIC];
+ }
+
+ void AllocateMemory(IMemoryAllocator &Allocator);
+
+#if USE_VARIABLE_HASH_MAP
+ // Hash map to look up shader variables by name.
+ // Note that sizeof(m_VariableHash)==128 (release mode, MS compiler, x64).
+ typedef std::pair<HashMapStringKey, IShaderVariable*> VariableHashElemType;
+ std::unordered_map<HashMapStringKey, IShaderVariable*, std::hash<HashMapStringKey>, std::equal_to<HashMapStringKey>, STDAllocatorRawMem<VariableHashElemType> > m_VariableHash;
+#endif
+
+ CComPtr<IVkDevice> m_pVkDevice;
+ IObject &m_Owner;
+ // We must use shared_ptr to reference ShaderResources instance, because
+ // there may be multiple objects referencing the same set of resources
+ std::shared_ptr<const ShaderResourcesVk> m_pResources;
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourcesVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourcesVk.h
new file mode 100644
index 00000000..cb1be120
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourcesVk.h
@@ -0,0 +1,95 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::ShaderResourcesD3D12 class
+
+// ShaderResourcesD3D12 are created by ShaderD3D12Impl instances. They are then referenced by ShaderResourceLayoutD3D12 objects, which are in turn
+// created by instances of PipelineStatesD3D12Impl and ShaderResourceBindingsD3D12Impl (and ShaderD3D12Impl too)
+//
+// _________________
+// | |
+// | ShaderD3D12Impl |
+// |_________________|
+// |
+// |shared_ptr
+// ________V_____________ _____________________________________________________________________
+// | | unique_ptr | | | | | | |
+// | ShaderResourcesD3D12 |--------------->| CBs | TexSRVs | TexUAVs | BufSRVs | BufUAVs | Samplers |
+// |______________________| |________|___________|___________|___________|___________|____________|
+// A A A A
+// | \ / \
+// |shared_ptr Ref Ref Ref
+// ________|__________________ ________\________________________/_________________________\_________________________________________
+// | | unique_ptr | | | | | | |
+// | ShaderResourceLayoutD3D12 |--------------->| SRV_CBV_UAV[0] | SRV_CBV_UAV[1] | ... | Sampler[0] | Sampler[1] | ... |
+// |___________________________| |___________________|_________________|_______________|__________________|_________________|__________|
+// A | A
+// | |___________________SamplerId________________________|
+// |
+// __________|_____________
+// | |
+// | PipelineStateD3D12Impl |
+// |________________________|
+//
+//
+// One ShaderResources instance can be referenced by multiple objects
+//
+//
+// ________________________ _<m_ShaderResourceLayouts>_ ____<m_pResourceLayouts>___ ________________________________
+// | | | | | | | |
+// | PipelineStateD3D12Impl |-------->| ShaderResourceLayoutD3D12 | ----| ShaderResourceLayoutD3D12 |<-----| ShaderResourceBindingD3D12Impl |
+// |________________________| |___________________________| | |___________________________| |________________________________|
+// | |
+// | shared_ptr |
+// _________________ ___________V__________ | ____<m_pResourceLayouts>___ ________________________________
+// | | shared_ptr | | shared_ptr| | | | |
+// | ShaderD3D12Impl |--------------->| ShaderResourcesD3D12 |<---------------| ShaderResourceLayoutD3D12 |<-----| ShaderResourceBindingD3D12Impl |
+// |_________________| |______________________| | |___________________________| |________________________________|
+// | A |
+// V | |
+// ____<m_StaticResLayout>____ | | ____<m_pResourceLayouts>___ ________________________________
+// | | shared_ptr | | | | | |
+// | ShaderResourceLayoutD3D12 |------------------- ----| ShaderResourceLayoutD3D12 |<-----| ShaderResourceBindingD3D12Impl |
+// |___________________________| |___________________________| |________________________________|
+//
+//
+
+#if 0
+#include "ShaderResources.h"
+
+namespace Diligent
+{
+
+/// Diligent::ShaderResources class
+class ShaderResourcesD3D12 : public ShaderResources
+{
+public:
+ // Loads shader resources from the compiled shader bytecode
+ ShaderResourcesD3D12(ID3DBlob *pShaderBytecode, const ShaderDesc &ShdrDesc);
+};
+
+}
+#endif \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h
new file mode 100644
index 00000000..904ae379
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.h
@@ -0,0 +1,80 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::ShaderVkImpl class
+
+#include "RenderDeviceVk.h"
+#include "ShaderVk.h"
+#include "ShaderBase.h"
+#include "ShaderResourceLayoutVk.h"
+
+#ifdef _DEBUG
+# define VERIFY_SHADER_BINDINGS
+#endif
+
+namespace Diligent
+{
+
+class ResourceMapping;
+class FixedBlockMemoryAllocator;
+
+/// Implementation of the Diligent::IShaderVk interface
+class ShaderVkImpl : public ShaderBase<IShaderVk, IRenderDeviceVk>
+{
+public:
+ typedef ShaderBase<IShaderVk, IRenderDeviceVk> TShaderBase;
+
+ ShaderVkImpl(IReferenceCounters *pRefCounters, class RenderDeviceVkImpl *pRenderDeviceVk, const ShaderCreationAttribs &ShaderCreationAttribs);
+ ~ShaderVkImpl();
+
+ //virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+
+ virtual void BindResources( IResourceMapping* pResourceMapping, Uint32 Flags )override;
+
+ virtual IShaderVariable* GetShaderVariable(const Char* Name)override;
+
+/*
+ ID3DBlob* GetShaderByteCode(){return m_pShaderByteCode;}
+ const std::shared_ptr<const ShaderResourcesVk>& GetShaderResources()const{return m_pShaderResources;}
+ const ShaderResourceLayoutVk& GetConstResLayout()const{return m_StaticResLayout;}
+
+#ifdef VERIFY_SHADER_BINDINGS
+ void DbgVerifyStaticResourceBindings();
+#endif
+
+private:
+
+ DummyShaderVariable m_DummyShaderVar; ///< Dummy shader variable
+
+ // ShaderResources class instance must be referenced through the shared pointer, because
+ // it is referenced by ShaderResourceLayoutVk class instances
+ std::shared_ptr<const ShaderResourcesVk> m_pShaderResources;
+ ShaderResourceLayoutVk m_StaticResLayout;
+ ShaderResourceCacheVk m_ConstResCache;
+*/
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h
new file mode 100644
index 00000000..584cad15
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.h
@@ -0,0 +1,70 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::SwapChainVkImpl class
+
+#include "SwapChainVk.h"
+#include "SwapChainBase.h"
+
+namespace Diligent
+{
+
+class ITextureViewVk;
+class IMemoryAllocator;
+/// Implementation of the Diligent::ISwapChainVk interface
+class SwapChainVkImpl : public SwapChainBase<ISwapChainVk>
+{
+public:
+ typedef SwapChainBase<ISwapChainVk> TSwapChainBase;
+ SwapChainVkImpl(IReferenceCounters *pRefCounters,
+ const SwapChainDesc& SwapChainDesc,
+ class RenderDeviceVkImpl* pRenderDeviceVk,
+ class DeviceContextVkImpl* pDeviceContextVk,
+ void* pNativeWndHandle);
+ ~SwapChainVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface );
+
+ virtual void Present();
+ virtual void Resize( Uint32 NewWidth, Uint32 NewHeight );
+
+/*
+ virtual IDXGISwapChain* GetDXGISwapChain()override final{ return m_pSwapChain; }
+ virtual ITextureViewVk* GetCurrentBackBufferRTV()override final;
+ virtual ITextureViewVk* GetDepthBufferDSV()override final{return m_pDepthBufferDSV;}
+
+private:
+ void InitBuffersAndViews();
+
+ /// DXGI swap chain
+ CComPtr<IDXGISwapChain3> m_pSwapChain;
+
+ std::vector< RefCntAutoPtr<ITextureViewVk>, STDAllocatorRawMem<RefCntAutoPtr<ITextureViewVk>> > m_pBackBufferRTV;
+ RefCntAutoPtr<ITextureViewVk> m_pDepthBufferDSV;
+*/
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h
new file mode 100644
index 00000000..74ec46ae
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h
@@ -0,0 +1,62 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::TextureViewVkImpl class
+
+#include "TextureViewVk.h"
+#include "RenderDeviceVk.h"
+#include "TextureViewBase.h"
+#include "DescriptorHeap.h"
+
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+/// Implementation of the Diligent::ITextureViewVk interface
+class TextureViewVkImpl : public TextureViewBase<ITextureViewVk>
+{
+public:
+ typedef TextureViewBase<ITextureViewVk> TTextureViewBase;
+
+ TextureViewVkImpl( IReferenceCounters *pRefCounters,
+ IRenderDevice *pDevice,
+ const TextureViewDesc& ViewDesc,
+ class ITexture *pTexture,
+ DescriptorHeapAllocation &&HandleAlloc,
+ bool bIsDefaultView);
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+
+ void GenerateMips( IDeviceContext *pContext )override;
+
+ //virtual Vk_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle()override{return m_Descriptor.GetCpuHandle();}
+
+protected:
+ /// Vk view descriptor handle
+ DescriptorHeapAllocation m_Descriptor;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h
new file mode 100644
index 00000000..96065658
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h
@@ -0,0 +1,117 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::TextureVkImpl class
+
+#include "TextureVk.h"
+#include "RenderDeviceVk.h"
+#include "TextureBase.h"
+#include "TextureViewVkImpl.h"
+#include "VulkanResourceBase.h"
+
+
+namespace Diligent
+{
+
+class FixedBlockMemoryAllocator;
+
+/// Base implementation of the Diligent::ITextureVk interface
+class TextureVkImpl : public TextureBase<ITextureVk, TextureViewVkImpl, FixedBlockMemoryAllocator>, public VulkanResourceBase
+{
+public:
+ typedef TextureBase<ITextureVk, TextureViewVkImpl, FixedBlockMemoryAllocator> TTextureBase;
+
+ // Creates a new Vk resource
+ TextureVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &TexViewObjAllocator,
+ class RenderDeviceVkImpl *pDeviceVk,
+ const TextureDesc& TexDesc,
+ const TextureData &InitData = TextureData());
+ // Attaches to an existing Vk resource
+ TextureVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &TexViewObjAllocator,
+ class RenderDeviceVkImpl *pDeviceVk,
+ const TextureDesc& TexDesc,
+ void *pTexture);
+ ~TextureVkImpl();
+
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+
+ virtual void UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box &DstBox, const TextureSubResData &SubresData )override;
+
+ //virtual void CopyData(CTexture *pSrcTexture, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size);
+ virtual void Map( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags, MappedTextureSubresource &MappedData )override;
+ virtual void Unmap( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags )override;
+
+/*
+ virtual IVkResource* GetVkTexture(){ return GetVkResource(); }
+ */
+ virtual void* GetNativeHandle()override final { return nullptr;/*GetVkTexture();*/ }
+/*
+ virtual void SetVkResourceState(Vk_RESOURCE_STATES state)override final{ SetState(state); }
+ */
+
+ void CopyData(IDeviceContext *pContext,
+ 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)
+ {
+ return m_MipUAVs.GetCpuHandle(Mip);
+ }
+
+ Vk_CPU_DESCRIPTOR_HANDLE GetTexArraySRV()
+ {
+ return m_TexArraySRV.GetCpuHandle();
+ }
+
+protected:
+*/
+ void CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )override;
+ //void PrepareVkInitData(const TextureData &InitData, Uint32 NumSubresources, std::vector<Vk_SUBRESOURCE_DATA> &VkInitData);
+/*
+ void CreateSRV( TextureViewDesc &SRVDesc, Vk_CPU_DESCRIPTOR_HANDLE SRVHandle );
+ void CreateRTV( TextureViewDesc &RTVDesc, Vk_CPU_DESCRIPTOR_HANDLE RTVHandle );
+ void CreateDSV( TextureViewDesc &DSVDesc, Vk_CPU_DESCRIPTOR_HANDLE DSVHandle );
+ void CreateUAV( TextureViewDesc &UAVDesc, Vk_CPU_DESCRIPTOR_HANDLE UAVHandle );
+
+ // UAVs for every mip level to facilitate mipmap generation
+ DescriptorHeapAllocation m_MipUAVs;
+ // SRV as texture array (even for a non-array texture) required for mipmap generation
+ DescriptorHeapAllocation m_TexArraySRV;
+
+ friend class RenderDeviceVkImpl;
+*/
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanResourceBase.h b/Graphics/GraphicsEngineVulkan/include/VulkanResourceBase.h
new file mode 100644
index 00000000..82043463
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanResourceBase.h
@@ -0,0 +1,55 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::D3D12ResourceBase class
+
+namespace Diligent
+{
+
+/// Base implementation of a D3D12 resource
+class VulkanResourceBase
+{
+public:
+#if 0
+ VulkanResourceBase() :
+ m_UsageState(D3D12_RESOURCE_STATE_COMMON)/*,
+ m_TransitioningState((D3D12_RESOURCE_STATES)-1)*/
+ {}
+
+ D3D12_RESOURCE_STATES GetState()const{return m_UsageState;}
+ void SetState(D3D12_RESOURCE_STATES UsageState){m_UsageState = UsageState;}
+ bool CheckAllStates(D3D12_RESOURCE_STATES States)const{return (m_UsageState & States) == States;}
+ bool CheckAnyState(D3D12_RESOURCE_STATES States)const{return (m_UsageState & States) != 0;}
+ ID3D12Resource *GetD3D12Resource(){ return m_pd3d12Resource; }
+
+protected:
+ D3D12_RESOURCE_STATES m_UsageState;
+ //D3D12_RESOURCE_STATES m_TransitioningState;
+ CComPtr<ID3D12Resource> m_pd3d12Resource; ///< D3D12 buffer object
+#endif
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h
new file mode 100644
index 00000000..edc9a51d
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.h
@@ -0,0 +1,56 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Type conversion routines
+
+#include "GraphicsTypes.h"
+
+namespace Diligent
+{
+#if 0
+D3D12_COMPARISON_FUNC ComparisonFuncToD3D12ComparisonFunc(COMPARISON_FUNCTION Func);
+D3D12_FILTER FilterTypeToD3D12Filter(FILTER_TYPE MinFilter, FILTER_TYPE MagFilter, FILTER_TYPE MipFilter);
+D3D12_TEXTURE_ADDRESS_MODE TexAddressModeToD3D12AddressMode(TEXTURE_ADDRESS_MODE Mode);
+D3D12_PRIMITIVE_TOPOLOGY TopologyToD3D12Topology(PRIMITIVE_TOPOLOGY Topology);
+
+void DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(const DepthStencilStateDesc &DepthStencilDesc, D3D12_DEPTH_STENCIL_DESC &d3d12DSSDesc);
+void RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(const RasterizerStateDesc &RasterizerDesc, D3D12_RASTERIZER_DESC &d3d11RSDesc);
+void BlendStateDesc_To_D3D12_BLEND_DESC(const BlendStateDesc &BSDesc, D3D12_BLEND_DESC &d3d12BlendDesc);
+
+void LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(const std::vector<LayoutElement, STDAllocatorRawMem<LayoutElement>> &LayoutElements,
+ std::vector<D3D12_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D12_INPUT_ELEMENT_DESC> > &d3d12InputElements);
+
+void TextureViewDesc_to_D3D12_SRV_DESC(const TextureViewDesc& SRVDesc, D3D12_SHADER_RESOURCE_VIEW_DESC &D3D12SRVDesc, Uint32 SampleCount);
+void TextureViewDesc_to_D3D12_RTV_DESC(const TextureViewDesc& RTVDesc, D3D12_RENDER_TARGET_VIEW_DESC &D3D12RTVDesc, Uint32 SampleCount);
+void TextureViewDesc_to_D3D12_DSV_DESC(const TextureViewDesc& DSVDesc, D3D12_DEPTH_STENCIL_VIEW_DESC &D3D12DSVDesc, Uint32 SampleCount);
+void TextureViewDesc_to_D3D12_UAV_DESC(const TextureViewDesc& UAVDesc, D3D12_UNORDERED_ACCESS_VIEW_DESC &D3D12UAVDesc);
+
+void BufferViewDesc_to_D3D12_SRV_DESC(const BufferDesc &BuffDesc, const BufferViewDesc& SRVDesc, D3D12_SHADER_RESOURCE_VIEW_DESC &D3D12SRVDesc);
+void BufferViewDesc_to_D3D12_UAV_DESC(const BufferDesc &BuffDesc, const BufferViewDesc& UAVDesc, D3D12_UNORDERED_ACCESS_VIEW_DESC &D3D12UAVDesc);
+
+D3D12_STATIC_BORDER_COLOR BorderColorToD3D12StaticBorderColor(const Float32 BorderColor[]);
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeDefinitions.h b/Graphics/GraphicsEngineVulkan/include/VulkanTypeDefinitions.h
new file mode 100644
index 00000000..f0ea539d
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeDefinitions.h
@@ -0,0 +1,189 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definitions of D3D12 types
+
+#if 0
+// Filters
+#define D3D_FILTER_MIN_MAG_MIP_POINT D3D12_FILTER_MIN_MAG_MIP_POINT
+#define D3D_FILTER_MIN_MAG_POINT_MIP_LINEAR D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_MIN_POINT_MAG_MIP_LINEAR D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR
+#define D3D_FILTER_MIN_LINEAR_MAG_MIP_POINT D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT
+#define D3D_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_MIN_MAG_LINEAR_MIP_POINT D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_MIN_MAG_MIP_LINEAR D3D12_FILTER_MIN_MAG_MIP_LINEAR
+#define D3D_FILTER_ANISOTROPIC D3D12_FILTER_ANISOTROPIC
+
+#define D3D_FILTER_COMPARISON_MIN_MAG_MIP_POINT D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT
+#define D3D_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR
+#define D3D_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT
+#define D3D_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR
+#define D3D_FILTER_COMPARISON_ANISOTROPIC D3D12_FILTER_COMPARISON_ANISOTROPIC
+
+#define D3D_FILTER_MINIMUM_MIN_MAG_MIP_POINT D3D12_FILTER_MINIMUM_MIN_MAG_MIP_POINT
+#define D3D_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR D3D12_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT D3D12_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR D3D12_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR
+#define D3D_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT
+#define D3D_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT D3D12_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR D3D12_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR
+#define D3D_FILTER_MINIMUM_ANISOTROPIC D3D12_FILTER_MINIMUM_ANISOTROPIC
+
+#define D3D_FILTER_MAXIMUM_MIN_MAG_MIP_POINT D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_POINT
+#define D3D_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR D3D12_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR
+#define D3D_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT
+#define D3D_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR
+#define D3D_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT D3D12_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT
+#define D3D_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR
+#define D3D_FILTER_MAXIMUM_ANISOTROPIC D3D12_FILTER_MAXIMUM_ANISOTROPIC
+
+// Comparison functions
+#define D3D_COMPARISON_FUNC_NEVER D3D12_COMPARISON_FUNC_NEVER
+#define D3D_COMPARISON_FUNC_LESS D3D12_COMPARISON_FUNC_LESS
+#define D3D_COMPARISON_FUNC_EQUAL D3D12_COMPARISON_FUNC_EQUAL
+#define D3D_COMPARISON_FUNC_LESS_EQUAL D3D12_COMPARISON_FUNC_LESS_EQUAL
+#define D3D_COMPARISON_FUNC_GREATER D3D12_COMPARISON_FUNC_GREATER
+#define D3D_COMPARISON_FUNC_NOT_EQUAL D3D12_COMPARISON_FUNC_NOT_EQUAL
+#define D3D_COMPARISON_FUNC_GREATER_EQUAL D3D12_COMPARISON_FUNC_GREATER_EQUAL
+#define D3D_COMPARISON_FUNC_ALWAYS D3D12_COMPARISON_FUNC_ALWAYS
+
+// Stencil operations
+#define D3D_STENCIL_OP_KEEP D3D12_STENCIL_OP_KEEP
+#define D3D_STENCIL_OP_ZERO D3D12_STENCIL_OP_ZERO
+#define D3D_STENCIL_OP_REPLACE D3D12_STENCIL_OP_REPLACE
+#define D3D_STENCIL_OP_INCR_SAT D3D12_STENCIL_OP_INCR_SAT
+#define D3D_STENCIL_OP_DECR_SAT D3D12_STENCIL_OP_DECR_SAT
+#define D3D_STENCIL_OP_INVERT D3D12_STENCIL_OP_INVERT
+#define D3D_STENCIL_OP_INCR D3D12_STENCIL_OP_INCR
+#define D3D_STENCIL_OP_DECR D3D12_STENCIL_OP_DECR
+
+// Depth write masks
+#define D3D_DEPTH_WRITE_MASK_ALL D3D12_DEPTH_WRITE_MASK_ALL
+#define D3D_DEPTH_WRITE_MASK_ZERO D3D12_DEPTH_WRITE_MASK_ZERO
+
+// Cull modes
+#define D3D_CULL_MODE_NONE D3D12_CULL_MODE_NONE
+#define D3D_CULL_MODE_FRONT D3D12_CULL_MODE_FRONT
+#define D3D_CULL_MODE_BACK D3D12_CULL_MODE_BACK
+
+// Fill modes
+#define D3D_FILL_MODE_WIREFRAME D3D12_FILL_MODE_WIREFRAME
+#define D3D_FILL_MODE_SOLID D3D12_FILL_MODE_SOLID
+
+// Blend sources
+#define D3D_BLEND_ZERO D3D12_BLEND_ZERO
+#define D3D_BLEND_ONE D3D12_BLEND_ONE
+#define D3D_BLEND_SRC_COLOR D3D12_BLEND_SRC_COLOR
+#define D3D_BLEND_INV_SRC_COLOR D3D12_BLEND_INV_SRC_COLOR
+#define D3D_BLEND_SRC_ALPHA D3D12_BLEND_SRC_ALPHA
+#define D3D_BLEND_INV_SRC_ALPHA D3D12_BLEND_INV_SRC_ALPHA
+#define D3D_BLEND_DEST_ALPHA D3D12_BLEND_DEST_ALPHA
+#define D3D_BLEND_INV_DEST_ALPHA D3D12_BLEND_INV_DEST_ALPHA
+#define D3D_BLEND_DEST_COLOR D3D12_BLEND_DEST_COLOR
+#define D3D_BLEND_INV_DEST_COLOR D3D12_BLEND_INV_DEST_COLOR
+#define D3D_BLEND_SRC_ALPHA_SAT D3D12_BLEND_SRC_ALPHA_SAT
+#define D3D_BLEND_BLEND_FACTOR D3D12_BLEND_BLEND_FACTOR
+#define D3D_BLEND_INV_BLEND_FACTOR D3D12_BLEND_INV_BLEND_FACTOR
+#define D3D_BLEND_SRC1_COLOR D3D12_BLEND_SRC1_COLOR
+#define D3D_BLEND_INV_SRC1_COLOR D3D12_BLEND_INV_SRC1_COLOR
+#define D3D_BLEND_SRC1_ALPHA D3D12_BLEND_SRC1_ALPHA
+#define D3D_BLEND_INV_SRC1_ALPHA D3D12_BLEND_INV_SRC1_ALPHA
+
+// Blend operations
+#define D3D_BLEND_OP_ADD D3D12_BLEND_OP_ADD
+#define D3D_BLEND_OP_SUBTRACT D3D12_BLEND_OP_SUBTRACT
+#define D3D_BLEND_OP_REV_SUBTRACT D3D12_BLEND_OP_REV_SUBTRACT
+#define D3D_BLEND_OP_MIN D3D12_BLEND_OP_MIN
+#define D3D_BLEND_OP_MAX D3D12_BLEND_OP_MAX
+
+// Color masks
+#define D3D_COLOR_WRITE_ENABLE_RED D3D12_COLOR_WRITE_ENABLE_RED
+#define D3D_COLOR_WRITE_ENABLE_GREEN D3D12_COLOR_WRITE_ENABLE_GREEN
+#define D3D_COLOR_WRITE_ENABLE_BLUE D3D12_COLOR_WRITE_ENABLE_BLUE
+#define D3D_COLOR_WRITE_ENABLE_ALPHA D3D12_COLOR_WRITE_ENABLE_ALPHA
+
+// Input classification
+#define D3D_INPUT_CLASSIFICATION_PER_VERTEX_DATA D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
+#define D3D_INPUT_CLASSIFICATION_PER_INSTANCE_DATA D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA
+
+// Texture address modes
+#define D3D_TEXTURE_ADDRESS_WRAP D3D12_TEXTURE_ADDRESS_MODE_WRAP
+#define D3D_TEXTURE_ADDRESS_MIRROR D3D12_TEXTURE_ADDRESS_MODE_MIRROR
+#define D3D_TEXTURE_ADDRESS_CLAMP D3D12_TEXTURE_ADDRESS_MODE_CLAMP
+#define D3D_TEXTURE_ADDRESS_BORDER D3D12_TEXTURE_ADDRESS_MODE_BORDER
+#define D3D_TEXTURE_ADDRESS_MIRROR_ONCE D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE
+
+// SRV Dimensions
+#define D3D_SRV_DIMENSION_UNKNOWN D3D12_SRV_DIMENSION_UNKNOWN
+#define D3D_SRV_DIMENSION_BUFFER D3D12_SRV_DIMENSION_BUFFER
+#define D3D_SRV_DIMENSION_TEXTURE1D D3D12_SRV_DIMENSION_TEXTURE1D
+#define D3D_SRV_DIMENSION_TEXTURE1DARRAY D3D12_SRV_DIMENSION_TEXTURE1DARRAY
+#define D3D_SRV_DIMENSION_TEXTURE2D D3D12_SRV_DIMENSION_TEXTURE2D
+#define D3D_SRV_DIMENSION_TEXTURE2DARRAY D3D12_SRV_DIMENSION_TEXTURE2DARRAY
+#define D3D_SRV_DIMENSION_TEXTURE2DMS D3D12_SRV_DIMENSION_TEXTURE2DMS
+#define D3D_SRV_DIMENSION_TEXTURE2DMSARRAY D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY
+#define D3D_SRV_DIMENSION_TEXTURE3D D3D12_SRV_DIMENSION_TEXTURE3D
+#define D3D_SRV_DIMENSION_TEXTURECUBE D3D12_SRV_DIMENSION_TEXTURECUBE
+#define D3D_SRV_DIMENSION_TEXTURECUBEARRAY D3D12_SRV_DIMENSION_TEXTURECUBEARRAY
+
+// RTV Dimensions
+#define D3D_RTV_DIMENSION_UNKNOWN D3D12_RTV_DIMENSION_UNKNOWN
+#define D3D_RTV_DIMENSION_BUFFER D3D12_RTV_DIMENSION_BUFFER
+#define D3D_RTV_DIMENSION_TEXTURE1D D3D12_RTV_DIMENSION_TEXTURE1D
+#define D3D_RTV_DIMENSION_TEXTURE1DARRAY D3D12_RTV_DIMENSION_TEXTURE1DARRAY
+#define D3D_RTV_DIMENSION_TEXTURE2D D3D12_RTV_DIMENSION_TEXTURE2D
+#define D3D_RTV_DIMENSION_TEXTURE2DARRAY D3D12_RTV_DIMENSION_TEXTURE2DARRAY
+#define D3D_RTV_DIMENSION_TEXTURE2DMS D3D12_RTV_DIMENSION_TEXTURE2DMS
+#define D3D_RTV_DIMENSION_TEXTURE2DMSARRAY D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY
+#define D3D_RTV_DIMENSION_TEXTURE3D D3D12_RTV_DIMENSION_TEXTURE3D
+
+
+// DSV Dimensions
+#define D3D_DSV_DIMENSION_UNKNOWN D3D12_DSV_DIMENSION_UNKNOWN
+#define D3D_DSV_DIMENSION_TEXTURE1D D3D12_DSV_DIMENSION_TEXTURE1D
+#define D3D_DSV_DIMENSION_TEXTURE1DARRAY D3D12_DSV_DIMENSION_TEXTURE1DARRAY
+#define D3D_DSV_DIMENSION_TEXTURE2D D3D12_DSV_DIMENSION_TEXTURE2D
+#define D3D_DSV_DIMENSION_TEXTURE2DARRAY D3D12_DSV_DIMENSION_TEXTURE2DARRAY
+#define D3D_DSV_DIMENSION_TEXTURE2DMS D3D12_DSV_DIMENSION_TEXTURE2DMS
+#define D3D_DSV_DIMENSION_TEXTURE2DMSARRAY D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY
+
+// UAV Dimensions
+#define D3D_UAV_DIMENSION_UNKNOWN D3D12_UAV_DIMENSION_UNKNOWN
+#define D3D_UAV_DIMENSION_BUFFER D3D12_UAV_DIMENSION_BUFFER
+#define D3D_UAV_DIMENSION_TEXTURE1D D3D12_UAV_DIMENSION_TEXTURE1D
+#define D3D_UAV_DIMENSION_TEXTURE1DARRAY D3D12_UAV_DIMENSION_TEXTURE1DARRAY
+#define D3D_UAV_DIMENSION_TEXTURE2D D3D12_UAV_DIMENSION_TEXTURE2D
+#define D3D_UAV_DIMENSION_TEXTURE2DARRAY D3D12_UAV_DIMENSION_TEXTURE2DARRAY
+#define D3D_UAV_DIMENSION_TEXTURE3D D3D12_UAV_DIMENSION_TEXTURE3D
+#endif \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtils.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtils.h
new file mode 100644
index 00000000..e7d509be
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtils.h
@@ -0,0 +1,30 @@
+/* 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 "BasicTypes.h"
+namespace Diligent
+{
+ //const Char* GetD3D12DescriptorHeapTypeLiteralName(D3D12_DESCRIPTOR_HEAP_TYPE Type);
+}
diff --git a/Graphics/GraphicsEngineVulkan/include/pch.h b/Graphics/GraphicsEngineVulkan/include/pch.h
new file mode 100644
index 00000000..b4973316
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/pch.h
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#define NOMINMAX
+
+
+#include <vector>
+#include <exception>
+#include <algorithm>
+//#include <vulkan.h>
+
+#include "PlatformDefinitions.h"
+#include "Errors.h"
+#include "RefCntAutoPtr.h"
+#include "DebugUtilities.h"
+//#include "D3DErrors.h"
+#include "RenderDeviceBase.h"
+#include "ValidatedCast.h"
+#include <atlcomcli.h> \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/interface/BufferViewVk.h b/Graphics/GraphicsEngineVulkan/interface/BufferViewVk.h
new file mode 100644
index 00000000..af95a79c
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/BufferViewVk.h
@@ -0,0 +1,47 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IBufferViewVk interface
+
+#include "../../GraphicsEngine/interface/BufferView.h"
+
+namespace Diligent
+{
+
+// {CB67024A-1E23-4202-A49A-07B6BCEABC06}
+static constexpr INTERFACE_ID IID_BufferViewVk =
+{ 0xcb67024a, 0x1e23, 0x4202,{ 0xa4, 0x9a, 0x7, 0xb6, 0xbc, 0xea, 0xbc, 0x6 } };
+
+/// Interface to the buffer view object implemented in Vulkan
+class IBufferViewVk : public IBufferView
+{
+public:
+
+ /// Returns CPU descriptor handle of the buffer view.
+ //virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/BufferVk.h b/Graphics/GraphicsEngineVulkan/interface/BufferVk.h
new file mode 100644
index 00000000..0b89eda1
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/BufferVk.h
@@ -0,0 +1,61 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IBufferVk interface
+
+#include "../../GraphicsEngine/interface/Buffer.h"
+
+namespace Diligent
+{
+
+// {12D8EC02-96F4-431E-9695-C5F572CC7587}
+static constexpr INTERFACE_ID IID_BufferVk =
+{ 0x12d8ec02, 0x96f4, 0x431e,{ 0x96, 0x95, 0xc5, 0xf5, 0x72, 0xcc, 0x75, 0x87 } };
+
+
+/// Interface to the buffer object implemented in Vulkan
+class IBufferVk : public IBuffer
+{
+public:
+
+ /// Returns a pointer to the ID3D12Resource interface of the internal Direct3D12 object.
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ /// \param [in] DataStartByteOffset - Offset from the beginning of the buffer
+ /// to the start of the data. This parameter
+ /// is required for dynamic buffers, which are
+ /// suballocated in a dynamic upload heap
+ /// \param [in] ContextId - Id of the context within which address of the buffer is requested.
+ //virtual ID3D12Resource* GetD3D12Buffer(size_t &DataStartByteOffset, Uint32 ContextId) = 0;
+
+ /// Sets the buffer usage state
+
+ /// \param [in] state - D3D12 resource state to be set for this buffer
+ //virtual void SetD3D12ResourceState(D3D12_RESOURCE_STATES state) = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h b/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h
new file mode 100644
index 00000000..d0900687
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/CommandQueueVk.h
@@ -0,0 +1,60 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ICommandQueueVk interface
+
+#include "../../../Primitives/interface/Object.h"
+
+namespace Diligent
+{
+
+// {9FBF582F-3069-41B9-AC05-344D5AF5CE8C}
+static constexpr INTERFACE_ID IID_CommandQueueVk =
+{ 0x9fbf582f, 0x3069, 0x41b9,{ 0xac, 0x5, 0x34, 0x4d, 0x5a, 0xf5, 0xce, 0x8c } };
+
+/// Command queue interface
+class ICommandQueueVk : public Diligent::IObject
+{
+public:
+ /// Returns the fence value that will be signaled next time
+ //virtual UINT64 GetNextFenceValue() = 0;
+
+ /// Executes a given command list
+
+ /// \return Fence value associated with the executed command list
+ //virtual UINT64 ExecuteCommandList(ID3D12GraphicsCommandList* commandList) = 0;
+
+ /// Returns D3D12 command queue. May return null if queue is anavailable
+ //virtual ID3D12CommandQueue* GetD3D12CommandQueue() = 0;
+
+ /// Returns value of the last completed fence
+ //virtual Uint64 GetCompletedFenceValue() = 0;
+
+ /// Blocks execution until all pending GPU commands are complete
+ //virtual void IdleGPU() = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h b/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h
new file mode 100644
index 00000000..9a283151
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/DeviceContextVk.h
@@ -0,0 +1,56 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IDeviceContextVk interface
+
+#include "../../GraphicsEngine/interface/DeviceContext.h"
+
+namespace Diligent
+{
+
+// {72AEB1BA-C6AD-42EC-8811-7ED9C72176BB}
+static constexpr INTERFACE_ID IID_DeviceContextVk =
+{ 0x72aeb1ba, 0xc6ad, 0x42ec,{ 0x88, 0x11, 0x7e, 0xd9, 0xc7, 0x21, 0x76, 0xbb } };
+
+/// Interface to the device context object implemented in Vulkan
+class IDeviceContextVk : public IDeviceContext
+{
+public:
+
+ /// Transitions internal D3D12 texture object to a specified state
+
+ /// \param [in] pTexture - texture to transition
+ /// \param [in] State - D3D12 resource state this texture to transition to
+ //virtual void TransitionTextureState(ITexture *pTexture, D3D12_RESOURCE_STATES State) = 0;
+
+ /// Transitions internal D3D12 buffer object to a specified state
+
+ /// \param [in] pBuffer - Buffer to transition
+ /// \param [in] State - D3D12 resource state this buffer to transition to
+ //virtual void TransitionBufferState(IBuffer *pBuffer, D3D12_RESOURCE_STATES State) = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h b/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h
new file mode 100644
index 00000000..828593d7
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h
@@ -0,0 +1,57 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IPipeplineStateVk interface
+
+#include "../../GraphicsEngine/interface/PipelineState.h"
+
+namespace Diligent
+{
+
+// {2FEA0868-0932-412A-9F0A-7CEA7E61B5E0}
+static constexpr INTERFACE_ID IID_PipelineStateVk =
+{ 0x2fea0868, 0x932, 0x412a,{ 0x9f, 0xa, 0x7c, 0xea, 0x7e, 0x61, 0xb5, 0xe0 } };
+
+
+/// Interface to the blend state object implemented in Vulkan
+class IPipelineStateVk : public IPipelineState
+{
+public:
+
+ /// Returns ID3D12PipelineState interface of the internal D3D12 pipeline state object object.
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual ID3D12PipelineState* GetD3D12PipelineState()const = 0;
+
+ /// Returns a pointer to the root signature object associated with this pipeline state.
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual ID3D12RootSignature* GetD3D12RootSignature()const = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceFactoryVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceFactoryVk.h
new file mode 100644
index 00000000..264bf54d
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceFactoryVk.h
@@ -0,0 +1,122 @@
+/* Copyright 2015-2018 Egor Yusov
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+*
+* In no event and under no legal theory, whether in tort (including negligence),
+* contract, or otherwise, unless required by applicable law (such as deliberate
+* and grossly negligent acts) or agreed to in writing, shall any Contributor be
+* liable for any damages, including any direct, indirect, special, incidental,
+* or consequential damages of any character arising as a result of this License or
+* out of the use or inability to use the software (including but not limited to damages
+* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+* all other commercial damages or losses), even if such Contributor has been advised
+* of the possibility of such damages.
+*/
+
+#pragma once
+
+/// \file
+/// Declaration of functions that initialize Direct3D12-based engine implementation
+
+#include <sstream>
+
+#include "../../GraphicsEngine/interface/RenderDevice.h"
+#include "../../GraphicsEngine/interface/DeviceContext.h"
+#include "../../GraphicsEngine/interface/SwapChain.h"
+
+#if PLATFORM_UNIVERSAL_WINDOWS && defined(ENGINE_DLL)
+# include "../../../Common/interface/StringTools.h"
+#endif
+
+namespace Diligent
+{
+
+ class IEngineFactoryVk
+ {
+ public:
+ virtual void CreateDeviceAndContextsVk(const EngineVkAttribs& CreationAttribs,
+ IRenderDevice **ppDevice,
+ IDeviceContext **ppContexts,
+ Uint32 NumDeferredContexts) = 0;
+
+ //virtual void AttachToVulkanDevice(void *pVkNativeDevice,
+ // class ICommandQueueVk *pCommandQueue,
+ // const EngineVkAttribs& EngineAttribs,
+ // IRenderDevice **ppDevice,
+ // IDeviceContext **ppContexts,
+ // Uint32 NumDeferredContexts) = 0;
+
+ virtual void CreateSwapChainVk(IRenderDevice *pDevice,
+ IDeviceContext *pImmediateContext,
+ const SwapChainDesc& SwapChainDesc,
+ void* pNativeWndHandle,
+ ISwapChain **ppSwapChain) = 0;
+
+ };
+
+
+#if ENGINE_DLL
+
+ typedef IEngineFactoryVk* (*GetEngineFactoryVkType)();
+
+ static bool LoadGraphicsEngineVk(GetEngineFactoryVkType &GetFactoryFunc)
+ {
+ GetFactoryFunc = nullptr;
+ std::string LibName = "GraphicsEngineVk_";
+
+#if _WIN64
+ LibName += "64";
+#else
+ LibName += "32";
+#endif
+
+#ifdef _DEBUG
+ LibName += "d";
+#else
+ LibName += "r";
+#endif
+
+ LibName += ".dll";
+#if PLATFORM_WIN32
+ auto hModule = LoadLibraryA(LibName.c_str());
+#elif PLATFORM_UNIVERSAL_WINDOWS
+ auto hModule = LoadPackagedLibrary(WidenString(LibName).c_str(), 0);
+#else
+# error Unexpected platform
+#endif
+
+ if (hModule == NULL)
+ {
+ std::stringstream ss;
+ ss << "Failed to load " << LibName << " library.\n";
+ OutputDebugStringA(ss.str().c_str());
+ return false;
+ }
+
+ GetFactoryFunc = reinterpret_cast<GetEngineFactoryVkType>(GetProcAddress(hModule, "GetEngineFactoryVk"));
+ if (GetFactoryFunc == NULL)
+ {
+ std::stringstream ss;
+ ss << "Failed to load GetEngineFactoryVk() from " << LibName << " library.\n";
+ OutputDebugStringA(ss.str().c_str());
+ FreeLibrary(hModule);
+ return false;
+ }
+
+ return true;
+ }
+#else
+
+ IEngineFactoryVk* GetEngineFactoryVk();
+
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
new file mode 100644
index 00000000..a5a03328
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
@@ -0,0 +1,82 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IRenderDeviceVk interface
+
+#include "../../GraphicsEngine/interface/RenderDevice.h"
+
+namespace Diligent
+{
+
+// {AB8CF3A6-D959-41C1-AE00-A58AE9820E6A}
+static constexpr INTERFACE_ID IID_RenderDeviceVk =
+{ 0xab8cf3a6, 0xd959, 0x41c1,{ 0xae, 0x0, 0xa5, 0x8a, 0xe9, 0x82, 0xe, 0x6a } };
+
+/// Interface to the render device object implemented in Vulkan
+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 the fence value that will be signaled by the GPU command queue next
+ //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;
+
+ /// 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;
+
+ /// Creates a texture object from native d3d12 resource
+
+ /// \param [in] pd3d12Texture - pointer to the native D3D12 texture
+ /// \param [out] ppTexture - Address of the memory location where the pointer to the
+ /// texture interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one refernce.
+ //virtual void CreateTextureFromD3DResource(ID3D12Resource *pd3d12Texture, ITexture **ppTexture) = 0;
+
+ /// Creates a buffer object from native d3d12 resoruce
+
+ /// \param [in] pd3d12Buffer - Pointer to the native d3d12 buffer resource
+ /// \param [in] BuffDesc - Buffer description. The system can recover buffer size, but
+ /// the rest of the fields need to be populated by the client
+ /// as they cannot be recovered from d3d12 resource description
+ /// \param [out] ppBuffer - Address of the memory location where the pointer to the
+ /// buffer interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ //virtual void CreateBufferFromD3DResource(ID3D12Resource *pd3d12Buffer, const BufferDesc& BuffDesc, IBuffer **ppBuffer) = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/SamplerVk.h b/Graphics/GraphicsEngineVulkan/interface/SamplerVk.h
new file mode 100644
index 00000000..5f122327
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/SamplerVk.h
@@ -0,0 +1,50 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ISamplerVk interface
+
+#include "../../GraphicsEngine/interface/Sampler.h"
+
+namespace Diligent
+{
+
+// {87C21E88-8A9F-4AD2-9A1E-D5EC140415EA}
+static constexpr INTERFACE_ID IID_SamplerVk =
+{ 0x87c21e88, 0x8a9f, 0x4ad2,{ 0x9a, 0x1e, 0xd5, 0xec, 0x14, 0x4, 0x15, 0xea } };
+
+/// Interface to the sampler object implemented in Vulkan
+class ISamplerVk : public ISampler
+{
+public:
+
+ /// Returns a CPU descriptor handle of the D3D12 sampler object
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/ShaderResourceBindingVk.h b/Graphics/GraphicsEngineVulkan/interface/ShaderResourceBindingVk.h
new file mode 100644
index 00000000..10daa5be
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/ShaderResourceBindingVk.h
@@ -0,0 +1,45 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IShaderResourceBindingVk interface and related data structures
+
+#include "../../GraphicsEngine/interface/ShaderResourceBinding.h"
+
+namespace Diligent
+{
+
+// {1E8C82DC-5B3A-47D5-8AE9-197CAE8DB71F}
+static constexpr INTERFACE_ID IID_ShaderResourceBindingVk =
+{ 0x1e8c82dc, 0x5b3a, 0x47d5,{ 0x8a, 0xe9, 0x19, 0x7c, 0xae, 0x8d, 0xb7, 0x1f } };
+
+/// Shader resource binding interface
+class IShaderResourceBindingVk : public IShaderResourceBinding
+{
+public:
+
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/ShaderVk.h b/Graphics/GraphicsEngineVulkan/interface/ShaderVk.h
new file mode 100644
index 00000000..e9fc51de
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/ShaderVk.h
@@ -0,0 +1,50 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IShaderVk interface
+
+#include "../../GraphicsEngine/interface/Shader.h"
+
+namespace Diligent
+{
+
+// {8B0C91B4-B1D8-4E03-9250-A70E131A59FA}
+static constexpr INTERFACE_ID IID_ShaderVk =
+{ 0x8b0c91b4, 0xb1d8, 0x4e03,{ 0x92, 0x50, 0xa7, 0xe, 0x13, 0x1a, 0x59, 0xfa } };
+
+/// Interface to the shader object implemented in Vulkan
+class IShaderVk : public IShader
+{
+public:
+
+ /// Returns a pointer to the ID3D12DeviceChild interface of the internal Direct3D12 object.
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual ID3D12DeviceChild* GetD3D12Shader() = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h b/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h
new file mode 100644
index 00000000..ce9c86e4
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/SwapChainVk.h
@@ -0,0 +1,65 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ISwapChainVk interface
+
+//#include <dxgi1_4.h>
+
+#include "../../GraphicsEngine/interface/SwapChain.h"
+#include "TextureViewVk.h"
+
+namespace Diligent
+{
+
+// {22A39881-5EC5-4A9C-8395-90215F04A5CC}
+static constexpr INTERFACE_ID IID_SwapChainVk =
+{ 0x22a39881, 0x5ec5, 0x4a9c,{ 0x83, 0x95, 0x90, 0x21, 0x5f, 0x4, 0xa5, 0xcc } };
+
+/// Interface to the swap chain object implemented in Vulkan
+class ISwapChainVk : public ISwapChain
+{
+public:
+
+ /// Returns a pointer to the IDXGISwapChain interface of the internal DXGI object.
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual IDXGISwapChain *GetDXGISwapChain() = 0;
+
+ /// Returns a pointer to the render target view of the current back buffer in the swap chain
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual ITextureViewD3D12* GetCurrentBackBufferRTV() = 0;
+
+ /// Returns a pointer to the depth-stencil view of the depth buffer
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual ITextureViewD3D12* GetDepthBufferDSV() = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/TextureViewVk.h b/Graphics/GraphicsEngineVulkan/interface/TextureViewVk.h
new file mode 100644
index 00000000..657b31c7
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/TextureViewVk.h
@@ -0,0 +1,47 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ITextureViewVk interface
+
+#include "../../GraphicsEngine/interface/TextureView.h"
+
+namespace Diligent
+{
+
+// {B02AA468-3328-46F3-9777-55E97BF6C86E}
+static constexpr INTERFACE_ID IID_TextureViewVk =
+{ 0xb02aa468, 0x3328, 0x46f3,{ 0x97, 0x77, 0x55, 0xe9, 0x7b, 0xf6, 0xc8, 0x6e } };
+
+/// Interface to the texture view object implemented in Vulkan
+class ITextureViewVk : public ITextureView
+{
+public:
+
+ /// Returns CPU descriptor handle of the texture view.
+ //virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/interface/TextureVk.h b/Graphics/GraphicsEngineVulkan/interface/TextureVk.h
new file mode 100644
index 00000000..b2ffd803
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/TextureVk.h
@@ -0,0 +1,56 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ITextureVk interface
+
+#include "../../GraphicsEngine/interface/Texture.h"
+
+namespace Diligent
+{
+
+// {3BB9155F-22C5-4365-927E-8C4049F9B949}
+static constexpr INTERFACE_ID IID_TextureVk =
+{ 0x3bb9155f, 0x22c5, 0x4365,{ 0x92, 0x7e, 0x8c, 0x40, 0x49, 0xf9, 0xb9, 0x49 } };
+
+
+/// Interface to the texture object implemented in Vulkan
+class ITextureVk : public ITexture
+{
+public:
+
+ /// Returns a pointer to the ID3D12Resource interface of the internal Direct3D12 object.
+
+ /// The method does *NOT* call AddRef() on the returned interface,
+ /// so Release() must not be called.
+ //virtual ID3D12Resource* GetD3D12Texture() = 0;
+
+ /// Sets the texture usage state
+
+ /// \param [in] state - D3D12 resource state to be set for this texture
+ //virtual void SetD3D12ResourceState(D3D12_RESOURCE_STATES state) = 0;
+};
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/readme.md b/Graphics/GraphicsEngineVulkan/readme.md
new file mode 100644
index 00000000..877e3425
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/readme.md
@@ -0,0 +1,11 @@
+
+# GraphicsEngineVulkan
+
+Implementation of Diligent Engine API using Vulkan
+
+
+
+
+**Copyright 2015-2018 Egor Yusov**
+
+[diligentgraphics.com](http://diligentgraphics.com)
diff --git a/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp
new file mode 100644
index 00000000..d8250600
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp
@@ -0,0 +1,43 @@
+/* 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 "BufferViewVkImpl.h"
+
+namespace Diligent
+{
+
+BufferViewVkImpl::BufferViewVkImpl( IReferenceCounters *pRefCounters,
+ IRenderDevice *pDevice,
+ const BufferViewDesc& ViewDesc,
+ IBuffer *pBuffer,
+ DescriptorHeapAllocation &&HandleAlloc,
+ bool bIsDefaultView ) :
+ TBufferViewBase( pRefCounters, pDevice, ViewDesc, pBuffer, bIsDefaultView ),
+ m_DescriptorHandle( std::move(HandleAlloc) )
+{
+}
+
+IMPLEMENT_QUERY_INTERFACE( BufferViewVkImpl, IID_BufferViewVk, TBufferViewBase )
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
new file mode 100644
index 00000000..dde4f8de
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
@@ -0,0 +1,493 @@
+/* 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 "BufferVkImpl.h"
+#include "RenderDeviceVkImpl.h"
+#include "DeviceContextVkImpl.h"
+//#include "VkTypeConversions.h"
+#include "BufferViewVkImpl.h"
+#include "GraphicsAccessories.h"
+//#include "DXGITypeConversions.h"
+#include "EngineMemory.h"
+#include "StringTools.h"
+
+namespace Diligent
+{
+
+BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &BuffViewObjMemAllocator,
+ RenderDeviceVkImpl *pRenderDeviceVk,
+ const BufferDesc& BuffDesc,
+ const BufferData &BuffData /*= BufferData()*/) :
+ TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BuffDesc, false)/*,
+#ifdef _DEBUG
+ m_DbgMapType(1 + pRenderDeviceVk->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>")),
+#endif
+ m_DynamicData(BuffDesc.Usage == USAGE_DYNAMIC ? (1 + pRenderDeviceVk->GetNumDeferredContexts()) : 0, DynamicAllocation(), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>"))
+ */
+{
+#if 0
+#define LOG_BUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Buffer \"", BuffDesc.Name ? BuffDesc.Name : "", "\": ", ##__VA_ARGS__);
+
+ if( m_Desc.Usage == USAGE_STATIC && BuffData.pData == nullptr )
+ LOG_BUFFER_ERROR_AND_THROW("Static buffer must be initialized with data at creation time")
+
+ if( m_Desc.Usage == USAGE_DYNAMIC && BuffData.pData != nullptr )
+ LOG_BUFFER_ERROR_AND_THROW("Dynamic buffer must be initialized via Map()")
+
+ Uint32 AlignmentMask = 1;
+ if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
+ AlignmentMask = 255;
+
+ if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
+ {
+ if (m_Desc.CPUAccessFlags != CPU_ACCESS_WRITE && m_Desc.CPUAccessFlags != CPU_ACCESS_READ)
+ LOG_BUFFER_ERROR_AND_THROW("Exactly one of the CPU_ACCESS_WRITE or CPU_ACCESS_READ flags must be specified for a cpu-accessible buffer")
+
+ if (m_Desc.CPUAccessFlags == CPU_ACCESS_WRITE)
+ {
+ if(BuffData.pData != nullptr )
+ LOG_BUFFER_ERROR_AND_THROW("CPU-writable staging buffers must be updated via map")
+
+ AlignmentMask = Vk_TEXTURE_DATA_PITCH_ALIGNMENT - 1;
+ }
+ }
+
+ if(AlignmentMask != 1)
+ m_Desc.uiSizeInBytes = (m_Desc.uiSizeInBytes + AlignmentMask) & (~AlignmentMask);
+
+ if(m_Desc.Usage == USAGE_DYNAMIC && (m_Desc.BindFlags & (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) == 0)
+ {
+ // Dynamic constant/vertex/index buffers are suballocated in the upload heap when Map() is called.
+ // Dynamic buffers with SRV or UAV flags need to be allocated in GPU-only memory
+ // Dynamic upload heap buffer is always in Vk_RESOURCE_STATE_GENERIC_READ state
+
+ m_UsageState = Vk_RESOURCE_STATE_GENERIC_READ;
+ VERIFY_EXPR(m_DynamicData.size() == 1 + pRenderDeviceVk->GetNumDeferredContexts());
+ }
+ else
+ {
+ Vk_RESOURCE_DESC VkBuffDesc = {};
+ VkBuffDesc.Dimension = Vk_RESOURCE_DIMENSION_BUFFER;
+ VkBuffDesc.Alignment = 0;
+ VkBuffDesc.Width = m_Desc.uiSizeInBytes;
+ VkBuffDesc.Height = 1;
+ VkBuffDesc.DepthOrArraySize = 1;
+ VkBuffDesc.MipLevels = 1;
+ VkBuffDesc.Format = DXGI_FORMAT_UNKNOWN;
+ VkBuffDesc.SampleDesc.Count = 1;
+ VkBuffDesc.SampleDesc.Quality = 0;
+ // Layout must be Vk_TEXTURE_LAYOUT_ROW_MAJOR, as buffer memory layouts are
+ // understood by applications and row-major texture data is commonly marshaled through buffers.
+ VkBuffDesc.Layout = Vk_TEXTURE_LAYOUT_ROW_MAJOR;
+ VkBuffDesc.Flags = Vk_RESOURCE_FLAG_NONE;
+ if( m_Desc.BindFlags & BIND_UNORDERED_ACCESS )
+ VkBuffDesc.Flags |= Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+ if( !(m_Desc.BindFlags & BIND_SHADER_RESOURCE) )
+ VkBuffDesc.Flags |= Vk_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
+
+ auto *pVkDevice = pRenderDeviceVk->GetVkDevice();
+
+ Vk_HEAP_PROPERTIES HeapProps;
+ if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
+ HeapProps.Type = m_Desc.CPUAccessFlags == CPU_ACCESS_READ ? Vk_HEAP_TYPE_READBACK : Vk_HEAP_TYPE_UPLOAD;
+ else
+ HeapProps.Type = Vk_HEAP_TYPE_DEFAULT;
+
+ if(HeapProps.Type == Vk_HEAP_TYPE_READBACK)
+ m_UsageState = Vk_RESOURCE_STATE_COPY_DEST;
+ else if(HeapProps.Type == Vk_HEAP_TYPE_UPLOAD)
+ m_UsageState = Vk_RESOURCE_STATE_GENERIC_READ;
+ HeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN;
+ HeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN;
+ HeapProps.CreationNodeMask = 1;
+ HeapProps.VisibleNodeMask = 1;
+
+ bool bInitializeBuffer = (BuffData.pData != nullptr && BuffData.DataSize > 0);
+ if(bInitializeBuffer)
+ m_UsageState = Vk_RESOURCE_STATE_COPY_DEST;
+
+ auto hr = pVkDevice->CreateCommittedResource( &HeapProps, Vk_HEAP_FLAG_NONE,
+ &VkBuffDesc, m_UsageState, nullptr, __uuidof(m_pVkResource), reinterpret_cast<void**>(static_cast<IVkResource**>(&m_pVkResource)) );
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create Vk buffer");
+
+ if( *m_Desc.Name != 0)
+ m_pVkResource->SetName(WidenString(m_Desc.Name).c_str());
+
+ if( bInitializeBuffer )
+ {
+ Vk_HEAP_PROPERTIES UploadHeapProps;
+ UploadHeapProps.Type = Vk_HEAP_TYPE_UPLOAD;
+ UploadHeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN;
+ UploadHeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN;
+ UploadHeapProps.CreationNodeMask = 1;
+ UploadHeapProps.VisibleNodeMask = 1;
+
+ VkBuffDesc.Flags = Vk_RESOURCE_FLAG_NONE;
+ CComPtr<IVkResource> UploadBuffer;
+ hr = pVkDevice->CreateCommittedResource( &UploadHeapProps, Vk_HEAP_FLAG_NONE,
+ &VkBuffDesc, Vk_RESOURCE_STATE_GENERIC_READ, nullptr, __uuidof(UploadBuffer),
+ reinterpret_cast<void**>(static_cast<IVkResource**>(&UploadBuffer)) );
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create uload buffer");
+
+ void* DestAddress = nullptr;
+ hr = UploadBuffer->Map(0, nullptr, &DestAddress);
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to map uload buffer");
+ memcpy(DestAddress, BuffData.pData, BuffData.DataSize);
+ UploadBuffer->Unmap(0, nullptr);
+
+ 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);
+ // 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);
+
+ // Command list fence should only be signaled when submitting cmd list
+ // from the immediate context, otherwise the basic requirement will be violated
+ // as in the scenario below
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+ //
+ // Signaled Fence | Immediate Context | InitContext |
+ // | | |
+ // N | Draw(ResourceX) | |
+ // | Release(ResourceX) | |
+ // | - (ResourceX, N) -> Release Queue | |
+ // | | CopyResource() |
+ // N+1 | | CloseAndExecuteCommandContext() |
+ // | | |
+ // N+2 | CloseAndExecuteCommandContext() | |
+ // | - Cmd list is submitted with number | |
+ // | N+1, but resource it references | |
+ // | was added to the delete queue | |
+ // | with value N | |
+ pRenderDeviceVk->CloseAndExecuteCommandContext(pInitContext, false);
+
+ // 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);
+ }
+
+ if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
+ {
+ m_CBVDescriptorAllocation = pRenderDeviceVk->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ CreateCBV(m_CBVDescriptorAllocation.GetCpuHandle());
+ }
+ }
+#endif
+}
+
+
+static BufferDesc BufferDescFromVkResource(BufferDesc BuffDesc, void *pVkBuffer)
+{
+#if 0
+ VERIFY(BuffDesc.Usage != USAGE_DYNAMIC, "Dynamic buffers cannot be attached to native Vk resource");
+
+ auto VkBuffDesc = pVkBuffer->GetDesc();
+ VERIFY(VkBuffDesc.Dimension == Vk_RESOURCE_DIMENSION_BUFFER, "Vk resource is not a buffer");
+
+ VERIFY(BuffDesc.uiSizeInBytes == 0 || BuffDesc.uiSizeInBytes == VkBuffDesc.Width, "Buffer size specified by the BufferDesc (", BuffDesc.uiSizeInBytes,") does not match Vk resource size (", VkBuffDesc.Width, ")" );
+ BuffDesc.uiSizeInBytes = static_cast<Uint32>( VkBuffDesc.Width );
+
+ if (VkBuffDesc.Flags & Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
+ {
+ VERIFY(BuffDesc.BindFlags == 0 || (BuffDesc.BindFlags & BIND_UNORDERED_ACCESS), "BIND_UNORDERED_ACCESS flag is not specified by the BufferDesc, while Vk resource was created with Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS flag");
+ BuffDesc.BindFlags |= BIND_UNORDERED_ACCESS;
+ }
+ if (VkBuffDesc.Flags & Vk_RESOURCE_FLAG_DENY_SHADER_RESOURCE)
+ {
+ VERIFY( !(BuffDesc.BindFlags & BIND_SHADER_RESOURCE), "BIND_SHADER_RESOURCE flag is specified by the BufferDesc, while Vk resource was created with Vk_RESOURCE_FLAG_DENY_SHADER_RESOURCE flag");
+ BuffDesc.BindFlags &= ~BIND_SHADER_RESOURCE;
+ }
+
+ if( (BuffDesc.BindFlags & BIND_UNORDERED_ACCESS) || (BuffDesc.BindFlags & BIND_SHADER_RESOURCE) )
+ {
+ if(BuffDesc.Mode == BUFFER_MODE_STRUCTURED)
+ {
+ VERIFY(BuffDesc.ElementByteStride != 0, "Element byte stride cannot be 0 for a structured buffer");
+ }
+ else if(BuffDesc.Mode == BUFFER_MODE_FORMATTED)
+ {
+ VERIFY( BuffDesc.Format.ValueType != VT_UNDEFINED, "Value type is not specified for a formatted buffer" );
+ VERIFY( BuffDesc.Format.NumComponents != 0, "Num components cannot be zero in a formated buffer" );
+ }
+ else
+ {
+ UNEXPECTED("Buffer mode must be structured or formatted");
+ }
+ }
+#endif
+ return BuffDesc;
+}
+
+BufferVkImpl :: BufferVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &BuffViewObjMemAllocator,
+ RenderDeviceVkImpl *pRenderDeviceVk,
+ const BufferDesc& BuffDesc,
+ void *pVkBuffer) :
+ TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BufferDescFromVkResource(BuffDesc, pVkBuffer), false)/*,
+#ifdef _DEBUG
+ m_DbgMapType(1 + pRenderDeviceVk->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>")),
+#endif
+ m_DynamicData(BuffDesc.Usage == USAGE_DYNAMIC ? (1 + pRenderDeviceVk->GetNumDeferredContexts()) : 0, DynamicAllocation(), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>"))
+ */
+{
+#if 0
+ m_pVkResource = pVkBuffer;
+
+ if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
+ {
+ m_CBVDescriptorAllocation = pRenderDeviceVk->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ CreateCBV(m_CBVDescriptorAllocation.GetCpuHandle());
+ }
+#endif
+}
+BufferVkImpl :: ~BufferVkImpl()
+{
+#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
+}
+
+IMPLEMENT_QUERY_INTERFACE( BufferVkImpl, IID_BufferVk, TBufferBase )
+
+void BufferVkImpl::UpdateData( IDeviceContext *pContext, Uint32 Offset, Uint32 Size, const PVoid pData )
+{
+ TBufferBase::UpdateData( pContext, Offset, Size, pData );
+
+#if 0
+ // We must use cmd context from the device context provided, otherwise there will
+ // be resource barrier issues in the cmd list in the device context
+ auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ pDeviceContextVk->UpdateBufferRegion(this, pData, Offset, Size);
+#endif
+}
+
+void BufferVkImpl :: CopyData(IDeviceContext *pContext, IBuffer *pSrcBuffer, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size)
+{
+#if 0
+ TBufferBase::CopyData( pContext, pSrcBuffer, SrcOffset, DstOffset, Size );
+ auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ pDeviceContextVk->CopyBufferRegion(ValidatedCast<BufferVkImpl>(pSrcBuffer), this, SrcOffset, DstOffset, Size);
+#endif
+}
+
+void BufferVkImpl :: Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags, PVoid &pMappedData)
+{
+ TBufferBase::Map( pContext, MapType, MapFlags, pMappedData );
+#if 0
+ auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+#ifdef _DEBUG
+ if(pDeviceContextVk != nullptr)
+ m_DbgMapType[pDeviceContextVk->GetContextId()] = std::make_pair(MapType, MapFlags);
+#endif
+ if (MapType == MAP_READ )
+ {
+ LOG_WARNING_MESSAGE_ONCE("Mapping CPU buffer for reading on Vk currently requires flushing context and idling GPU");
+ pDeviceContextVk->Flush();
+ auto *pDeviceVk = ValidatedCast<RenderDeviceVkImpl>(GetDevice());
+ pDeviceVk->IdleGPU(false);
+
+ VERIFY(m_Desc.Usage == USAGE_CPU_ACCESSIBLE, "Buffer must be created as USAGE_CPU_ACCESSIBLE to be mapped for reading");
+ Vk_RANGE MapRange;
+ MapRange.Begin = 0;
+ MapRange.End = m_Desc.uiSizeInBytes;
+ m_pVkResource->Map(0, &MapRange, &pMappedData);
+ }
+ else if(MapType == MAP_WRITE)
+ {
+ if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
+ {
+ VERIFY(m_pVkResource != nullptr, "USAGE_CPU_ACCESSIBLE buffer mapped for writing must intialize Vk resource");
+ if (MapFlags & MAP_FLAG_DISCARD)
+ {
+
+ }
+ m_pVkResource->Map(0, nullptr, &pMappedData);
+ }
+ else if (m_Desc.Usage == USAGE_DYNAMIC)
+ {
+ VERIFY(MapFlags & MAP_FLAG_DISCARD, "Vk buffer must be mapped for writing with MAP_FLAG_DISCARD flag");
+ auto *pCtxVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ auto ContextId = pDeviceContextVk->GetContextId();
+ m_DynamicData[ContextId] = pCtxVk->AllocateDynamicSpace(m_Desc.uiSizeInBytes);
+ pMappedData = m_DynamicData[ContextId].CPUAddress;
+ }
+ else
+ {
+ LOG_ERROR("Only USAGE_DYNAMIC and USAGE_CPU_ACCESSIBLE Vk buffers can be mapped for writing");
+ }
+ }
+ else if(MapType == MAP_READ_WRITE)
+ {
+ LOG_ERROR("MAP_READ_WRITE is not supported on Vk");
+ }
+ else
+ {
+ LOG_ERROR("Only MAP_WRITE_DISCARD and MAP_READ are currently implemented in Vk");
+ }
+#endif
+}
+
+void BufferVkImpl::Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags )
+{
+ TBufferBase::Unmap( pContext, MapType, MapFlags );
+
+#if 0
+ auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ Uint32 CtxId = pDeviceContextVk != nullptr ? pDeviceContextVk->GetContextId() : static_cast<Uint32>(-1);
+#ifdef _DEBUG
+ if (pDeviceContextVk != nullptr)
+ {
+ VERIFY(m_DbgMapType[CtxId].first == MapType, "Map type does not match the type provided to Map()");
+ VERIFY(m_DbgMapType[CtxId].second == MapFlags, "Map flags do not match the flags provided to Map()");
+ }
+#endif
+
+ if (MapType == MAP_READ )
+ {
+ Vk_RANGE MapRange;
+ // It is valid to specify the CPU didn't write any data by passing a range where End is less than or equal to Begin.
+ MapRange.Begin = 1;
+ MapRange.End = 0;
+ m_pVkResource->Unmap(0, &MapRange);
+ }
+ else if(MapType == MAP_WRITE)
+ {
+ if (m_Desc.Usage == USAGE_CPU_ACCESSIBLE)
+ {
+ VERIFY(m_pVkResource != nullptr, "USAGE_CPU_ACCESSIBLE buffer mapped for writing must intialize Vk resource");
+ m_pVkResource->Unmap(0, nullptr);
+ }
+ else if (m_Desc.Usage == USAGE_DYNAMIC)
+ {
+ VERIFY(MapFlags & MAP_FLAG_DISCARD, "Vk buffer must be mapped for writing with MAP_FLAG_DISCARD flag");
+ // Copy data into the resource
+ if (m_pVkResource)
+ {
+ pDeviceContextVk->UpdateBufferRegion(this, m_DynamicData[CtxId], 0, m_Desc.uiSizeInBytes);
+ }
+ }
+ }
+
+#ifdef _DEBUG
+ if(pDeviceContextVk != nullptr)
+ m_DbgMapType[CtxId] = std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1));
+#endif
+#endif
+}
+
+void BufferVkImpl::CreateViewInternal( const BufferViewDesc &OrigViewDesc, IBufferView **ppView, bool bIsDefaultView )
+{
+ VERIFY( ppView != nullptr, "Null pointer provided" );
+ if( !ppView )return;
+ VERIFY( *ppView == nullptr, "Overwriting reference to existing object may cause memory leaks" );
+
+ *ppView = nullptr;
+#if 0
+ try
+ {
+ auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice());
+ auto &BuffViewAllocator = pDeviceVkImpl->GetBuffViewObjAllocator();
+ VERIFY( &BuffViewAllocator == &m_dbgBuffViewAllocator, "Buff view allocator does not match allocator provided at buffer initialization" );
+
+ BufferViewDesc ViewDesc = OrigViewDesc;
+ if( ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS )
+ {
+ auto UAVHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ CreateUAV( ViewDesc, UAVHandleAlloc.GetCpuHandle() );
+ *ppView = NEW_RC_OBJ(BuffViewAllocator, "BufferViewVkImpl instance", BufferViewVkImpl, bIsDefaultView ? this : nullptr)
+ (GetDevice(), ViewDesc, this, std::move(UAVHandleAlloc), bIsDefaultView );
+ }
+ else if( ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE )
+ {
+ auto SRVHandleAlloc = pDeviceVkImpl->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ CreateSRV( ViewDesc, SRVHandleAlloc.GetCpuHandle() );
+ *ppView = NEW_RC_OBJ(BuffViewAllocator, "BufferViewVkImpl instance", BufferViewVkImpl, bIsDefaultView ? this : nullptr)
+ (GetDevice(), ViewDesc, this, std::move(SRVHandleAlloc), bIsDefaultView );
+ }
+
+ if( !bIsDefaultView && *ppView )
+ (*ppView)->AddRef();
+ }
+ catch( const std::runtime_error & )
+ {
+ const auto *ViewTypeName = GetBufferViewTypeLiteralName(OrigViewDesc.ViewType);
+ LOG_ERROR("Failed to create view \"", OrigViewDesc.Name ? OrigViewDesc.Name : "", "\" (", ViewTypeName, ") for buffer \"", m_Desc.Name, "\"" );
+ }
+#endif
+}
+
+#if 0
+void BufferVkImpl::CreateUAV( BufferViewDesc &UAVDesc, Vk_CPU_DESCRIPTOR_HANDLE UAVDescriptor )
+{
+ CorrectBufferViewDesc( UAVDesc );
+
+ Vk_UNORDERED_ACCESS_VIEW_DESC Vk_UAVDesc;
+ BufferViewDesc_to_Vk_UAV_DESC(m_Desc, UAVDesc, Vk_UAVDesc);
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateUnorderedAccessView( m_pVkResource, nullptr, &Vk_UAVDesc, UAVDescriptor );
+}
+
+void BufferVkImpl::CreateSRV( struct BufferViewDesc &SRVDesc, Vk_CPU_DESCRIPTOR_HANDLE SRVDescriptor )
+{
+ CorrectBufferViewDesc( SRVDesc );
+
+ Vk_SHADER_RESOURCE_VIEW_DESC Vk_SRVDesc;
+ BufferViewDesc_to_Vk_SRV_DESC(m_Desc, SRVDesc, Vk_SRVDesc);
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateShaderResourceView( m_pVkResource, &Vk_SRVDesc, SRVDescriptor );
+}
+
+void BufferVkImpl::CreateCBV(Vk_CPU_DESCRIPTOR_HANDLE CBVDescriptor)
+{
+ Vk_CONSTANT_BUFFER_VIEW_DESC Vk_CBVDesc;
+ Vk_CBVDesc.BufferLocation = m_pVkResource->GetGPUVirtualAddress();
+ Vk_CBVDesc.SizeInBytes = m_Desc.uiSizeInBytes;
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateConstantBufferView( &Vk_CBVDesc, CBVDescriptor );
+}
+
+#ifdef _DEBUG
+void BufferVkImpl::DbgVerifyDynamicAllocation(Uint32 ContextId)
+{
+ VERIFY(m_DynamicData[ContextId].GPUAddress != 0, "Dynamic buffer must be mapped before the first use");
+ auto CurrentFrame = ValidatedCast<RenderDeviceVkImpl>(GetDevice())->GetCurrentFrameNumber();
+ VERIFY(m_DynamicData[ContextId].FrameNum == CurrentFrame, "Dynamic allocation is out-of-date. Dynamic buffer \"", m_Desc.Name, "\" must be mapped in the same frame it is used.");
+ VERIFY(GetState() == Vk_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers are expected to always be in Vk_RESOURCE_STATE_GENERIC_READ state");
+}
+#endif
+
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp b/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp
new file mode 100644
index 00000000..fa1157a1
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp
@@ -0,0 +1,321 @@
+/* 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 "CommandContext.h"
+#include "TextureVkImpl.h"
+#include "BufferVkImpl.h"
+#include "CommandListManager.h"
+
+namespace Diligent
+{
+
+CommandContext::CommandContext( IMemoryAllocator &MemAllocator,
+ CommandListManager &CmdListManager,
+ GPUDescriptorHeap GPUDescriptorHeaps[],
+ const Uint32 DynamicDescriptorAllocationChunkSize[])/* :
+ m_pCurGraphicsRootSignature( nullptr),
+ m_pCurPipelineState( nullptr),
+ m_pCurComputeRootSignature( nullptr),
+ m_DynamicGPUDescriptorAllocator
+ {
+ {MemAllocator, GPUDescriptorHeaps[0], DynamicDescriptorAllocationChunkSize[0]},
+ {MemAllocator, GPUDescriptorHeaps[1], DynamicDescriptorAllocationChunkSize[1]}
+ },
+ m_PendingResourceBarriers( STD_ALLOCATOR_RAW_MEM(Vk_RESOURCE_BARRIER, GetRawAllocator(), "Allocator for vector<Vk_RESOURCE_BARRIER>") ),
+ m_PendingBarrierObjects( STD_ALLOCATOR_RAW_MEM(RefCntAutoPtr<IDeviceObject>, GetRawAllocator(), "Allocator for vector<RefCntAutoPtr<IDeviceObject>>") )
+ */
+{
+#if 0
+ m_PendingResourceBarriers.reserve(MaxPendingBarriers);
+ m_PendingBarrierObjects.reserve(MaxPendingBarriers);
+
+ CmdListManager.CreateNewCommandList(&m_pCommandList, &m_pCurrentAllocator);
+#endif
+}
+
+CommandContext::~CommandContext( void )
+{
+}
+
+
+#if 0
+void CommandContext::Reset( CommandListManager& CmdListManager )
+{
+
+ // We only call Reset() on previously freed contexts. The command list persists, but we need to
+ // request a new allocator if there is none
+ // The allocator may not be null if the command context was previously disposed without being executed
+ VERIFY_EXPR(m_pCommandList != nullptr);
+ if( !m_pCurrentAllocator )
+ {
+ CmdListManager.RequestAllocator(&m_pCurrentAllocator);
+ m_pCommandList->Reset(m_pCurrentAllocator, nullptr);
+ }
+
+ m_pCurPipelineState = nullptr;
+ m_pCurGraphicsRootSignature = nullptr;
+ m_pCurComputeRootSignature = nullptr;
+ m_PendingResourceBarriers.clear();
+ m_PendingBarrierObjects.clear();
+ m_BoundDescriptorHeaps = ShaderDescriptorHeaps();
+
+ m_PrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
+#if 0
+ BindDescriptorHeaps();
+#endif
+}
+
+
+IVkGraphicsCommandList* CommandContext::Close(IVkCommandAllocator **ppAllocator)
+{
+
+ FlushResourceBarriers();
+
+ //if (m_ID.length() > 0)
+ // EngineProfiling::EndBlock(this);
+
+ VERIFY_EXPR(m_pCurrentAllocator != nullptr);
+ auto hr = m_pCommandList->Close();
+ VERIFY(SUCCEEDED(hr), "Failed to close the command list");
+
+ if( ppAllocator != nullptr )
+ *ppAllocator = m_pCurrentAllocator.Detach();
+ return m_pCommandList;
+}
+
+
+
+void GraphicsContext::SetRenderTargets( UINT NumRTVs, ITextureViewVk** ppRTVs, ITextureViewVk* pDSV )
+{
+ Vk_CPU_DESCRIPTOR_HANDLE RTVHandles[8]; // Do not waste time initializing array to zero
+
+ for (UINT i = 0; i < NumRTVs; ++i)
+ {
+ auto *pRTV = ppRTVs[i];
+ if( pRTV )
+ {
+ auto *pTexture = ValidatedCast<TextureVkImpl>( pRTV->GetTexture() );
+ TransitionResource(pTexture, Vk_RESOURCE_STATE_RENDER_TARGET);
+ RTVHandles[i] = pRTV->GetCPUDescriptorHandle();
+ VERIFY_EXPR(RTVHandles[i].ptr != 0);
+ }
+ }
+
+ if (pDSV)
+ {
+ auto *pTexture = ValidatedCast<TextureVkImpl>( pDSV->GetTexture() );
+ //if (bReadOnlyDepth)
+ //{
+ // TransitionResource(*pTexture, Vk_RESOURCE_STATE_DEPTH_READ);
+ // m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, &DSV->GetDSV_DepthReadOnly() );
+ //}
+ //else
+ {
+ TransitionResource(pTexture, Vk_RESOURCE_STATE_DEPTH_WRITE);
+ auto DSVHandle = pDSV->GetCPUDescriptorHandle();
+ VERIFY_EXPR(DSVHandle.ptr != 0);
+ m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, &DSVHandle );
+ }
+ }
+ else if(NumRTVs > 0)
+ {
+ m_pCommandList->OMSetRenderTargets( NumRTVs, RTVHandles, FALSE, nullptr );
+ }
+}
+
+void CommandContext::ClearUAVFloat( ITextureViewVk *pTexView, const float* Color )
+{
+ auto *pTexture = ValidatedCast<TextureVkImpl>( pTexView->GetTexture() );
+ TransitionResource(pTexture, Vk_RESOURCE_STATE_UNORDERED_ACCESS, true);
+
+ // After binding a UAV, we can get a GPU handle that is required to clear it as a UAV (because it essentially runs
+ // a shader to set all of the values).
+ UNSUPPORTED("Not yet implemented");
+ Vk_GPU_DESCRIPTOR_HANDLE GpuVisibleHandle = {};//m_DynamicDescriptorHeap.UploadDirect(Target.GetUAV());
+ m_pCommandList->ClearUnorderedAccessViewFloat(GpuVisibleHandle, pTexView->GetCPUDescriptorHandle(), pTexture->GetVkResource(), Color, 0, nullptr);
+}
+
+void CommandContext::ClearUAVUint( ITextureViewVk *pTexView, const UINT *Color )
+{
+ auto *pTexture = ValidatedCast<TextureVkImpl>( pTexView->GetTexture() );
+ TransitionResource(pTexture, Vk_RESOURCE_STATE_UNORDERED_ACCESS, true);
+
+ // After binding a UAV, we can get a GPU handle that is required to clear it as a UAV (because it essentially runs
+ // a shader to set all of the values).
+ UNSUPPORTED("Not yet implemented");
+ Vk_GPU_DESCRIPTOR_HANDLE GpuVisibleHandle = {};//m_DynamicDescriptorHeap.UploadDirect(Target.GetUAV());
+ //CD3DX12_RECT ClearRect(0, 0, (LONG)Target.GetWidth(), (LONG)Target.GetHeight());
+
+ //TODO: My Nvidia card is not clearing UAVs with either Float or Uint variants.
+ m_pCommandList->ClearUnorderedAccessViewUint(GpuVisibleHandle, pTexView->GetCPUDescriptorHandle(), pTexture->GetVkResource(), Color, 0, nullptr/*1, &ClearRect*/);
+}
+
+
+void GraphicsContext::ClearRenderTarget( ITextureViewVk *pRTV, const float *Color )
+{
+ auto *pTexture = ValidatedCast<TextureVkImpl>( pRTV->GetTexture() );
+ TransitionResource(pTexture, Vk_RESOURCE_STATE_RENDER_TARGET, true);
+ m_pCommandList->ClearRenderTargetView(pRTV->GetCPUDescriptorHandle(), Color, 0, nullptr);
+}
+
+void GraphicsContext::ClearDepthStencil( ITextureViewVk *pDSV, Vk_CLEAR_FLAGS ClearFlags, float Depth, UINT8 Stencil )
+{
+ auto *pTexture = ValidatedCast<TextureVkImpl>( pDSV->GetTexture() );
+ TransitionResource( pTexture, Vk_RESOURCE_STATE_DEPTH_WRITE, true);
+ m_pCommandList->ClearDepthStencilView(pDSV->GetCPUDescriptorHandle(), ClearFlags, Depth, Stencil, 0, nullptr);
+}
+
+
+void CommandContext::TransitionResource(ITextureVk *pTexture, Vk_RESOURCE_STATES NewState, bool FlushImmediate)
+{
+ VERIFY_EXPR( pTexture != nullptr );
+ auto *pTexVk = ValidatedCast<TextureVkImpl>(pTexture);
+ TransitionResource(*pTexVk, *pTexVk, NewState, FlushImmediate);
+}
+
+void CommandContext::TransitionResource(IBufferVk *pBuffer, Vk_RESOURCE_STATES NewState, bool FlushImmediate)
+{
+ VERIFY_EXPR( pBuffer != nullptr );
+ auto *pBuffVk = ValidatedCast<BufferVkImpl>(pBuffer);
+
+#ifdef _DEBUG
+ // Dynamic buffers wtih no SRV/UAV bind flags are suballocated in
+ // the upload heap when Map() is called and must always be in
+ // Vk_RESOURCE_STATE_GENERIC_READ state
+ if(pBuffVk->GetDesc().Usage == USAGE_DYNAMIC && (pBuffVk->GetDesc().BindFlags & (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) == 0)
+ {
+ VERIFY(pBuffVk->GetState() == Vk_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers that cannot be bound as SRV or UAV are expected to always be in Vk_RESOURCE_STATE_GENERIC_READ state");
+ VERIFY( (NewState & Vk_RESOURCE_STATE_GENERIC_READ) == NewState, "Dynamic buffers can only transition to one of Vk_RESOURCE_STATE_GENERIC_READ states");
+ }
+#endif
+
+ TransitionResource(*pBuffVk, *pBuffVk, NewState, FlushImmediate);
+
+#ifdef _DEBUG
+ if(pBuffVk->GetDesc().Usage == USAGE_DYNAMIC && (pBuffVk->GetDesc().BindFlags & (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) == 0)
+ VERIFY(pBuffVk->GetState() == Vk_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers without SRV/UAV bind flag are expected to never transition from Vk_RESOURCE_STATE_GENERIC_READ state");
+#endif
+}
+
+void CommandContext::TransitionResource(VkResourceBase& Resource, IDeviceObject &Object, Vk_RESOURCE_STATES NewState, bool FlushImmediate)
+{
+ Vk_RESOURCE_STATES OldState = Resource.GetState();
+
+ // Check if required state is already set
+ if ( (OldState & NewState) != NewState || NewState == 0 && OldState != 0 )
+ {
+ // If both old state and new state are read-only states, combine the two
+ if( (OldState & Vk_RESOURCE_STATE_GENERIC_READ) == OldState &&
+ (NewState & Vk_RESOURCE_STATE_GENERIC_READ) == NewState )
+ NewState |= OldState;
+
+ m_PendingResourceBarriers.emplace_back();
+ m_PendingBarrierObjects.emplace_back(&Object);
+ Vk_RESOURCE_BARRIER& BarrierDesc = m_PendingResourceBarriers.back();
+
+ BarrierDesc.Type = Vk_RESOURCE_BARRIER_TYPE_TRANSITION;
+ BarrierDesc.Transition.pResource = Resource.GetVkResource();
+ BarrierDesc.Transition.Subresource = Vk_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ BarrierDesc.Transition.StateBefore = OldState;
+ BarrierDesc.Transition.StateAfter = NewState;
+
+ // Check to see if we already started the transition
+#if 0
+ if (NewState == Resource.m_TransitioningState)
+ {
+ BarrierDesc.Flags = Vk_RESOURCE_BARRIER_FLAG_END_ONLY;
+ Resource.m_TransitioningState = (Vk_RESOURCE_STATES)-1;
+ }
+ else
+#endif
+ BarrierDesc.Flags = Vk_RESOURCE_BARRIER_FLAG_NONE;
+
+ Resource.SetState( NewState );
+ }
+ else if (NewState == Vk_RESOURCE_STATE_UNORDERED_ACCESS)
+ InsertUAVBarrier(Resource, Object, FlushImmediate);
+
+ if (FlushImmediate || m_PendingResourceBarriers.size() >= MaxPendingBarriers)
+ FlushResourceBarriers();
+}
+
+void CommandContext::FlushResourceBarriers()
+{
+ if (m_PendingResourceBarriers.empty())
+ {
+ VERIFY_EXPR(m_PendingBarrierObjects.empty());
+ return;
+ }
+
+ m_pCommandList->ResourceBarrier(static_cast<UINT>(m_PendingResourceBarriers.size()), m_PendingResourceBarriers.data());
+ m_PendingResourceBarriers.clear();
+ m_PendingBarrierObjects.clear();
+}
+
+
+void CommandContext::InsertUAVBarrier(VkResourceBase& Resource, IDeviceObject &Object, bool FlushImmediate)
+{
+ m_PendingResourceBarriers.emplace_back();
+ m_PendingBarrierObjects.emplace_back(&Object);
+ Vk_RESOURCE_BARRIER& BarrierDesc = m_PendingResourceBarriers.back();
+
+ BarrierDesc.Type = Vk_RESOURCE_BARRIER_TYPE_UAV;
+ BarrierDesc.Flags = Vk_RESOURCE_BARRIER_FLAG_NONE;
+ BarrierDesc.UAV.pResource = Resource.GetVkResource();
+
+ if (FlushImmediate)
+ FlushResourceBarriers();
+}
+
+void CommandContext::InsertAliasBarrier(VkResourceBase& Before, VkResourceBase& After, IDeviceObject &BeforeObj, IDeviceObject &AfterObj, bool FlushImmediate)
+{
+ m_PendingResourceBarriers.emplace_back();
+ m_PendingBarrierObjects.emplace_back(&BeforeObj);
+ m_PendingBarrierObjects.emplace_back(&AfterObj);
+ Vk_RESOURCE_BARRIER& BarrierDesc = m_PendingResourceBarriers.back();
+
+ BarrierDesc.Type = Vk_RESOURCE_BARRIER_TYPE_ALIASING;
+ BarrierDesc.Flags = Vk_RESOURCE_BARRIER_FLAG_NONE;
+ BarrierDesc.Aliasing.pResourceBefore = Before.GetVkResource();
+ BarrierDesc.Aliasing.pResourceAfter = After.GetVkResource();
+
+ if (FlushImmediate)
+ FlushResourceBarriers();
+}
+
+void CommandContext::DiscardDynamicDescriptors(Uint64 FenceValue)
+{
+ for(size_t HeapType = 0; HeapType < _countof(m_DynamicGPUDescriptorAllocator); ++HeapType)
+ m_DynamicGPUDescriptorAllocator[HeapType].DiscardAllocations(FenceValue);
+}
+
+DescriptorHeapAllocation CommandContext::AllocateDynamicGPUVisibleDescriptor( Vk_DESCRIPTOR_HEAP_TYPE Type, UINT Count )
+{
+ VERIFY(Type >= Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && Type <= Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, "Invalid heap type");
+ return m_DynamicGPUDescriptorAllocator[Type].Allocate(Count);
+}
+
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp b/Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp
new file mode 100644
index 00000000..b4d67c9a
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/CommandListManager.cpp
@@ -0,0 +1,109 @@
+/* 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
new file mode 100644
index 00000000..bf7c3527
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp
@@ -0,0 +1,84 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "CommandQueueVkImpl.h"
+
+namespace Diligent
+{
+
+CommandQueueVkImpl::CommandQueueVkImpl(IReferenceCounters *pRefCounters, void *pVkNativeCmdQueue, void *pVkFence) :
+ TBase(pRefCounters)/*,
+ m_pVkCmdQueue(pVkNativeCmdQueue),
+ m_VkFence(pVkFence),
+ m_NextFenceValue(1),
+ m_WaitForGPUEventHandle( CreateEvent(nullptr, false, false, nullptr) )
+ */
+{
+ //VERIFY_EXPR(m_WaitForGPUEventHandle != INVALID_HANDLE_VALUE);
+ //m_VkFence->Signal(0);
+}
+
+CommandQueueVkImpl::~CommandQueueVkImpl()
+{
+// CloseHandle(m_WaitForGPUEventHandle);
+}
+
+IMPLEMENT_QUERY_INTERFACE( CommandQueueVkImpl, IID_CommandQueueVk, TBase )
+
+#if 0
+UINT64 CommandQueueVkImpl::ExecuteCommandList(IVkGraphicsCommandList* commandList)
+{
+ IVkCommandList *const ppCmdLists[] = {commandList};
+ m_pVkCmdQueue->ExecuteCommandLists(1, ppCmdLists);
+ auto FenceValue = m_NextFenceValue;
+ // Signal the fence
+ m_pVkCmdQueue->Signal(m_VkFence, FenceValue);
+ // Increment the value
+ Atomics::AtomicIncrement(m_NextFenceValue);
+ return FenceValue;
+}
+
+void CommandQueueVkImpl::IdleGPU()
+{
+ Uint64 LastSignaledFenceValue = m_NextFenceValue;
+ m_pVkCmdQueue->Signal(m_VkFence, LastSignaledFenceValue);
+ Atomics::AtomicIncrement(m_NextFenceValue);
+ if (GetCompletedFenceValue() < LastSignaledFenceValue)
+ {
+ m_VkFence->SetEventOnCompletion(LastSignaledFenceValue, m_WaitForGPUEventHandle);
+ WaitForSingleObject(m_WaitForGPUEventHandle, INFINITE);
+ VERIFY(GetCompletedFenceValue() == LastSignaledFenceValue, "Unexpected signaled fence value");
+ }
+}
+
+Uint64 CommandQueueVkImpl::GetCompletedFenceValue()
+{
+ auto CompletedFenceValue = m_VkFence->GetCompletedValue();
+ if(CompletedFenceValue > m_LastCompletedFenceValue)
+ m_LastCompletedFenceValue = CompletedFenceValue;
+ return m_LastCompletedFenceValue;
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/DLLMain.cpp b/Graphics/GraphicsEngineVulkan/src/DLLMain.cpp
new file mode 100644
index 00000000..58b1c375
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/DLLMain.cpp
@@ -0,0 +1,49 @@
+/* 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"
+
+BOOL APIENTRY DllMain(HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+{
+ switch( ul_reason_for_call )
+ {
+ case DLL_PROCESS_ATTACH:
+ #if defined(_DEBUG) || defined(DEBUG)
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+ #endif
+ break;
+
+ case DLL_THREAD_ATTACH:
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+
+ return TRUE;
+} \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp
new file mode 100644
index 00000000..a464d7b9
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp
@@ -0,0 +1,429 @@
+/* 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 "DescriptorHeap.h"
+#include "RenderDeviceVkImpl.h"
+#include "VulkanUtils.h"
+
+namespace Diligent
+{
+
+#if 0
+// Creates a new descriptor heap and reference the entire heap
+DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocator &Allocator,
+ RenderDeviceVkImpl *pDeviceVkImpl,
+ IDescriptorAllocator *pParentAllocator,
+ size_t ThisManagerId,
+ const Vk_DESCRIPTOR_HEAP_DESC &HeapDesc) :
+ m_FreeBlockManager(HeapDesc.NumDescriptors, Allocator),
+ m_NumDescriptorsInAllocation(HeapDesc.NumDescriptors),
+ m_HeapDesc(HeapDesc),
+ m_pDeviceVkImpl(pDeviceVkImpl),
+ m_pParentAllocator(pParentAllocator),
+ m_ThisManagerId(ThisManagerId)
+{
+ auto pDevice = pDeviceVkImpl->GetVkDevice();
+
+ m_FirstCPUHandle.ptr = 0;
+ m_FirstGPUHandle.ptr = 0;
+ m_DescriptorSize = pDevice->GetDescriptorHandleIncrementSize(HeapDesc.Type);
+
+ pDevice->CreateDescriptorHeap(&m_HeapDesc, __uuidof(m_pVkDescriptorHeap), reinterpret_cast<void**>(static_cast<IVkDescriptorHeap**>(&m_pVkDescriptorHeap)));
+ m_FirstCPUHandle = m_pVkDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
+ if(m_HeapDesc.Flags & Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
+ m_FirstGPUHandle = m_pVkDescriptorHeap->GetGPUDescriptorHandleForHeapStart();
+}
+
+// Uses subrange of descriptors in the existing Vk descriptor heap
+// that starts at offset FirstDescriptor and uses NumDescriptors descriptors
+DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocator &Allocator,
+ RenderDeviceVkImpl *pDeviceVkImpl,
+ IDescriptorAllocator *pParentAllocator,
+ size_t ThisManagerId,
+ IVkDescriptorHeap *pVkDescriptorHeap,
+ Uint32 FirstDescriptor,
+ Uint32 NumDescriptors):
+ m_FreeBlockManager(NumDescriptors, Allocator),
+ m_NumDescriptorsInAllocation(NumDescriptors),
+ m_pDeviceVkImpl(pDeviceVkImpl),
+ m_pParentAllocator(pParentAllocator),
+ m_ThisManagerId(ThisManagerId),
+ m_pVkDescriptorHeap(pVkDescriptorHeap)
+{
+ m_HeapDesc = m_pVkDescriptorHeap->GetDesc();
+ m_DescriptorSize = pDeviceVkImpl->GetVkDevice()->GetDescriptorHandleIncrementSize(m_HeapDesc.Type);
+
+ m_FirstCPUHandle = pVkDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
+ m_FirstCPUHandle.ptr += m_DescriptorSize * FirstDescriptor;
+
+ if (m_HeapDesc.Flags & Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
+ {
+ m_FirstGPUHandle = pVkDescriptorHeap->GetGPUDescriptorHandleForHeapStart();
+ m_FirstGPUHandle.ptr += m_DescriptorSize * FirstDescriptor;
+ }
+}
+
+
+DescriptorHeapAllocationManager::~DescriptorHeapAllocationManager()
+{
+ VERIFY(m_FreeBlockManager.GetFreeSize() == m_NumDescriptorsInAllocation, "Not all descriptors were released");
+}
+
+DescriptorHeapAllocation DescriptorHeapAllocationManager::Allocate(uint32_t Count)
+{
+ std::lock_guard<std::mutex> LockGuard(m_AllocationMutex);
+ // Methods of VariableSizeGPUAllocationsManager class are not thread safe!
+
+ // Use variable-size GPU allocations manager to allocate the requested number of descriptors
+ auto DescriptorHandleOffset = m_FreeBlockManager.Allocate(Count);
+ if (DescriptorHandleOffset == VariableSizeGPUAllocationsManager::InvalidOffset)
+ {
+ return DescriptorHeapAllocation();
+ }
+
+ // Compute the first CPU and GPU descriptor handles in the allocation by
+ // offseting the first CPU and GPU descriptor handle in the range
+ auto CPUHandle = m_FirstCPUHandle;
+ CPUHandle.ptr += DescriptorHandleOffset * m_DescriptorSize;
+
+ auto GPUHandle = m_FirstGPUHandle; // Will be null if the heap is not GPU-visible
+ if(m_HeapDesc.Flags & Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)
+ GPUHandle.ptr += DescriptorHandleOffset * m_DescriptorSize;
+
+ VERIFY(m_ThisManagerId < std::numeric_limits<Uint16>::max(), "ManagerID exceeds 16-bit range");
+ return DescriptorHeapAllocation( m_pParentAllocator, m_pVkDescriptorHeap, CPUHandle, GPUHandle, Count, static_cast<Uint16>(m_ThisManagerId));
+}
+
+void DescriptorHeapAllocationManager::Free(DescriptorHeapAllocation&& Allocation)
+{
+ std::lock_guard<std::mutex> LockGuard(m_AllocationMutex);
+ // Methods of VariableSizeGPUAllocationsManager class are not thread safe!
+
+ VERIFY(Allocation.GetAllocationManagerId() == m_ThisManagerId, "Invalid descriptor heap manager Id");
+
+ auto DescriptorOffset = (Allocation.GetCpuHandle().ptr - m_FirstCPUHandle.ptr) / m_DescriptorSize;
+
+ // Note that the allocation is not released immediately, but added to the release queue in the allocations manager
+
+ // 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
+ //
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+ //
+ // If basic requirement is met, GetNextFenceValue() will never return a number that is less than the fence value
+ // associated with the last command list that references descriptors from the allocation
+ m_FreeBlockManager.Free(DescriptorOffset, Allocation.GetNumHandles(), m_pDeviceVkImpl->GetNextFenceValue());
+
+ // Clear the allocation
+ Allocation = DescriptorHeapAllocation();
+}
+
+void DescriptorHeapAllocationManager::ReleaseStaleAllocations(Uint64 LastCompletedFenceValue)
+{
+ std::lock_guard<std::mutex> LockGuard(m_AllocationMutex);
+ // Methods of VariableSizeGPUAllocationsManager class are not thread safe!
+
+ m_FreeBlockManager.ReleaseStaleAllocations(LastCompletedFenceValue);
+}
+
+
+
+
+//
+// CPUDescriptorHeap implementation
+//
+CPUDescriptorHeap::CPUDescriptorHeap(IMemoryAllocator &Allocator, RenderDeviceVkImpl *pDeviceVkImpl, Uint32 NumDescriptorsInHeap, Vk_DESCRIPTOR_HEAP_TYPE Type, Vk_DESCRIPTOR_HEAP_FLAGS Flags) :
+ m_pDeviceVkImpl(pDeviceVkImpl),
+ m_MemAllocator(Allocator),
+ m_HeapPool(STD_ALLOCATOR_RAW_MEM(DescriptorHeapAllocationManager, GetRawAllocator(), "Allocator for vector<DescriptorHeapAllocationManager>")),
+ m_AvailableHeaps(STD_ALLOCATOR_RAW_MEM(size_t, GetRawAllocator(), "Allocator for set<size_t>"))
+{
+ m_HeapDesc.Type = Type;
+ m_HeapDesc.NodeMask = 1;
+ m_HeapDesc.NumDescriptors = NumDescriptorsInHeap;
+ m_HeapDesc.Flags = Flags;
+
+ m_DescriptorSize = m_pDeviceVkImpl->GetVkDevice()->GetDescriptorHandleIncrementSize(Type);
+}
+
+CPUDescriptorHeap::~CPUDescriptorHeap()
+{
+ VERIFY(m_CurrentSize == 0, "Not all allocations released" );
+
+ VERIFY(m_AvailableHeaps.size() == m_HeapPool.size(), "Not all descriptor heap pools are released");
+ Uint32 TotalDescriptors = 0;
+ for (auto HeapPoolIt = m_HeapPool.begin(); HeapPoolIt != m_HeapPool.end(); ++HeapPoolIt)
+ {
+ VERIFY(HeapPoolIt->GetNumAvailableDescriptors() == HeapPoolIt->GetMaxDescriptors(), "Not all descriptors in the descriptor pool are released");
+ TotalDescriptors += HeapPoolIt->GetMaxDescriptors();
+ }
+ TotalDescriptors = std::max(TotalDescriptors, 1u);
+
+ LOG_INFO_MESSAGE(GetVkDescriptorHeapTypeLiteralName(m_HeapDesc.Type), " CPU heap max size: ", m_MaxHeapSize, " (", m_MaxHeapSize*100/ TotalDescriptors, "%) "
+ ". Max stale size: ", m_MaxStaleSize, " (", m_MaxStaleSize * 100 / TotalDescriptors, "%)");
+}
+
+DescriptorHeapAllocation CPUDescriptorHeap::Allocate( uint32_t Count )
+{
+ std::lock_guard<std::mutex> LockGuard(m_AllocationMutex);
+ // Note that every DescriptorHeapAllocationManager object instance is itslef
+ // thread-safe. Nested mutexes cannot cause a deadlock
+
+ DescriptorHeapAllocation Allocation;
+ // Go through all descriptor heap managers that have free descriptors
+ auto AvailableHeapIt = m_AvailableHeaps.begin();
+ while( AvailableHeapIt != m_AvailableHeaps.end() )
+ {
+ auto NextIt = AvailableHeapIt;
+ ++NextIt;
+ // Try to allocate descriptor using the current descriptor heap manager
+ Allocation = m_HeapPool[*AvailableHeapIt].Allocate(Count);
+ // Remove the manager from the pool if it has no more available descriptors
+ if (m_HeapPool[*AvailableHeapIt].GetNumAvailableDescriptors() == 0)
+ m_AvailableHeaps.erase(*AvailableHeapIt);
+
+ // Terminate the loop if descriptor was successfully allocated, otherwise
+ // go to the next manager
+ if(Allocation.GetCpuHandle().ptr != 0)
+ break;
+ AvailableHeapIt = NextIt;
+ }
+
+ // If there were no available descriptor heap managers or no manager was able
+ // to suffice the allocation request, create a new manager
+ if(Allocation.GetCpuHandle().ptr == 0)
+ {
+ // Make sure the heap is large enough to accomodate the requested number of descriptors
+ if(Count > m_HeapDesc.NumDescriptors)
+ {
+ LOG_WARNING_MESSAGE("Number of requested CPU descriptors handles (", Count, ") exceeds the descriptor heap size (", m_HeapDesc.NumDescriptors,"). Increasing the number of descriptors in the heap");
+ }
+ m_HeapDesc.NumDescriptors = std::max(m_HeapDesc.NumDescriptors, static_cast<UINT>(Count));
+ // Create a new descriptor heap manager. Note that this constructor creates a new Vk descriptor
+ // heap and references the entire heap. Pool index is used as manager ID
+ m_HeapPool.emplace_back(m_MemAllocator, m_pDeviceVkImpl, this, m_HeapPool.size(), m_HeapDesc);
+ auto NewHeapIt = m_AvailableHeaps.insert(m_HeapPool.size()-1);
+
+ // Use the new manager to allocate descriptor handles
+ Allocation = m_HeapPool[*NewHeapIt.first].Allocate(Count);
+ }
+
+ m_CurrentSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0;
+ m_MaxHeapSize = std::max(m_MaxHeapSize, m_CurrentSize);
+
+ return Allocation;
+}
+
+void CPUDescriptorHeap::Free(DescriptorHeapAllocation&& Allocation)
+{
+ // Method is called from ~DescriptorHeapAllocation()
+ std::lock_guard<std::mutex> LockGuard(m_AllocationMutex);
+ auto ManagerId = Allocation.GetAllocationManagerId();
+ m_CurrentSize -= static_cast<Uint32>(Allocation.GetNumHandles());
+ m_HeapPool[ManagerId].Free(std::move(Allocation));
+}
+
+void CPUDescriptorHeap::ReleaseStaleAllocations(Uint64 LastCompletedFenceValue)
+{
+ std::lock_guard<std::mutex> LockGuard(m_AllocationMutex);
+ size_t StaleSize = 0;
+ for (size_t HeapManagerInd = 0; HeapManagerInd < m_HeapPool.size(); ++HeapManagerInd)
+ {
+ // Update size before releasing stale allocations
+ StaleSize += m_HeapPool[HeapManagerInd].GetNumStaleDescriptors();
+
+ m_HeapPool[HeapManagerInd].ReleaseStaleAllocations(LastCompletedFenceValue);
+ // Return the manager to the pool of available managers if it has available descriptors
+ if(m_HeapPool[HeapManagerInd].GetNumAvailableDescriptors() > 0)
+ m_AvailableHeaps.insert(HeapManagerInd);
+ }
+ m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast<Uint32>(StaleSize));
+}
+
+
+
+
+GPUDescriptorHeap::GPUDescriptorHeap(IMemoryAllocator &Allocator,
+ RenderDeviceVkImpl *pDevice,
+ Uint32 NumDescriptorsInHeap,
+ Uint32 NumDynamicDescriptors,
+ Vk_DESCRIPTOR_HEAP_TYPE Type,
+ Vk_DESCRIPTOR_HEAP_FLAGS Flags) :
+ m_pDeviceVk(pDevice),
+ m_HeapDesc
+ {
+ Type,
+ NumDescriptorsInHeap + NumDynamicDescriptors,
+ Flags,
+ 1 // UINT NodeMask;
+ },
+ m_pVkDescriptorHeap([&]{
+ CComPtr<IVkDescriptorHeap> pHeap;
+ pDevice->GetVkDevice()->CreateDescriptorHeap(&m_HeapDesc, __uuidof(pHeap), reinterpret_cast<void**>(&pHeap));
+ return pHeap;
+ }()),
+ m_DescriptorSize( pDevice->GetVkDevice()->GetDescriptorHandleIncrementSize(Type) ),
+ m_HeapAllocationManager(Allocator, pDevice, this, 0, m_pVkDescriptorHeap, 0, NumDescriptorsInHeap),
+ m_DynamicAllocationsManager(Allocator, pDevice, this, 1, m_pVkDescriptorHeap, NumDescriptorsInHeap, NumDynamicDescriptors )
+{
+}
+
+GPUDescriptorHeap::~GPUDescriptorHeap()
+{
+ auto StaticSize = m_HeapAllocationManager.GetMaxDescriptors();
+ auto DynamicSize = m_DynamicAllocationsManager.GetMaxDescriptors();
+ LOG_INFO_MESSAGE(GetVkDescriptorHeapTypeLiteralName(m_HeapDesc.Type), " GPU heap max allocated size (static|dynamic): ",
+ m_MaxHeapSize, " (", m_MaxHeapSize * 100 / StaticSize,"%) | ",
+ m_MaxDynamicSize, " (", m_MaxDynamicSize * 100 / DynamicSize, "%). Max stale size (static|dynamic): ",
+ m_MaxStaleSize, " (", m_MaxStaleSize * 100 / StaticSize, "%) | ",
+ m_MaxDynamicStaleSize, " (", m_MaxDynamicStaleSize * 100 / DynamicSize, "%)");
+}
+
+DescriptorHeapAllocation GPUDescriptorHeap::Allocate(uint32_t Count)
+{
+ VERIFY_EXPR(Count > 0);
+ // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe
+ std::lock_guard<std::mutex> LockGuard(m_AllocMutex);
+ DescriptorHeapAllocation Allocation = m_HeapAllocationManager.Allocate(Count);
+ VERIFY(!Allocation.IsNull(), "Failed to allocate ", Count, " GPU descriptors");
+
+ m_CurrentSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0;
+ m_MaxHeapSize = std::max(m_MaxHeapSize, m_CurrentSize);
+
+ return Allocation;
+}
+
+DescriptorHeapAllocation GPUDescriptorHeap::AllocateDynamic(uint32_t Count)
+{
+ VERIFY_EXPR(Count > 0);
+ // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe
+ std::lock_guard<std::mutex> LockGuard(m_DynAllocMutex);
+ DescriptorHeapAllocation Allocation = m_DynamicAllocationsManager.Allocate(Count);
+ VERIFY(!Allocation.IsNull(), "Failed to allocate ", Count, " dynamic GPU descriptors");
+
+ m_CurrentDynamicSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0;
+ m_MaxDynamicSize = std::max(m_MaxDynamicSize, m_CurrentDynamicSize);
+
+ return Allocation;
+}
+
+void GPUDescriptorHeap::Free(DescriptorHeapAllocation&& Allocation)
+{
+ auto MgrId = Allocation.GetAllocationManagerId();
+ VERIFY(MgrId == 0 || MgrId == 1, "Unexpected allocation manager ID");
+
+ // Note: mutexex may be redundant as DescriptorHeapAllocationManager::Free() is itself thread-safe
+ if(MgrId == 0)
+ {
+ std::lock_guard<std::mutex> LockGuard(m_AllocMutex);
+ m_CurrentSize -= static_cast<Uint32>(Allocation.GetNumHandles());
+ m_HeapAllocationManager.Free(std::move(Allocation));
+ }
+ else
+ {
+ std::lock_guard<std::mutex> LockGuard(m_DynAllocMutex);
+ m_CurrentDynamicSize -= static_cast<Uint32>(Allocation.GetNumHandles());
+ m_DynamicAllocationsManager.Free(std::move(Allocation));
+ }
+}
+
+void GPUDescriptorHeap::ReleaseStaleAllocations(Uint64 LastCompletedFenceValue)
+{
+ {
+ std::lock_guard<std::mutex> LockGuard(m_AllocMutex);
+ m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast<Uint32>(m_HeapAllocationManager.GetNumStaleDescriptors()));
+ m_HeapAllocationManager.ReleaseStaleAllocations(LastCompletedFenceValue);
+ }
+
+ {
+ std::lock_guard<std::mutex> LockGuard(m_DynAllocMutex);
+ m_MaxDynamicStaleSize = std::max(m_MaxDynamicStaleSize, static_cast<Uint32>(m_DynamicAllocationsManager.GetNumStaleDescriptors()));
+ m_DynamicAllocationsManager.ReleaseStaleAllocations(LastCompletedFenceValue);
+ }
+}
+
+
+
+
+
+DynamicSuballocationsManager::DynamicSuballocationsManager(IMemoryAllocator &Allocator, GPUDescriptorHeap& ParentGPUHeap, Uint32 DynamicChunkSize) :
+ m_ParentGPUHeap(ParentGPUHeap),
+ m_DynamicChunkSize(DynamicChunkSize),
+ m_Suballocations(STD_ALLOCATOR_RAW_MEM(DescriptorHeapAllocation, GetRawAllocator(), "Allocator for vector<DescriptorHeapAllocation>"))
+{
+}
+
+void DynamicSuballocationsManager::DiscardAllocations(Uint64 /*FenceValue*/)
+{
+ // Clear the list and dispose all allocated chunks of GPU descriptor heap.
+ // The chunks will be added to the release queue in the allocations manager
+ m_Suballocations.clear();
+}
+
+DescriptorHeapAllocation DynamicSuballocationsManager::Allocate(Uint32 Count)
+{
+ // This method is intentionally lock-free as it is expected to
+ // be called through device context from single thread only
+
+ // Check if there are no chunks or the last chunk does not have enough space
+ if( m_Suballocations.empty() ||
+ m_CurrentSuballocationOffset + Count > m_Suballocations.back().GetNumHandles() )
+ {
+ // Request a new chunk from the parent GPU descriptor heap
+ auto SuballocationSize = std::max(m_DynamicChunkSize, Count);
+ auto NewDynamicSubAllocation = m_ParentGPUHeap.AllocateDynamic(SuballocationSize);
+ if (NewDynamicSubAllocation.GetCpuHandle().ptr == 0)
+ {
+ LOG_ERROR_MESSAGE("Failed to suballocate region for dynamic descriptors");
+ return DescriptorHeapAllocation();
+ }
+ m_Suballocations.emplace_back(std::move(NewDynamicSubAllocation));
+ m_CurrentSuballocationOffset = 0;
+ }
+
+ // Perform suballocation from the last chunk
+ auto &CurrentSuballocation = m_Suballocations.back();
+
+ auto ManagerId = CurrentSuballocation.GetAllocationManagerId();
+ VERIFY(ManagerId < std::numeric_limits<Uint16>::max(), "ManagerID exceed allowed limit");
+ DescriptorHeapAllocation Allocation( this,
+ CurrentSuballocation.GetDescriptorHeap(),
+ CurrentSuballocation.GetCpuHandle(m_CurrentSuballocationOffset),
+ CurrentSuballocation.GetGpuHandle(m_CurrentSuballocationOffset),
+ Count,
+ static_cast<Uint16>(ManagerId) );
+ m_CurrentSuballocationOffset += Count;
+
+ return Allocation;
+}
+
+void DynamicSuballocationsManager::Free(DescriptorHeapAllocation&& Allocation)
+{
+ // Do nothing. Dynamic allocations are not disposed individually, but as whole chunks at the end of the frame
+ Allocation = DescriptorHeapAllocation();
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
new file mode 100644
index 00000000..4409abdd
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -0,0 +1,939 @@
+/* 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 "RenderDeviceVkImpl.h"
+#include "DeviceContextVkImpl.h"
+#include "SwapChainVk.h"
+#include "PipelineStateVkImpl.h"
+#include "CommandContext.h"
+#include "TextureVkImpl.h"
+#include "BufferVkImpl.h"
+#include "VulkanTypeConversions.h"
+#include "DynamicUploadHeap.h"
+#include "CommandListVkImpl.h"
+//#include "DXGITypeConversions.h"
+
+namespace Diligent
+{
+
+ DeviceContextVkImpl::DeviceContextVkImpl( IReferenceCounters *pRefCounters, RenderDeviceVkImpl *pDeviceVkImpl, bool bIsDeferred, const EngineVkAttribs &Attribs, Uint32 ContextId) :
+ TDeviceContextBase(pRefCounters, pDeviceVkImpl, bIsDeferred)/*,
+ m_pUploadHeap(pDeviceVkImpl->RequestUploadHeap() ),
+ m_NumCommandsInCurCtx(0),
+ m_NumCommandsToFlush(bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : Attribs.NumCommandsToFlushCmdList),
+ m_pCurrCmdCtx(pDeviceVkImpl->AllocateCommandContext()),
+ m_CommittedIBFormat(VT_UNDEFINED),
+ m_CommittedVkIndexDataStartOffset(0),
+ m_MipsGenerator(pDeviceVkImpl->GetVkDevice()),
+ m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListVkImpl), 64 ),
+ m_ContextId(ContextId)*/
+ {
+#if 0
+ auto *pVkDevice = pDeviceVkImpl->GetVkDevice();
+
+ Vk_COMMAND_SIGNATURE_DESC CmdSignatureDesc = {};
+ Vk_INDIRECT_ARGUMENT_DESC IndirectArg = {};
+ CmdSignatureDesc.NodeMask = 0;
+ CmdSignatureDesc.NumArgumentDescs = 1;
+ CmdSignatureDesc.pArgumentDescs = &IndirectArg;
+
+ CmdSignatureDesc.ByteStride = sizeof(UINT)*4;
+ IndirectArg.Type = Vk_INDIRECT_ARGUMENT_TYPE_DRAW;
+ auto hr = pVkDevice->CreateCommandSignature(&CmdSignatureDesc, nullptr, __uuidof(m_pDrawIndirectSignature), reinterpret_cast<void**>(static_cast<IVkCommandSignature**>(&m_pDrawIndirectSignature)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create indirect draw command signature")
+
+ CmdSignatureDesc.ByteStride = sizeof(UINT)*5;
+ IndirectArg.Type = Vk_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
+ hr = pVkDevice->CreateCommandSignature(&CmdSignatureDesc, nullptr, __uuidof(m_pDrawIndexedIndirectSignature), reinterpret_cast<void**>(static_cast<IVkCommandSignature**>(&m_pDrawIndexedIndirectSignature)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create draw indexed indirect command signature")
+
+ CmdSignatureDesc.ByteStride = sizeof(UINT)*3;
+ IndirectArg.Type = Vk_INDIRECT_ARGUMENT_TYPE_DISPATCH;
+ hr = pVkDevice->CreateCommandSignature(&CmdSignatureDesc, nullptr, __uuidof(m_pDispatchIndirectSignature), reinterpret_cast<void**>(static_cast<IVkCommandSignature**>(&m_pDispatchIndirectSignature)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create dispatch indirect command signature")
+#endif
+ }
+
+ DeviceContextVkImpl::~DeviceContextVkImpl()
+ {
+#if 0
+ if(m_bIsDeferred)
+ ValidatedCast<RenderDeviceVkImpl>(m_pDevice.RawPtr())->DisposeCommandContext(m_pCurrCmdCtx);
+ else
+ {
+ if (m_NumCommandsInCurCtx != 0)
+ LOG_WARNING_MESSAGE("Flusing outstanding commands from the device context being destroyed. This may result in Vk synchronization errors");
+
+ Flush(false);
+ }
+#endif
+ }
+
+ IMPLEMENT_QUERY_INTERFACE( DeviceContextVkImpl, IID_DeviceContextVk, TDeviceContextBase )
+
+ void DeviceContextVkImpl::SetPipelineState(IPipelineState *pPipelineState)
+ {
+#if 0
+ // Never flush deferred context!
+ if (!m_bIsDeferred && m_NumCommandsInCurCtx >= m_NumCommandsToFlush)
+ {
+ Flush(true);
+ }
+
+ auto *pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState);
+ const auto &PSODesc = pPipelineStateVk->GetDesc();
+
+ bool CommitStates = false;
+ bool CommitScissor = false;
+ if(!m_pPipelineState)
+ {
+ // If no pipeline state is bound, we are working with the fresh command
+ // list. We have to commit the states set in the context that are not
+ // committed by the draw command (render targets, viewports, scissor rects, etc.)
+ CommitStates = true;
+ }
+ else
+ {
+ const auto& OldPSODesc = m_pPipelineState->GetDesc();
+ // Commit all graphics states when switching from compute pipeline
+ // This is necessary because if the command list had been flushed
+ // and the first PSO set on the command list was a compute pipeline,
+ // the states would otherwise never be committed (since m_pPipelineState != nullptr)
+ CommitStates = OldPSODesc.IsComputePipeline;
+ // We also need to update scissor rect if ScissorEnable state has changed
+ CommitScissor = OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable != PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable;
+ }
+
+ TDeviceContextBase::SetPipelineState( pPipelineState );
+
+ auto *pCmdCtx = RequestCmdContext();
+
+ auto *pVkPSO = pPipelineStateVk->GetVkPipelineState();
+ if (PSODesc.IsComputePipeline)
+ {
+ pCmdCtx->AsComputeContext().SetPipelineState(pVkPSO);
+ }
+ else
+ {
+ auto &GraphicsCtx = pCmdCtx->AsGraphicsContext();
+ GraphicsCtx.SetPipelineState(pVkPSO);
+
+ if(CommitStates)
+ {
+ GraphicsCtx.SetStencilRef(m_StencilRef);
+ GraphicsCtx.SetBlendFactor(m_BlendFactors);
+ CommitRenderTargets();
+ CommitViewports();
+ }
+
+ if(CommitStates || CommitScissor)
+ {
+ CommitScissorRects(GraphicsCtx, PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable);
+ }
+ }
+ m_pCommittedResourceCache = nullptr;
+#endif
+ }
+
+ void DeviceContextVkImpl::TransitionShaderResources(IPipelineState *pPipelineState, IShaderResourceBinding *pShaderResourceBinding)
+ {
+#if 0
+ VERIFY_EXPR(pPipelineState != nullptr);
+
+ auto *pCtx = RequestCmdContext();
+ auto *pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState);
+ pPipelineStateVk->CommitAndTransitionShaderResources(pShaderResourceBinding, *pCtx, false, true);
+#endif
+ }
+
+ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding *pShaderResourceBinding, Uint32 Flags)
+ {
+ if (!DeviceContextBase::CommitShaderResources<PipelineStateVkImpl>(pShaderResourceBinding, Flags, 0 /*Dummy*/))
+ return;
+#if 0
+ auto *pCtx = RequestCmdContext();
+ auto *pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
+
+ m_pCommittedResourceCache = pPipelineStateVk->CommitAndTransitionShaderResources(pShaderResourceBinding, *pCtx, true, (Flags & COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES)!=0);
+#endif
+ }
+
+ void DeviceContextVkImpl::SetStencilRef(Uint32 StencilRef)
+ {
+ if (TDeviceContextBase::SetStencilRef(StencilRef, 0))
+ {
+#if 0
+ RequestCmdContext()->AsGraphicsContext().SetStencilRef( m_StencilRef );
+#endif
+ }
+ }
+
+ void DeviceContextVkImpl::SetBlendFactors(const float* pBlendFactors)
+ {
+ if (TDeviceContextBase::SetBlendFactors(m_BlendFactors, 0))
+ {
+#if 0
+ RequestCmdContext()->AsGraphicsContext().SetBlendFactor( m_BlendFactors );
+#endif
+ }
+ }
+
+#if 0
+ void DeviceContextVkImpl::CommitVkIndexBuffer(VALUE_TYPE IndexType)
+ {
+ VERIFY( m_pIndexBuffer != nullptr, "Index buffer is not set up for indexed draw command" );
+
+ Vk_INDEX_BUFFER_VIEW IBView;
+ BufferVkImpl *pBuffVk = static_cast<BufferVkImpl *>(m_pIndexBuffer.RawPtr());
+ IBView.BufferLocation = pBuffVk->GetGPUAddress(m_ContextId) + m_IndexDataStartOffset;
+ if( IndexType == VT_UINT32 )
+ IBView.Format = DXGI_FORMAT_R32_UINT;
+ else if( IndexType == VT_UINT16 )
+ IBView.Format = DXGI_FORMAT_R16_UINT;
+ else
+ {
+ UNEXPECTED( "Unsupported index format. Only R16_UINT and R32_UINT are allowed." );
+ }
+ // Note that for a dynamic buffer, what we use here is the size of the buffer itself, not the upload heap buffer!
+ IBView.SizeInBytes = pBuffVk->GetDesc().uiSizeInBytes - m_IndexDataStartOffset;
+
+ // Device context keeps strong reference to bound index buffer.
+ // When the buffer is unbound, the reference to the Vk resource
+ // is added to the context. There is no need to add reference here
+ //auto &GraphicsCtx = RequestCmdContext()->AsGraphicsContext();
+ //auto *pVkResource = pBuffVk->GetVkBuffer();
+ //GraphicsCtx.AddReferencedObject(pVkResource);
+
+ bool IsDynamic = pBuffVk->GetDesc().Usage == USAGE_DYNAMIC;
+#ifdef _DEBUG
+ if(IsDynamic)
+ pBuffVk->DbgVerifyDynamicAllocation(m_ContextId);
+#endif
+ auto &GraphicsCtx = RequestCmdContext()->AsGraphicsContext();
+ // Resource transitioning must always be performed!
+ GraphicsCtx.TransitionResource(pBuffVk, Vk_RESOURCE_STATE_INDEX_BUFFER, true);
+
+ size_t BuffDataStartByteOffset;
+ auto *pVkBuff = pBuffVk->GetVkBuffer(BuffDataStartByteOffset, m_ContextId);
+
+ if( IsDynamic ||
+ m_CommittedVkIndexBuffer != pVkBuff ||
+ m_CommittedIBFormat != IndexType ||
+ m_CommittedVkIndexDataStartOffset != m_IndexDataStartOffset + BuffDataStartByteOffset)
+ {
+ m_CommittedVkIndexBuffer = pVkBuff;
+ m_CommittedIBFormat = IndexType;
+ m_CommittedVkIndexDataStartOffset = m_IndexDataStartOffset + static_cast<Uint32>(BuffDataStartByteOffset);
+ GraphicsCtx.SetIndexBuffer( IBView );
+ }
+
+ // GPU virtual address of a dynamic index buffer can change every time
+ // a draw command is invoked
+ m_bCommittedVkIBUpToDate = !IsDynamic;
+ }
+
+ void DeviceContextVkImpl::TransitionVkVertexBuffers(GraphicsContext &GraphCtx)
+ {
+ for( UINT Buff = 0; Buff < m_NumVertexStreams; ++Buff )
+ {
+ auto &CurrStream = m_VertexStreams[Buff];
+ VERIFY( CurrStream.pBuffer, "Attempting to bind a null buffer for rendering" );
+ auto *pBufferVk = static_cast<BufferVkImpl*>(CurrStream.pBuffer.RawPtr());
+ if(!pBufferVk->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER))
+ GraphCtx.TransitionResource(pBufferVk, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
+ }
+ }
+
+ void DeviceContextVkImpl::CommitVkVertexBuffers(GraphicsContext &GraphCtx)
+ {
+ auto *pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
+
+ // Do not initialize array with zeroes for performance reasons
+ Vk_VERTEX_BUFFER_VIEW VBViews[MaxBufferSlots];// = {}
+ VERIFY( m_NumVertexStreams <= MaxBufferSlots, "Too many buffers are being set" );
+ const auto *TightStrides = pPipelineStateVk->GetTightStrides();
+ bool DynamicBufferPresent = false;
+ for( UINT Buff = 0; Buff < m_NumVertexStreams; ++Buff )
+ {
+ auto &CurrStream = m_VertexStreams[Buff];
+ auto &VBView = VBViews[Buff];
+ VERIFY( CurrStream.pBuffer, "Attempting to bind a null buffer for rendering" );
+
+ auto *pBufferVk = static_cast<BufferVkImpl*>(CurrStream.pBuffer.RawPtr());
+ if (pBufferVk->GetDesc().Usage == USAGE_DYNAMIC)
+ {
+ DynamicBufferPresent = true;
+#ifdef _DEBUG
+ pBufferVk->DbgVerifyDynamicAllocation(m_ContextId);
+#endif
+ }
+
+ GraphCtx.TransitionResource(pBufferVk, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
+
+ // Device context keeps strong references to all vertex buffers.
+ // When a buffer is unbound, a reference to Vk resource is added to the context,
+ // so there is no need to reference the resource here
+ //GraphicsCtx.AddReferencedObject(pVkResource);
+
+ VBView.BufferLocation = pBufferVk->GetGPUAddress(m_ContextId) + CurrStream.Offset;
+ VBView.StrideInBytes = CurrStream.Stride ? CurrStream.Stride : TightStrides[Buff];
+ // Note that for a dynamic buffer, what we use here is the size of the buffer itself, not the upload heap buffer!
+ VBView.SizeInBytes = pBufferVk->GetDesc().uiSizeInBytes - CurrStream.Offset;
+ }
+
+ GraphCtx.FlushResourceBarriers();
+ GraphCtx.SetVertexBuffers( 0, m_NumVertexStreams, VBViews );
+
+ // GPU virtual address of a dynamic vertex buffer can change every time
+ // a draw command is invoked
+ m_bCommittedVkVBsUpToDate = !DynamicBufferPresent;
+ }
+#endif
+
+ void DeviceContextVkImpl::Draw( DrawAttribs &DrawAttribs )
+ {
+#ifdef _DEBUG
+ if (!m_pPipelineState)
+ {
+ LOG_ERROR("No pipeline state is bound");
+ return;
+ }
+ if (m_pPipelineState->GetDesc().IsComputePipeline)
+ {
+ LOG_ERROR("No graphics pipeline state is bound");
+ return;
+ }
+#endif
+
+#if 0
+ auto &GraphCtx = RequestCmdContext()->AsGraphicsContext();
+ if( DrawAttribs.IsIndexed )
+ {
+ if( m_CommittedIBFormat != DrawAttribs.IndexType )
+ m_bCommittedVkIBUpToDate = false;
+
+ if(m_bCommittedVkIBUpToDate)
+ {
+ BufferVkImpl *pBuffVk = static_cast<BufferVkImpl *>(m_pIndexBuffer.RawPtr());
+ if(!pBuffVk->CheckAllStates(Vk_RESOURCE_STATE_INDEX_BUFFER))
+ GraphCtx.TransitionResource(pBuffVk, Vk_RESOURCE_STATE_INDEX_BUFFER, true);
+ }
+ else
+ CommitVkIndexBuffer(DrawAttribs.IndexType);
+ }
+
+ auto *pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
+
+ auto VkTopology = TopologyToVkTopology( DrawAttribs.Topology );
+ GraphCtx.SetPrimitiveTopology(VkTopology);
+
+ if(m_bCommittedVkVBsUpToDate)
+ TransitionVkVertexBuffers(GraphCtx);
+ else
+ CommitVkVertexBuffers(GraphCtx);
+
+ GraphCtx.SetRootSignature( pPipelineStateVk->GetVkRootSignature() );
+
+ if(m_pCommittedResourceCache != nullptr)
+ {
+ pPipelineStateVk->GetRootSignature().CommitRootViews(*m_pCommittedResourceCache, GraphCtx, false, m_ContextId);
+ }
+#ifdef _DEBUG
+ else
+ {
+ if( pPipelineStateVk->dbgContainsShaderResources() )
+ LOG_ERROR_MESSAGE("Pipeline state \"", pPipelineStateVk->GetDesc().Name, "\" contains shader resources, but IDeviceContext::CommitShaderResources() was not called" );
+ }
+#endif
+
+
+ if( DrawAttribs.IsIndirect )
+ {
+ if( auto *pBufferVk = ValidatedCast<BufferVkImpl>(DrawAttribs.pIndirectDrawAttribs) )
+ {
+#ifdef _DEBUG
+ if(pBufferVk->GetDesc().Usage == USAGE_DYNAMIC)
+ pBufferVk->DbgVerifyDynamicAllocation(m_ContextId);
+#endif
+
+ GraphCtx.TransitionResource(pBufferVk, Vk_RESOURCE_STATE_INDIRECT_ARGUMENT);
+ size_t BuffDataStartByteOffset;
+ IVkResource *pVkArgsBuff = pBufferVk->GetVkBuffer(BuffDataStartByteOffset, m_ContextId);
+ GraphCtx.ExecuteIndirect(DrawAttribs.IsIndexed ? m_pDrawIndexedIndirectSignature : m_pDrawIndirectSignature, pVkArgsBuff, DrawAttribs.IndirectDrawArgsOffset + BuffDataStartByteOffset);
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Valid pIndirectDrawAttribs must be provided for indirect draw command");
+ }
+ }
+ else
+ {
+ if( DrawAttribs.IsIndexed )
+ GraphCtx.DrawIndexed(DrawAttribs.NumIndices, DrawAttribs.NumInstances, DrawAttribs.FirstIndexLocation, DrawAttribs.BaseVertex, DrawAttribs.FirstInstanceLocation);
+ else
+ GraphCtx.Draw(DrawAttribs.NumVertices, DrawAttribs.NumInstances, DrawAttribs.StartVertexLocation, DrawAttribs.FirstInstanceLocation );
+ }
+#endif
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::DispatchCompute( const DispatchComputeAttribs &DispatchAttrs )
+ {
+#ifdef _DEBUG
+ if (!m_pPipelineState)
+ {
+ LOG_ERROR("No pipeline state is bound");
+ return;
+ }
+ if (!m_pPipelineState->GetDesc().IsComputePipeline)
+ {
+ LOG_ERROR("No compute pipeline state is bound");
+ return;
+ }
+#endif
+
+#if 0
+ auto *pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(m_pPipelineState.RawPtr());
+
+ auto &ComputeCtx = RequestCmdContext()->AsComputeContext();
+ ComputeCtx.SetRootSignature( pPipelineStateVk->GetVkRootSignature() );
+
+ if(m_pCommittedResourceCache != nullptr)
+ {
+ pPipelineStateVk->GetRootSignature().CommitRootViews(*m_pCommittedResourceCache, ComputeCtx, true, m_ContextId);
+ }
+#ifdef _DEBUG
+ else
+ {
+ if( pPipelineStateVk->dbgContainsShaderResources() )
+ LOG_ERROR_MESSAGE("Pipeline state \"", pPipelineStateVk->GetDesc().Name, "\" contains shader resources, but IDeviceContext::CommitShaderResources() was not called" );
+ }
+#endif
+
+ if( DispatchAttrs.pIndirectDispatchAttribs )
+ {
+ if( auto *pBufferVk = ValidatedCast<BufferVkImpl>(DispatchAttrs.pIndirectDispatchAttribs) )
+ {
+#ifdef _DEBUG
+ if(pBufferVk->GetDesc().Usage == USAGE_DYNAMIC)
+ pBufferVk->DbgVerifyDynamicAllocation(m_ContextId);
+#endif
+
+ ComputeCtx.TransitionResource(pBufferVk, Vk_RESOURCE_STATE_INDIRECT_ARGUMENT);
+ size_t BuffDataStartByteOffset;
+ IVkResource *pVkArgsBuff = pBufferVk->GetVkBuffer(BuffDataStartByteOffset, m_ContextId);
+ ComputeCtx.ExecuteIndirect(m_pDispatchIndirectSignature, pVkArgsBuff, DispatchAttrs.DispatchArgsByteOffset + BuffDataStartByteOffset);
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Valid pIndirectDrawAttribs must be provided for indirect dispatch command");
+ }
+ }
+ else
+ ComputeCtx.Dispatch(DispatchAttrs.ThreadGroupCountX, DispatchAttrs.ThreadGroupCountY, DispatchAttrs.ThreadGroupCountZ);
+#endif
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::ClearDepthStencil( ITextureView *pView, Uint32 ClearFlags, float fDepth, Uint8 Stencil )
+ {
+#if 0
+ ITextureViewVk *pDSVVk = nullptr;
+ if( pView != nullptr )
+ {
+ pDSVVk = ValidatedCast<ITextureViewVk>(pView);
+#ifdef _DEBUG
+ const auto& ViewDesc = pDSVVk->GetDesc();
+ VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL, "Incorrect view type: depth stencil is expected" );
+#endif
+ }
+ else
+ {
+ if (m_pSwapChain)
+ {
+ pDSVVk = ValidatedCast<ISwapChainVk>(m_pSwapChain.RawPtr())->GetDepthBufferDSV();
+ }
+ else
+ {
+ LOG_ERROR("Failed to clear default depth stencil buffer: swap chain is not initialized in the device context");
+ return;
+ }
+ }
+ Vk_CLEAR_FLAGS VkClearFlags = (Vk_CLEAR_FLAGS)0;
+ if( ClearFlags & CLEAR_DEPTH_FLAG ) VkClearFlags |= Vk_CLEAR_FLAG_DEPTH;
+ if( ClearFlags & CLEAR_STENCIL_FLAG ) VkClearFlags |= Vk_CLEAR_FLAG_STENCIL;
+ // The full extent of the resource view is always cleared.
+ // Viewport and scissor settings are not applied??
+ RequestCmdContext()->AsGraphicsContext().ClearDepthStencil( pDSVVk, VkClearFlags, fDepth, Stencil );
+#endif
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::ClearRenderTarget( ITextureView *pView, const float *RGBA )
+ {
+#if 0
+ ITextureViewVk *pVkRTV = nullptr;
+ if( pView != nullptr )
+ {
+#ifdef _DEBUG
+ const auto& ViewDesc = pView->GetDesc();
+ VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET, "Incorrect view type: render target is expected" );
+#endif
+ pVkRTV = ValidatedCast<ITextureViewVk>(pView);
+ }
+ else
+ {
+ if (m_pSwapChain)
+ {
+ pVkRTV = ValidatedCast<ISwapChainVk>(m_pSwapChain.RawPtr())->GetCurrentBackBufferRTV();
+ }
+ else
+ {
+ LOG_ERROR("Failed to clear default render target: swap chain is not initialized in the device context");
+ return;
+ }
+ }
+
+ static constexpr float Zero[4] = { 0.f, 0.f, 0.f, 0.f };
+ if( RGBA == nullptr )
+ RGBA = Zero;
+
+ // The full extent of the resource view is always cleared.
+ // Viewport and scissor settings are not applied??
+ RequestCmdContext()->AsGraphicsContext().ClearRenderTarget( pVkRTV, RGBA );
+#endif
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::Flush(bool RequestNewCmdCtx)
+ {
+#if 0
+ auto pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(m_pDevice.RawPtr());
+ if( m_pCurrCmdCtx )
+ {
+ VERIFY(!m_bIsDeferred, "Deferred contexts cannot execute command lists directly");
+ if (m_NumCommandsInCurCtx != 0)
+ {
+ m_pCurrCmdCtx->FlushResourceBarriers();
+ pDeviceVkImpl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true);
+ }
+ else
+ pDeviceVkImpl->DisposeCommandContext(m_pCurrCmdCtx);
+ }
+
+ m_pCurrCmdCtx = RequestNewCmdCtx ? pDeviceVkImpl->AllocateCommandContext() : nullptr;
+ m_NumCommandsInCurCtx = 0;
+
+ m_CommittedVkIndexBuffer = nullptr;
+ m_CommittedVkIndexDataStartOffset = 0;
+ m_CommittedIBFormat = VT_UNDEFINED;
+ m_bCommittedVkVBsUpToDate = false;
+ m_bCommittedVkIBUpToDate = false;
+
+ m_pPipelineState.Release();
+#endif
+ }
+
+ void DeviceContextVkImpl::Flush()
+ {
+ VERIFY(!m_bIsDeferred, "Flush() should only be called for immediate contexts");
+#if 0
+ Flush(true);
+#endif
+ }
+
+ void DeviceContextVkImpl::SetVertexBuffers( Uint32 StartSlot, Uint32 NumBuffersSet, IBuffer **ppBuffers, Uint32 *pStrides, Uint32 *pOffsets, Uint32 Flags )
+ {
+ TDeviceContextBase::SetVertexBuffers( StartSlot, NumBuffersSet, ppBuffers, pStrides, pOffsets, Flags );
+#if 0
+ m_bCommittedVkVBsUpToDate = false;
+#endif
+ }
+
+ void DeviceContextVkImpl::InvalidateState()
+ {
+ if (m_NumCommandsInCurCtx != 0)
+ LOG_WARNING_MESSAGE("Invalidating context that has outstanding commands in it. Call Flush() to submit commands for execution");
+
+ TDeviceContextBase::InvalidateState();
+#if 0
+ m_CommittedVkIndexBuffer = nullptr;
+ m_CommittedVkIndexDataStartOffset = 0;
+ m_CommittedIBFormat = VT_UNDEFINED;
+ m_bCommittedVkVBsUpToDate = false;
+ m_bCommittedVkIBUpToDate = false;
+#endif
+ }
+
+ void DeviceContextVkImpl::SetIndexBuffer( IBuffer *pIndexBuffer, Uint32 ByteOffset )
+ {
+ TDeviceContextBase::SetIndexBuffer( pIndexBuffer, ByteOffset );
+#if 0
+ m_bCommittedVkIBUpToDate = false;
+#endif
+ }
+
+#if 0
+ void DeviceContextVkImpl::CommitViewports()
+ {
+ constexpr Uint32 MaxViewports = Vk_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ Vk_VIEWPORT VkViewports[MaxViewports]; // Do not waste time initializing array to zero
+
+ for( Uint32 vp = 0; vp < m_NumViewports; ++vp )
+ {
+ VkViewports[vp].TopLeftX = m_Viewports[vp].TopLeftX;
+ VkViewports[vp].TopLeftY = m_Viewports[vp].TopLeftY;
+ VkViewports[vp].Width = m_Viewports[vp].Width;
+ VkViewports[vp].Height = m_Viewports[vp].Height;
+ VkViewports[vp].MinDepth = m_Viewports[vp].MinDepth;
+ VkViewports[vp].MaxDepth = m_Viewports[vp].MaxDepth;
+ }
+ // All viewports must be set atomically as one operation.
+ // Any viewports not defined by the call are disabled.
+ RequestCmdContext()->AsGraphicsContext().SetViewports( m_NumViewports, VkViewports );
+ }
+#endif
+ void DeviceContextVkImpl::SetViewports( Uint32 NumViewports, const Viewport *pViewports, Uint32 RTWidth, Uint32 RTHeight )
+ {
+#if 0
+ constexpr Uint32 MaxViewports = Vk_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ VERIFY( NumViewports < MaxViewports, "Too many viewports are being set" );
+ NumViewports = std::min( NumViewports, MaxViewports );
+
+ TDeviceContextBase::SetViewports( NumViewports, pViewports, RTWidth, RTHeight );
+ VERIFY( NumViewports == m_NumViewports, "Unexpected number of viewports" );
+
+ CommitViewports();
+#endif
+ }
+
+#if 0
+ constexpr LONG MaxVkTexDim = Vk_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+ constexpr Uint32 MaxVkScissorRects = Vk_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ static constexpr RECT MaxVkTexSizeRects[Vk_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE] =
+ {
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim },
+ { 0,0, MaxVkTexDim,MaxVkTexDim }
+ };
+
+ void DeviceContextVkImpl::CommitScissorRects(GraphicsContext &GraphCtx, bool ScissorEnable)
+ {
+ if (ScissorEnable)
+ {
+ // Commit currently set scissor rectangles
+ Vk_RECT VkScissorRects[MaxVkScissorRects]; // Do not waste time initializing array with zeroes
+ for (Uint32 sr = 0; sr < m_NumScissorRects; ++sr)
+ {
+ VkScissorRects[sr].left = m_ScissorRects[sr].left;
+ VkScissorRects[sr].top = m_ScissorRects[sr].top;
+ VkScissorRects[sr].right = m_ScissorRects[sr].right;
+ VkScissorRects[sr].bottom = m_ScissorRects[sr].bottom;
+ }
+ GraphCtx.SetScissorRects(m_NumScissorRects, VkScissorRects);
+ }
+ else
+ {
+ // Disable scissor rectangles
+ static_assert(_countof(MaxVkTexSizeRects) == MaxVkScissorRects, "Unexpected array size");
+ GraphCtx.SetScissorRects(MaxVkScissorRects, MaxVkTexSizeRects);
+ }
+ }
+#endif
+
+ void DeviceContextVkImpl::SetScissorRects( Uint32 NumRects, const Rect *pRects, Uint32 RTWidth, Uint32 RTHeight )
+ {
+#if 0
+ const Uint32 MaxScissorRects = Vk_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ VERIFY( NumRects < MaxScissorRects, "Too many scissor rects are being set" );
+ NumRects = std::min( NumRects, MaxScissorRects );
+
+ TDeviceContextBase::SetScissorRects(NumRects, pRects, RTWidth, RTHeight);
+
+ // Only commit scissor rects if scissor test is enabled in the rasterizer state.
+ // If scissor is currently disabled, or no PSO is bound, scissor rects will be committed by
+ // the SetPipelineState() when a PSO with enabled scissor test is set.
+ if( m_pPipelineState )
+ {
+ const auto &PSODesc = m_pPipelineState->GetDesc();
+ if(!PSODesc.IsComputePipeline && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable)
+ {
+ VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects");
+ auto &Ctx = RequestCmdContext()->AsGraphicsContext();
+ CommitScissorRects(Ctx, true);
+ }
+ }
+#endif
+ }
+
+
+#if 0
+ void DeviceContextVkImpl::CommitRenderTargets()
+ {
+ const Uint32 MaxVkRTs = Vk_SIMULTANEOUS_RENDER_TARGET_COUNT;
+ Uint32 NumRenderTargets = m_NumBoundRenderTargets;
+ VERIFY( NumRenderTargets <= MaxVkRTs, "Vk only allows 8 simultaneous render targets" );
+ NumRenderTargets = std::min( MaxVkRTs, NumRenderTargets );
+
+ ITextureViewVk *ppRTVs[MaxVkRTs]; // Do not initialize with zeroes!
+ ITextureViewVk *pDSV = nullptr;
+ if( m_IsDefaultFramebufferBound )
+ {
+ if (m_pSwapChain)
+ {
+ NumRenderTargets = 1;
+ auto *pSwapChainVk = ValidatedCast<ISwapChainVk>(m_pSwapChain.RawPtr());
+ ppRTVs[0] = pSwapChainVk->GetCurrentBackBufferRTV();
+ pDSV = pSwapChainVk->GetDepthBufferDSV();
+ }
+ else
+ {
+ LOG_WARNING_MESSAGE("Failed to bind default render targets and depth-stencil buffer: swap chain is not initialized in the device context");
+ return;
+ }
+ }
+ else
+ {
+ for( Uint32 rt = 0; rt < NumRenderTargets; ++rt )
+ ppRTVs[rt] = ValidatedCast<ITextureViewVk>(m_pBoundRenderTargets[rt].RawPtr());
+ pDSV = ValidatedCast<ITextureViewVk>(m_pBoundDepthStencil.RawPtr());
+ }
+ RequestCmdContext()->AsGraphicsContext().SetRenderTargets(NumRenderTargets, ppRTVs, pDSV);
+ }
+#endif
+ void DeviceContextVkImpl::SetRenderTargets( Uint32 NumRenderTargets, ITextureView *ppRenderTargets[], ITextureView *pDepthStencil )
+ {
+ if( TDeviceContextBase::SetRenderTargets( NumRenderTargets, ppRenderTargets, pDepthStencil ) )
+ {
+#if 0
+ CommitRenderTargets();
+
+ // Set the viewport to match the render target size
+ SetViewports(1, nullptr, 0, 0);
+#endif
+ }
+ }
+
+#if 0
+ DynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(size_t NumBytes)
+ {
+ return m_pUploadHeap->Allocate(NumBytes);
+ }
+#endif
+
+#if 0
+ void DeviceContextVkImpl::UpdateBufferRegion(class BufferVkImpl *pBuffVk, DynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes)
+ {
+ auto pCmdCtx = RequestCmdContext();
+ VERIFY_EXPR( static_cast<size_t>(NumBytes) == NumBytes );
+ pCmdCtx->TransitionResource(pBuffVk, Vk_RESOURCE_STATE_COPY_DEST, true);
+ size_t DstBuffDataStartByteOffset;
+ auto *pVkBuff = pBuffVk->GetVkBuffer(DstBuffDataStartByteOffset, m_ContextId);
+ VERIFY(DstBuffDataStartByteOffset == 0, "Dst buffer must not be suballocated");
+ pCmdCtx->GetCommandList()->CopyBufferRegion( pVkBuff, DstOffset + DstBuffDataStartByteOffset, Allocation.pBuffer, Allocation.Offset, NumBytes);
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl *pBuffVk, const void *pData, Uint64 DstOffset, Uint64 NumBytes)
+ {
+ VERIFY(pBuffVk->GetDesc().Usage != USAGE_DYNAMIC, "Dynamic buffers must be updated via Map()");
+ VERIFY_EXPR( static_cast<size_t>(NumBytes) == NumBytes );
+ auto TmpSpace = m_pUploadHeap->Allocate(static_cast<size_t>(NumBytes));
+ memcpy(TmpSpace.CPUAddress, pData, static_cast<size_t>(NumBytes));
+ UpdateBufferRegion(pBuffVk, TmpSpace, DstOffset, NumBytes);
+ }
+#endif
+
+#if 0
+ void DeviceContextVkImpl::CopyBufferRegion(BufferVkImpl *pSrcBuffVk, BufferVkImpl *pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes)
+ {
+ VERIFY(pDstBuffVk->GetDesc().Usage != USAGE_DYNAMIC, "Dynamic buffers cannot be copy destinations");
+
+ auto pCmdCtx = RequestCmdContext();
+ pCmdCtx->TransitionResource(pSrcBuffVk, Vk_RESOURCE_STATE_COPY_SOURCE);
+ pCmdCtx->TransitionResource(pDstBuffVk, Vk_RESOURCE_STATE_COPY_DEST, true);
+ size_t DstDataStartByteOffset;
+ auto *pVkDstBuff = pDstBuffVk->GetVkBuffer(DstDataStartByteOffset, m_ContextId);
+ VERIFY(DstDataStartByteOffset == 0, "Dst buffer must not be suballocated");
+
+ size_t SrcDataStartByteOffset;
+ auto *pVkSrcBuff = pSrcBuffVk->GetVkBuffer(SrcDataStartByteOffset, m_ContextId);
+ pCmdCtx->GetCommandList()->CopyBufferRegion( pVkDstBuff, DstOffset + DstDataStartByteOffset, pVkSrcBuff, SrcOffset+SrcDataStartByteOffset, NumBytes);
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::CopyTextureRegion(TextureVkImpl *pSrcTexture, Uint32 SrcSubResIndex, const Vk_BOX *pVkSrcBox,
+ TextureVkImpl *pDstTexture, Uint32 DstSubResIndex, Uint32 DstX, Uint32 DstY, Uint32 DstZ)
+ {
+ auto pCmdCtx = RequestCmdContext();
+ pCmdCtx->TransitionResource(pSrcTexture, Vk_RESOURCE_STATE_COPY_SOURCE);
+ pCmdCtx->TransitionResource(pDstTexture, Vk_RESOURCE_STATE_COPY_DEST, true);
+
+ Vk_TEXTURE_COPY_LOCATION DstLocation = {}, SrcLocation = {};
+
+ DstLocation.Type = Vk_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ DstLocation.pResource = pDstTexture->GetVkResource();
+ DstLocation.SubresourceIndex = DstSubResIndex;
+
+ SrcLocation.Type = Vk_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ SrcLocation.pResource = pSrcTexture->GetVkResource();
+ SrcLocation.SubresourceIndex = SrcSubResIndex;
+
+ pCmdCtx->GetCommandList()->CopyTextureRegion( &DstLocation, DstX, DstY, DstZ, &SrcLocation, pVkSrcBox);
+ ++m_NumCommandsInCurCtx;
+ }
+
+ void DeviceContextVkImpl::CopyTextureRegion(IBuffer *pSrcBuffer, Uint32 SrcStride, Uint32 SrcDepthStride, class TextureVkImpl *pTextureVk, Uint32 DstSubResIndex, const Box &DstBox)
+ {
+ auto *pBufferVk = ValidatedCast<BufferVkImpl>(pSrcBuffer);
+ const auto& TexDesc = pTextureVk->GetDesc();
+ VERIFY(pBufferVk->GetState() == Vk_RESOURCE_STATE_GENERIC_READ, "Staging buffer is expected to always be in Vk_RESOURCE_STATE_GENERIC_READ state");
+
+ auto *pCmdCtx = RequestCmdContext();
+ auto *pCmdList = pCmdCtx->GetCommandList();
+ auto TextureState = pTextureVk->GetState();
+ Vk_RESOURCE_BARRIER BarrierDesc;
+ BarrierDesc.Type = Vk_RESOURCE_BARRIER_TYPE_TRANSITION;
+ BarrierDesc.Transition.pResource = pTextureVk->GetVkResource();
+ BarrierDesc.Transition.Subresource = DstSubResIndex;
+ BarrierDesc.Transition.StateBefore = TextureState;
+ BarrierDesc.Transition.StateAfter = Vk_RESOURCE_STATE_COPY_DEST;
+ BarrierDesc.Flags = Vk_RESOURCE_BARRIER_FLAG_NONE;
+ bool StateTransitionRequired = (TextureState & Vk_RESOURCE_STATE_COPY_DEST) != Vk_RESOURCE_STATE_COPY_DEST;
+ if (StateTransitionRequired)
+ pCmdList->ResourceBarrier(1, &BarrierDesc);
+
+ Vk_TEXTURE_COPY_LOCATION DstLocation;
+ DstLocation.Type = Vk_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ DstLocation.pResource = pTextureVk->GetVkResource();
+ DstLocation.SubresourceIndex = static_cast<UINT>(DstSubResIndex);
+
+ Vk_TEXTURE_COPY_LOCATION SrcLocation;
+ SrcLocation.Type = Vk_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ SrcLocation.pResource = pBufferVk->GetVkResource();
+ Vk_PLACED_SUBRESOURCE_FOOTPRINT &Footpring = SrcLocation.PlacedFootprint;
+ Footpring.Offset = 0;
+ Footpring.Footprint.Width = static_cast<UINT>(DstBox.MaxX - DstBox.MinX);
+ Footpring.Footprint.Height = static_cast<UINT>(DstBox.MaxY - DstBox.MinY);
+ Footpring.Footprint.Depth = static_cast<UINT>(DstBox.MaxZ - DstBox.MinZ); // Depth cannot be 0
+ Footpring.Footprint.Format = TexFormatToDXGI_Format(TexDesc.Format);
+
+ Footpring.Footprint.RowPitch = static_cast<UINT>(SrcStride);
+ VERIFY(Footpring.Footprint.RowPitch * Footpring.Footprint.Height * Footpring.Footprint.Depth <= pBufferVk->GetDesc().uiSizeInBytes, "Buffer is not large enough");
+ VERIFY(SrcDepthStride == 0 || static_cast<UINT>(SrcDepthStride) == Footpring.Footprint.RowPitch * Footpring.Footprint.Height, "Depth stride must be equal to the size 2D level");
+
+ Vk_BOX VkSrcBox;
+ VkSrcBox.left = 0;
+ VkSrcBox.right = Footpring.Footprint.Width;
+ VkSrcBox.top = 0;
+ VkSrcBox.bottom = Footpring.Footprint.Height;
+ VkSrcBox.front = 0;
+ VkSrcBox.back = Footpring.Footprint.Depth;
+ pCmdCtx->GetCommandList()->CopyTextureRegion( &DstLocation,
+ static_cast<UINT>( DstBox.MinX ),
+ static_cast<UINT>( DstBox.MinY ),
+ static_cast<UINT>( DstBox.MinZ ),
+ &SrcLocation, &VkSrcBox);
+
+ ++m_NumCommandsInCurCtx;
+
+ if (StateTransitionRequired)
+ {
+ std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
+ pCmdList->ResourceBarrier(1, &BarrierDesc);
+ }
+ }
+#endif
+ void DeviceContextVkImpl::GenerateMips(TextureViewVkImpl *pTexView)
+ {
+#if 0
+ auto *pCtx = RequestCmdContext();
+ m_MipsGenerator.GenerateMips(ValidatedCast<RenderDeviceVkImpl>(m_pDevice.RawPtr()), pTexView, *pCtx);
+ ++m_NumCommandsInCurCtx;
+#endif
+ }
+
+ void DeviceContextVkImpl::FinishCommandList(class ICommandList **ppCommandList)
+ {
+#if 0
+ CommandListVkImpl *pCmdListVk( NEW_RC_OBJ(m_CmdListAllocator, "CommandListVkImpl instance", CommandListVkImpl)
+ (m_pDevice, m_pCurrCmdCtx) );
+ pCmdListVk->QueryInterface( IID_CommandList, reinterpret_cast<IObject**>(ppCommandList) );
+ m_pCurrCmdCtx = nullptr;
+ Flush(true);
+
+ InvalidateState();
+#endif
+ }
+
+ void DeviceContextVkImpl::ExecuteCommandList(class ICommandList *pCommandList)
+ {
+ if (m_bIsDeferred)
+ {
+ LOG_ERROR("Only immediate context can execute command list");
+ return;
+ }
+#if 0
+ // First execute commands in this context
+ Flush(true);
+
+ InvalidateState();
+
+ CommandListVkImpl* pCmdListVk = ValidatedCast<CommandListVkImpl>(pCommandList);
+ ValidatedCast<RenderDeviceVkImpl>(m_pDevice.RawPtr())->CloseAndExecuteCommandContext(pCmdListVk->Close(), true);
+#endif
+ }
+
+#if 0
+ void DeviceContextVkImpl::TransitionTextureState(ITexture *pTexture, Vk_RESOURCE_STATES State)
+ {
+ VERIFY_EXPR(pTexture != nullptr);
+ auto *pCmdCtx = RequestCmdContext();
+ pCmdCtx->TransitionResource(ValidatedCast<ITextureVk>(pTexture), State);
+ }
+
+ void DeviceContextVkImpl::TransitionBufferState(IBuffer *pBuffer, Vk_RESOURCE_STATES State)
+ {
+ VERIFY_EXPR(pBuffer != nullptr);
+ auto *pCmdCtx = RequestCmdContext();
+ pCmdCtx->TransitionResource(ValidatedCast<IBufferVk>(pBuffer), State);
+ }
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp
new file mode 100644
index 00000000..ae01cc3e
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/DynamicUploadHeap.cpp
@@ -0,0 +1,171 @@
+/* Copyright 2015-2018 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "DynamicUploadHeap.h"
+#include "RenderDeviceVkImpl.h"
+
+namespace Diligent
+{
+#if 0
+ GPURingBuffer::GPURingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, IVkDevice *pVkDevice, bool AllowCPUAccess) :
+ RingBuffer(MaxSize, Allocator),
+ m_CpuVirtualAddress(nullptr),
+ m_GpuVirtualAddress(0)
+ {
+ Vk_HEAP_PROPERTIES HeapProps;
+ HeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN;
+ HeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN;
+ HeapProps.CreationNodeMask = 1;
+ HeapProps.VisibleNodeMask = 1;
+
+ Vk_RESOURCE_DESC ResourceDesc;
+ ResourceDesc.Dimension = Vk_RESOURCE_DIMENSION_BUFFER;
+ ResourceDesc.Alignment = 0;
+ ResourceDesc.Height = 1;
+ ResourceDesc.DepthOrArraySize = 1;
+ ResourceDesc.MipLevels = 1;
+ ResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
+ ResourceDesc.SampleDesc.Count = 1;
+ ResourceDesc.SampleDesc.Quality = 0;
+ ResourceDesc.Layout = Vk_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ Vk_RESOURCE_STATES DefaultUsage;
+ if (AllowCPUAccess)
+ {
+ HeapProps.Type = Vk_HEAP_TYPE_UPLOAD;
+ ResourceDesc.Flags = Vk_RESOURCE_FLAG_NONE;
+ DefaultUsage = Vk_RESOURCE_STATE_GENERIC_READ;
+ }
+ else
+ {
+ HeapProps.Type = Vk_HEAP_TYPE_DEFAULT;
+ ResourceDesc.Flags = Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+ DefaultUsage = Vk_RESOURCE_STATE_UNORDERED_ACCESS;
+ }
+ ResourceDesc.Width = MaxSize;
+
+ auto hr = pVkDevice->CreateCommittedResource(&HeapProps, Vk_HEAP_FLAG_NONE, &ResourceDesc,
+ DefaultUsage, nullptr, __uuidof(m_pBuffer), reinterpret_cast<void**>(static_cast<IVkResource**>(&m_pBuffer)) );
+ if(FAILED(hr))
+ LOG_ERROR("Failed to create new upload ring buffer");
+
+ m_pBuffer->SetName(L"Upload Ring Buffer");
+
+ m_GpuVirtualAddress = m_pBuffer->GetGPUVirtualAddress();
+
+ if (AllowCPUAccess)
+ {
+ m_pBuffer->Map(0, nullptr, &m_CpuVirtualAddress);
+ }
+
+ LOG_INFO_MESSAGE("GPU ring buffer created. Size: ", MaxSize, "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress);
+ }
+
+ void GPURingBuffer::Destroy()
+ {
+ if(m_pBuffer)
+ {
+ LOG_INFO_MESSAGE("Destroying GPU ring buffer. Size: ", m_pBuffer->GetDesc().Width, "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress);
+ }
+
+ if (m_CpuVirtualAddress)
+ {
+ m_pBuffer->Unmap(0, nullptr);
+ }
+ m_CpuVirtualAddress = 0;
+ m_GpuVirtualAddress = 0;
+ m_pBuffer.Release();
+ }
+
+ GPURingBuffer::~GPURingBuffer()
+ {
+ Destroy();
+ }
+
+ DynamicUploadHeap::DynamicUploadHeap(IMemoryAllocator &Allocator, bool bIsCPUAccessible, class RenderDeviceVkImpl* pDevice, size_t InitialSize) :
+ m_Allocator(Allocator),
+ m_pDeviceVk(pDevice),
+ m_bIsCPUAccessible(bIsCPUAccessible),
+ m_RingBuffers(STD_ALLOCATOR_RAW_MEM(GPURingBuffer, GetRawAllocator(), "Allocator for vector<GPURingBuffer>"))
+ {
+ m_RingBuffers.emplace_back(InitialSize, Allocator, pDevice->GetVkDevice(), m_bIsCPUAccessible);
+ }
+
+ DynamicAllocation DynamicUploadHeap::Allocate(size_t SizeInBytes, size_t Alignment /*= DEFAULT_ALIGN*/)
+ {
+ // Every device context has its own upload heap, so there is no need to lock
+
+ //std::lock_guard<std::mutex> Lock(m_Mutex);
+
+ //
+ // Deferred contexts must not update resources or map dynamic buffers
+ // across several frames!
+ //
+
+ const size_t AlignmentMask = Alignment - 1;
+ // Assert that it's a power of two.
+ VERIFY_EXPR((AlignmentMask & Alignment) == 0);
+ // Align the allocation
+ const size_t AlignedSize = (SizeInBytes + AlignmentMask) & ~AlignmentMask;
+ auto DynAlloc = m_RingBuffers.back().Allocate(AlignedSize);
+ if (!DynAlloc.pBuffer)
+ {
+ auto NewMaxSize = m_RingBuffers.back().GetMaxSize() * 2;
+ while(NewMaxSize < AlignedSize)NewMaxSize*=2;
+ m_RingBuffers.emplace_back(NewMaxSize, m_Allocator, m_pDeviceVk->GetVkDevice(), m_bIsCPUAccessible);
+ DynAlloc = m_RingBuffers.back().Allocate(AlignedSize);
+ }
+#ifdef _DEBUG
+ DynAlloc.FrameNum = m_pDeviceVk->GetCurrentFrameNumber();
+#endif
+ return DynAlloc;
+ }
+
+ void DynamicUploadHeap::FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue)
+ {
+ // Every device context has its own upload heap, so there is no need to lock
+ //std::lock_guard<std::mutex> Lock(m_Mutex);
+
+ //
+ // Deferred contexts must not update resources or map dynamic buffers
+ // across several frames!
+ //
+
+ size_t NumBuffsToDelete = 0;
+ for(size_t Ind = 0; Ind < m_RingBuffers.size(); ++Ind)
+ {
+ auto &RingBuff = m_RingBuffers[Ind];
+ RingBuff.FinishCurrentFrame(FenceValue);
+ RingBuff.ReleaseCompletedFrames(LastCompletedFenceValue);
+ if ( NumBuffsToDelete == Ind && Ind < m_RingBuffers.size()-1 && RingBuff.IsEmpty())
+ {
+ ++NumBuffsToDelete;
+ }
+ }
+
+ if(NumBuffsToDelete)
+ m_RingBuffers.erase(m_RingBuffers.begin(), m_RingBuffers.begin()+NumBuffsToDelete);
+ }
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMips.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMips.cpp
new file mode 100644
index 00000000..fc9facf1
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/GenerateMips.cpp
@@ -0,0 +1,196 @@
+/* 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.
+ */
+
+// The source code in this file is derived from ColorBuffer.cpp and GraphicsCore.cpp developed by Minigraph
+// Original source files header:
+
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+// Developed by Minigraph
+//
+// Author: James Stanard
+//
+
+
+#include "pch.h"
+
+/*
+#include "RenderDeviceVkImpl.h"
+#include "GenerateMips.h"
+#include "CommandContext.h"
+#include "TextureViewVkImpl.h"
+#include "TextureVkImpl.h"
+
+#include "GenerateMips/GenerateMipsLinearCS.h"
+#include "GenerateMips/GenerateMipsLinearOddCS.h"
+#include "GenerateMips/GenerateMipsLinearOddXCS.h"
+#include "GenerateMips/GenerateMipsLinearOddYCS.h"
+#include "GenerateMips/GenerateMipsGammaCS.h"
+#include "GenerateMips/GenerateMipsGammaOddCS.h"
+#include "GenerateMips/GenerateMipsGammaOddXCS.h"
+#include "GenerateMips/GenerateMipsGammaOddYCS.h"
+
+namespace Diligent
+{
+ GenerateMipsHelper::GenerateMipsHelper(IVkDevice *pVkDevice)
+ {
+ CD3DX12_ROOT_PARAMETER Params[3];
+ Params[0].InitAsConstants(6, 0);
+ CD3DX12_DESCRIPTOR_RANGE SRVRange(Vk_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
+ Params[1].InitAsDescriptorTable(1, &SRVRange);
+ CD3DX12_DESCRIPTOR_RANGE UAVRange(Vk_DESCRIPTOR_RANGE_TYPE_UAV, 4, 0);
+ Params[2].InitAsDescriptorTable(1, &UAVRange);
+ CD3DX12_STATIC_SAMPLER_DESC SamplerLinearClampDesc(
+ 0, Vk_FILTER_MIN_MAG_MIP_LINEAR, Vk_TEXTURE_ADDRESS_MODE_CLAMP, Vk_TEXTURE_ADDRESS_MODE_CLAMP, Vk_TEXTURE_ADDRESS_MODE_CLAMP);
+ CD3DX12_ROOT_SIGNATURE_DESC RootSigDesc;
+ RootSigDesc.NumParameters = _countof(Params);
+ RootSigDesc.pParameters = Params;
+ RootSigDesc.NumStaticSamplers = 1;
+ RootSigDesc.pStaticSamplers = &SamplerLinearClampDesc;
+ RootSigDesc.Flags = Vk_ROOT_SIGNATURE_FLAG_NONE;
+
+ CComPtr<ID3DBlob> signature;
+ CComPtr<ID3DBlob> error;
+ HRESULT hr = VkSerializeRootSignature(&RootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
+ hr = pVkDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(m_pGenerateMipsRS), reinterpret_cast<void**>( static_cast<IVkRootSignature**>(&m_pGenerateMipsRS)));
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature for mipmap generation")
+
+ Vk_COMPUTE_PIPELINE_STATE_DESC PSODesc = {};
+ PSODesc.pRootSignature = m_pGenerateMipsRS;
+ PSODesc.NodeMask = 0;
+ PSODesc.Flags = Vk_PIPELINE_STATE_FLAG_NONE;
+
+#define CreatePSO(PSO, ShaderByteCode) \
+ PSODesc.CS.pShaderBytecode = ShaderByteCode;\
+ PSODesc.CS.BytecodeLength = sizeof(ShaderByteCode);\
+ hr = pVkDevice->CreateComputePipelineState(&PSODesc, __uuidof(PSO), reinterpret_cast<void**>( static_cast<IVkPipelineState**>(&PSO))); \
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create Pipeline state for mipmap generation") \
+ PSO->SetName(L"Generate mips PSO");
+
+ CreatePSO(m_pGenerateMipsLinearPSO[0], g_pGenerateMipsLinearCS);
+ CreatePSO(m_pGenerateMipsLinearPSO[1], g_pGenerateMipsLinearOddXCS);
+ CreatePSO(m_pGenerateMipsLinearPSO[2], g_pGenerateMipsLinearOddYCS);
+ CreatePSO(m_pGenerateMipsLinearPSO[3], g_pGenerateMipsLinearOddCS);
+ CreatePSO(m_pGenerateMipsGammaPSO[0], g_pGenerateMipsGammaCS);
+ CreatePSO(m_pGenerateMipsGammaPSO[1], g_pGenerateMipsGammaOddXCS);
+ CreatePSO(m_pGenerateMipsGammaPSO[2], g_pGenerateMipsGammaOddYCS);
+ CreatePSO(m_pGenerateMipsGammaPSO[3], g_pGenerateMipsGammaOddCS);
+ }
+
+ void GenerateMipsHelper::GenerateMips(RenderDeviceVkImpl *pRenderDeviceVk, TextureViewVkImpl *pTexView, CommandContext& Ctx)
+ {
+ auto &ComputeCtx = Ctx.AsComputeContext();
+ ComputeCtx.SetRootSignature(m_pGenerateMipsRS);
+ auto *pTexture = pTexView->GetTexture();
+ auto *pTexVk = ValidatedCast<TextureVkImpl>( pTexture );
+ auto &TexDesc = pTexture->GetDesc();
+ auto SRVDescriptorHandle = pTexVk->GetTexArraySRV();
+
+ Ctx.TransitionResource(pTexVk, Vk_RESOURCE_STATE_UNORDERED_ACCESS);
+ auto *pVkDevice = pRenderDeviceVk->GetVkDevice();
+
+ const auto &ViewDesc = pTexView->GetDesc();
+ for (Uint32 ArrSlice = ViewDesc.FirstArraySlice; ArrSlice < ViewDesc.FirstArraySlice + ViewDesc.NumArraySlices; ++ArrSlice)
+ {
+ for (uint32_t TopMip = 0; TopMip < TexDesc.MipLevels - 1; )
+ {
+ uint32_t SrcWidth = TexDesc.Width >> TopMip;
+ uint32_t SrcHeight = TexDesc.Height >> TopMip;
+ uint32_t DstWidth = SrcWidth >> 1;
+ uint32_t DstHeight = SrcHeight >> 1;
+
+ // Determine if the first downsample is more than 2:1. This happens whenever
+ // the source width or height is odd.
+ uint32_t NonPowerOfTwo = (SrcWidth & 1) | (SrcHeight & 1) << 1;
+ if (TexDesc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB)
+ ComputeCtx.SetPipelineState(m_pGenerateMipsGammaPSO[NonPowerOfTwo]);
+ else
+ ComputeCtx.SetPipelineState(m_pGenerateMipsLinearPSO[NonPowerOfTwo]);
+
+ // We can downsample up to four times, but if the ratio between levels is not
+ // exactly 2:1, we have to shift our blend weights, which gets complicated or
+ // expensive. Maybe we can update the code later to compute sample weights for
+ // each successive downsample. We use _BitScanForward to count number of zeros
+ // in the low bits. Zeros indicate we can divide by two without truncating.
+ uint32_t AdditionalMips;
+ _BitScanForward((unsigned long*)&AdditionalMips, DstWidth | DstHeight);
+ uint32_t NumMips = 1 + (AdditionalMips > 3 ? 3 : AdditionalMips);
+ if (TopMip + NumMips > TexDesc.MipLevels - 1)
+ NumMips = TexDesc.MipLevels - 1 - TopMip;
+
+ // These are clamped to 1 after computing additional mips because clamped
+ // dimensions should not limit us from downsampling multiple times. (E.g.
+ // 16x1 -> 8x1 -> 4x1 -> 2x1 -> 1x1.)
+ if (DstWidth == 0)
+ DstWidth = 1;
+ if (DstHeight == 0)
+ DstHeight = 1;
+
+ Vk_DESCRIPTOR_HEAP_TYPE HeapType = Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ auto DescriptorAlloc = Ctx.AllocateDynamicGPUVisibleDescriptor(HeapType, 5);
+ CommandContext::ShaderDescriptorHeaps Heaps(DescriptorAlloc.GetDescriptorHeap());
+ ComputeCtx.SetDescriptorHeaps(Heaps);
+ Ctx.GetCommandList()->SetComputeRootDescriptorTable(1, DescriptorAlloc.GetGpuHandle(0));
+ Ctx.GetCommandList()->SetComputeRootDescriptorTable(2, DescriptorAlloc.GetGpuHandle(1));
+ struct RootCBData
+ {
+ Uint32 SrcMipLevel; // Texture level of source mip
+ Uint32 NumMipLevels; // Number of OutMips to write: [1, 4]
+ Uint32 ArraySlice;
+ Uint32 Dummy;
+ float TexelSize[2]; // 1.0 / OutMip1.Dimensions
+ }CBData = { TopMip, NumMips, ArrSlice, 0, 1.0f / static_cast<float>(DstWidth), 1.0f / static_cast<float>(DstHeight) };
+ Ctx.GetCommandList()->SetComputeRoot32BitConstants(0, 6, &CBData, 0);
+
+ // TODO: Shouldn't we transition top mip to shader resource state?
+ Vk_CPU_DESCRIPTOR_HANDLE DstDescriptorRange = DescriptorAlloc.GetCpuHandle();
+ const Uint32 MaxMipsHandledByCS = 4; // Max number of mip levels processed by one CS shader invocation
+ UINT DstRangeSize = 1 + MaxMipsHandledByCS;
+ Vk_CPU_DESCRIPTOR_HANDLE SrcDescriptorRanges[5] = {};
+ SrcDescriptorRanges[0] = SRVDescriptorHandle;
+ UINT SrcRangeSizes[5] = { 1,1,1,1,1 };
+ // On Resource Binding Tier 2 hardware, all descriptor tables of type CBV and UAV declared in the set
+ // Root Signature must be populated and initialized, even if the shaders do not need the descriptor.
+ // So we must populate all 4 slots even though we may actually process less than 4 mip levels
+ // Copy top mip level UAV descriptor handle to all unused slots
+ for (Uint32 u = 0; u < MaxMipsHandledByCS; ++u)
+ SrcDescriptorRanges[1 + u] = pTexVk->GetMipLevelUAV(std::min(TopMip + u + 1, TexDesc.MipLevels - 1));
+
+ pVkDevice->CopyDescriptors(1, &DstDescriptorRange, &DstRangeSize, 1 + MaxMipsHandledByCS, SrcDescriptorRanges, SrcRangeSizes, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+
+ ComputeCtx.Dispatch((DstWidth + 7) / 8, (DstHeight + 7) / 8);
+
+ Ctx.InsertUAVBarrier(*pTexVk, *pTexVk);
+
+ TopMip += NumMips;
+ }
+ }
+ }
+}
+*/ \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/src/GraphicsEngineVk.def b/Graphics/GraphicsEngineVulkan/src/GraphicsEngineVk.def
new file mode 100644
index 00000000..a9ed58f5
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/GraphicsEngineVk.def
@@ -0,0 +1,2 @@
+EXPORTS
+ GetEngineFactoryVk \ No newline at end of file
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
new file mode 100644
index 00000000..02ed991f
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
@@ -0,0 +1,404 @@
+/* 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 "PipelineStateVkImpl.h"
+#include "ShaderVkImpl.h"
+#include "VulkanTypeConversions.h"
+#include "RenderDeviceVkImpl.h"
+//#include "DXGITypeConversions.h"
+#include "ShaderResourceBindingVkImpl.h"
+#include "CommandContext.h"
+#include "EngineMemory.h"
+#include "StringTools.h"
+
+namespace Diligent
+{
+/*
+Vk_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType_To_Vk_PRIMITIVE_TOPOLOGY_TYPE( PRIMITIVE_TOPOLOGY_TYPE TopologyType )
+{
+ static bool bIsInit = false;
+ static Vk_PRIMITIVE_TOPOLOGY_TYPE VkTopologyType[PRIMITIVE_TOPOLOGY_TYPE_NUM_TYPES] = {};
+ if( !bIsInit )
+ {
+ VkTopologyType[ PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED] = Vk_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED;
+ VkTopologyType[ PRIMITIVE_TOPOLOGY_TYPE_POINT ] = Vk_PRIMITIVE_TOPOLOGY_TYPE_POINT;
+ VkTopologyType[ PRIMITIVE_TOPOLOGY_TYPE_LINE ] = Vk_PRIMITIVE_TOPOLOGY_TYPE_LINE;
+ VkTopologyType[ PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE ] = Vk_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ VkTopologyType[ PRIMITIVE_TOPOLOGY_TYPE_PATCH ] = Vk_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
+
+ bIsInit = true;
+ }
+
+ if( TopologyType >= PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED && TopologyType < PRIMITIVE_TOPOLOGY_TYPE_NUM_TYPES )
+ {
+ auto VkTopType = VkTopologyType[TopologyType];
+ return VkTopType;
+ }
+ else
+ {
+ UNEXPECTED( "Incorrect topology type operation (", TopologyType, ")" );
+ return static_cast<Vk_PRIMITIVE_TOPOLOGY_TYPE>(0);
+ }
+}
+
+void PipelineStateVkImpl::ParseShaderResourceLayout(IShader *pShader)
+{
+ VERIFY_EXPR(pShader);
+
+ auto ShaderType = pShader->GetDesc().ShaderType;
+ auto ShaderInd = GetShaderTypeIndex(ShaderType);
+ auto *pShaderVk = ValidatedCast<ShaderVkImpl>(pShader);
+
+ VERIFY(m_pShaderResourceLayouts[ShaderInd] == nullptr, "Shader resource layout has already been initialized");
+
+ auto pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(pShaderVk->GetDevice());
+ auto &ShaderResLayoutAllocator = GetRawAllocator();
+
+ auto *pRawMem = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", sizeof(ShaderResourceLayoutVk));
+ m_pShaderResourceLayouts[ShaderInd] = new (pRawMem) ShaderResourceLayoutVk(*this, GetRawAllocator());
+ m_pShaderResourceLayouts[ShaderInd]->Initialize(pDeviceVkImpl->GetVkDevice(), pShaderVk->GetShaderResources(), GetRawAllocator(), nullptr, 0, nullptr, &m_RootSig);
+}
+*/
+PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, RenderDeviceVkImpl *pDeviceVk, const PipelineStateDesc &PipelineDesc) :
+ TPipelineStateBase(pRefCounters, pDeviceVk, PipelineDesc)/*,
+ m_DummyVar(*this),
+ m_ResourceCacheDataAllocator(GetRawAllocator(), PipelineDesc.SRBAllocationGranularity),
+ m_pDefaultShaderResBinding(nullptr, STDDeleter<ShaderResourceBindingVkImpl, FixedBlockMemoryAllocator>(pDeviceVk->GetSRBAllocator()) )
+*/
+{
+#if 0
+ auto pVkDevice = pDeviceVk->GetVkDevice();
+ if (PipelineDesc.IsComputePipeline)
+ {
+ auto &ComputePipeline = PipelineDesc.ComputePipeline;
+
+ if( ComputePipeline.pCS == nullptr )
+ LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc");
+
+ Vk_COMPUTE_PIPELINE_STATE_DESC VkPSODesc = {};
+ VkPSODesc.pRootSignature = nullptr;
+
+ auto *pByteCode = ValidatedCast<ShaderVkImpl>(ComputePipeline.pCS)->GetShaderByteCode();
+ VkPSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer();
+ VkPSODesc.CS.BytecodeLength = pByteCode->GetBufferSize();
+
+ // For single GPU operation, set this to zero. If there are multiple GPU nodes,
+ // set bits to identify the nodes (the device's physical adapters) for which the
+ // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
+ VkPSODesc.NodeMask = 0;
+
+ VkPSODesc.CachedPSO.pCachedBlob = nullptr;
+ VkPSODesc.CachedPSO.CachedBlobSizeInBytes = 0;
+
+ // The only valid bit is Vk_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
+ VkPSODesc.Flags = Vk_PIPELINE_STATE_FLAG_NONE;
+
+ ParseShaderResourceLayout(ComputePipeline.pCS);
+ m_RootSig.Finalize(pVkDevice);
+ VkPSODesc.pRootSignature = m_RootSig.GetVkRootSignature();
+
+ HRESULT hr = pVkDevice->CreateComputePipelineState(&VkPSODesc, __uuidof(IVkPipelineState), reinterpret_cast<void**>( static_cast<IVkPipelineState**>(&m_pVkPSO)) );
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create pipeline state");
+ }
+ else
+ {
+ const auto& GraphicsPipeline = PipelineDesc.GraphicsPipeline;
+ Vk_GRAPHICS_PIPELINE_STATE_DESC VkPSODesc = {};
+
+ m_RootSig.AllocateStaticSamplers( GetShaders(), GetNumShaders() );
+
+#define INIT_SHADER(VarName, ExpectedType)\
+ if (GraphicsPipeline.p##VarName) \
+ { \
+ auto ShaderType = GraphicsPipeline.p##VarName->GetDesc().ShaderType; \
+ if( ShaderType != ExpectedType ) \
+ LOG_ERROR_AND_THROW( GetShaderTypeLiteralName(ShaderType), " shader is provided while ", GetShaderTypeLiteralName(ExpectedType), " is expected");\
+ auto *pByteCode = ValidatedCast<ShaderVkImpl>(GraphicsPipeline.p##VarName)->GetShaderByteCode(); \
+ VkPSODesc.VarName.pShaderBytecode = pByteCode->GetBufferPointer(); \
+ VkPSODesc.VarName.BytecodeLength = pByteCode->GetBufferSize(); \
+ ParseShaderResourceLayout(GraphicsPipeline.p##VarName); \
+ } \
+ else \
+ { \
+ VkPSODesc.VarName.pShaderBytecode = nullptr; \
+ VkPSODesc.VarName.BytecodeLength = 0; \
+ }
+
+ INIT_SHADER(VS, SHADER_TYPE_VERTEX);
+ INIT_SHADER(PS, SHADER_TYPE_PIXEL);
+ INIT_SHADER(GS, SHADER_TYPE_GEOMETRY);
+ INIT_SHADER(DS, SHADER_TYPE_DOMAIN);
+ INIT_SHADER(HS, SHADER_TYPE_HULL);
+#undef INIT_SHADER
+
+ m_RootSig.Finalize(pVkDevice);
+ VkPSODesc.pRootSignature = m_RootSig.GetVkRootSignature();
+
+ memset(&VkPSODesc.StreamOutput, 0, sizeof(VkPSODesc.StreamOutput));
+
+ BlendStateDesc_To_Vk_BLEND_DESC(GraphicsPipeline.BlendDesc, VkPSODesc.BlendState);
+ // The sample mask for the blend state.
+ VkPSODesc.SampleMask = GraphicsPipeline.SampleMask;
+
+ RasterizerStateDesc_To_Vk_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, VkPSODesc.RasterizerState);
+ DepthStencilStateDesc_To_Vk_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, VkPSODesc.DepthStencilState);
+
+ std::vector<Vk_INPUT_ELEMENT_DESC, STDAllocatorRawMem<Vk_INPUT_ELEMENT_DESC>> d312InputElements( STD_ALLOCATOR_RAW_MEM(Vk_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<Vk_INPUT_ELEMENT_DESC>") );
+ if (m_LayoutElements.size() > 0)
+ {
+ LayoutElements_To_Vk_INPUT_ELEMENT_DESCs(m_LayoutElements, d312InputElements);
+ VkPSODesc.InputLayout.NumElements = static_cast<UINT>(d312InputElements.size());
+ VkPSODesc.InputLayout.pInputElementDescs = d312InputElements.data();
+ }
+ else
+ {
+ VkPSODesc.InputLayout.NumElements = 0;
+ VkPSODesc.InputLayout.pInputElementDescs = nullptr;
+ }
+
+ VkPSODesc.IBStripCutValue = Vk_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
+ VkPSODesc.PrimitiveTopologyType = PrimitiveTopologyType_To_Vk_PRIMITIVE_TOPOLOGY_TYPE(GraphicsPipeline.PrimitiveTopologyType);
+
+ VkPSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets;
+ for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt)
+ VkPSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]);
+ for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < 8; ++rt)
+ VkPSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]);
+ VkPSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat);
+
+ VkPSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count;
+ VkPSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality;
+
+ // For single GPU operation, set this to zero. If there are multiple GPU nodes,
+ // set bits to identify the nodes (the device's physical adapters) for which the
+ // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
+ VkPSODesc.NodeMask = 0;
+
+ VkPSODesc.CachedPSO.pCachedBlob = nullptr;
+ VkPSODesc.CachedPSO.CachedBlobSizeInBytes = 0;
+
+ // The only valid bit is Vk_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
+ VkPSODesc.Flags = Vk_PIPELINE_STATE_FLAG_NONE;
+
+ HRESULT hr = pVkDevice->CreateGraphicsPipelineState(&VkPSODesc, __uuidof(IVkPipelineState), reinterpret_cast<void**>( static_cast<IVkPipelineState**>(&m_pVkPSO)) );
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create pipeline state");
+ }
+
+ if (*m_Desc.Name != 0)
+ {
+ m_pVkPSO->SetName(WidenString(m_Desc.Name).c_str());
+ String RootSignatureDesc("Root signature for PSO \"");
+ RootSignatureDesc.append(m_Desc.Name);
+ RootSignatureDesc.push_back('\"');
+ m_RootSig.GetVkRootSignature()->SetName(WidenString(RootSignatureDesc).c_str());
+ }
+
+ if(PipelineDesc.SRBAllocationGranularity > 1)
+ m_ResLayoutDataAllocators.Init(m_NumShaders, PipelineDesc.SRBAllocationGranularity);
+
+ auto &SRBAllocator = pDeviceVk->GetSRBAllocator();
+ // Default shader resource binding must be initialized after resource layouts are parsed!
+ m_pDefaultShaderResBinding.reset( NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl, this)(this, true) );
+
+ m_ShaderResourceLayoutHash = m_RootSig.GetHash();
+#endif
+}
+
+PipelineStateVkImpl::~PipelineStateVkImpl()
+{
+#if 0
+ auto &ShaderResLayoutAllocator = GetRawAllocator();
+ for(Int32 l = 0; l < _countof(m_pShaderResourceLayouts); ++l)
+ {
+ if (m_pShaderResourceLayouts[l] != nullptr)
+ {
+ m_pShaderResourceLayouts[l]->~ShaderResourceLayoutVk();
+ ShaderResLayoutAllocator.Free(m_pShaderResourceLayouts[l]);
+ }
+ }
+
+ // Vk object can only be destroyed when it is no longer used by the GPU
+ auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice());
+ pDeviceVkImpl->SafeReleaseVkObject(m_pVkPSO);
+#endif
+}
+
+IMPLEMENT_QUERY_INTERFACE( PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase )
+
+void PipelineStateVkImpl::BindShaderResources(IResourceMapping *pResourceMapping, Uint32 Flags)
+{
+#if 0
+ if( m_Desc.IsComputePipeline )
+ {
+ if(m_pCS)m_pCS->BindResources(pResourceMapping, Flags);
+ }
+ else
+ {
+ if(m_pVS)m_pVS->BindResources(pResourceMapping, Flags);
+ if(m_pPS)m_pPS->BindResources(pResourceMapping, Flags);
+ if(m_pGS)m_pGS->BindResources(pResourceMapping, Flags);
+ if(m_pDS)m_pDS->BindResources(pResourceMapping, Flags);
+ if(m_pHS)m_pHS->BindResources(pResourceMapping, Flags);
+ }
+#endif
+}
+
+void PipelineStateVkImpl::CreateShaderResourceBinding(IShaderResourceBinding **ppShaderResourceBinding)
+{
+#if 0
+ auto *pRenderDeviceVk = ValidatedCast<RenderDeviceVkImpl>( GetDevice() );
+ auto &SRBAllocator = pRenderDeviceVk->GetSRBAllocator();
+ auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false);
+ pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
+#endif
+}
+
+bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState *pPSO)const
+{
+ VERIFY_EXPR(pPSO != nullptr);
+
+ if (pPSO == this)
+ return true;
+#if 0
+ const PipelineStateVkImpl *pPSOVk = ValidatedCast<const PipelineStateVkImpl>(pPSO);
+ if (m_ShaderResourceLayoutHash != pPSOVk->m_ShaderResourceLayoutHash)
+ return false;
+
+ auto IsSameRootSignature = m_RootSig.IsSameAs(pPSOVk->m_RootSig);
+
+#ifdef _DEBUG
+ {
+ bool IsCompatibleShaders = true;
+ if (m_NumShaders != pPSOVk->m_NumShaders)
+ IsCompatibleShaders = false;
+
+ if(IsCompatibleShaders)
+ {
+ for (Uint32 s = 0; s < m_NumShaders; ++s)
+ {
+ auto *pShader0 = ValidatedCast<ShaderVkImpl>(m_ppShaders[s]);
+ auto *pShader1 = ValidatedCast<ShaderVkImpl>(pPSOVk->m_ppShaders[s]);
+ if (pShader0->GetDesc().ShaderType != pShader1->GetDesc().ShaderType)
+ {
+ IsCompatibleShaders = false;
+ break;
+ }
+ const ShaderResourcesVk *pRes0 = pShader0->GetShaderResources().get();
+ const ShaderResourcesVk *pRes1 = pShader1->GetShaderResources().get();
+ if (!pRes0->IsCompatibleWith(*pRes1))
+ {
+ IsCompatibleShaders = false;
+ break;
+ }
+ }
+ }
+
+ if(IsCompatibleShaders)
+ VERIFY(IsSameRootSignature, "Compatible shaders must have same root signatures");
+ }
+#endif
+
+ return IsSameRootSignature;
+#endif
+ return true;
+}
+
+#if 0
+const ShaderResourceLayoutVk& PipelineStateVkImpl::GetShaderResLayout(SHADER_TYPE ShaderType)const
+{
+ auto ShaderInd = GetShaderTypeIndex(ShaderType);
+ VERIFY_EXPR(m_pShaderResourceLayouts[ShaderInd] != nullptr);
+ return *m_pShaderResourceLayouts[ShaderInd];
+}
+
+ShaderResourceCacheVk* PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBinding *pShaderResourceBinding,
+ CommandContext &Ctx,
+ bool CommitResources,
+ bool TransitionResources)const
+{
+#ifdef VERIFY_SHADER_BINDINGS
+ if (pShaderResourceBinding == nullptr &&
+ (m_RootSig.GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE_MUTABLE) != 0 ||
+ m_RootSig.GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE_DYNAMIC) != 0))
+ {
+ LOG_ERROR_MESSAGE("Pipeline state \"", m_Desc.Name, "\" contains mutable/dynamic shader variables and requires shader resource binding to commit all resources, but none is provided.");
+ }
+#endif
+
+ // If the shaders contain no resources or static resources only, shader resource binding may be null.
+ // In this case use special internal SRB object
+ auto *pResBindingVkImpl = pShaderResourceBinding ? ValidatedCast<ShaderResourceBindingVkImpl>(pShaderResourceBinding) : m_pDefaultShaderResBinding.get();
+
+#ifdef VERIFY_SHADER_BINDINGS
+ {
+ auto *pRefPSO = pResBindingVkImpl->GetPipelineState();
+ if ( IsIncompatibleWith(pRefPSO) )
+ {
+ LOG_ERROR_MESSAGE("Shader resource binding is incompatible with the pipeline state \"", m_Desc.Name, "\". Operation will be ignored.");
+ return nullptr;
+ }
+ }
+#endif
+
+ // First time only, copy static shader resources to the cache
+ if(!pResBindingVkImpl->StaticResourcesInitialized())
+ pResBindingVkImpl->InitializeStaticResources(this);
+
+#ifdef VERIFY_SHADER_BINDINGS
+ pResBindingVkImpl->dbgVerifyResourceBindings(this);
+#endif
+
+ auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>( GetDevice() );
+ auto &ResourceCache = pResBindingVkImpl->GetResourceCache();
+ if(CommitResources)
+ {
+ if(m_Desc.IsComputePipeline)
+ Ctx.AsComputeContext().SetRootSignature( GetVkRootSignature() );
+ else
+ Ctx.AsGraphicsContext().SetRootSignature( GetVkRootSignature() );
+
+ if(TransitionResources)
+ (m_RootSig.*m_RootSig.TransitionAndCommitDescriptorHandles)(pDeviceVkImpl, ResourceCache, Ctx, m_Desc.IsComputePipeline);
+ else
+ (m_RootSig.*m_RootSig.CommitDescriptorHandles)(pDeviceVkImpl, ResourceCache, Ctx, m_Desc.IsComputePipeline);
+ }
+ else
+ {
+ VERIFY(TransitionResources, "Resources should be transitioned or committed or both");
+ m_RootSig.TransitionResources(ResourceCache, Ctx);
+ }
+ return &ResourceCache;
+}
+
+
+bool PipelineStateVkImpl::dbgContainsShaderResources()const
+{
+ return m_RootSig.GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE_STATIC) != 0 ||
+ m_RootSig.GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE_MUTABLE) != 0 ||
+ m_RootSig.GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE_DYNAMIC) != 0;
+}
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp
new file mode 100644
index 00000000..4764d849
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp
@@ -0,0 +1,414 @@
+/* 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.
+ */
+
+/// \file
+/// Routines that initialize Vulkan-based engine implementation
+
+#include "pch.h"
+#include "RenderDeviceFactoryVk.h"
+#include "RenderDeviceVkImpl.h"
+#include "DeviceContextVkImpl.h"
+#include "SwapChainVkImpl.h"
+#include "VulkanTypeConversions.h"
+#include "StringTools.h"
+#include "EngineMemory.h"
+#include "CommandQueueVkImpl.h"
+#include <Windows.h>
+#include <dxgi1_4.h>
+
+namespace Diligent
+{
+
+/// Engine factory for Vk implementation
+class EngineFactoryVkImpl : public IEngineFactoryVk
+{
+public:
+ static EngineFactoryVkImpl* GetInstance()
+ {
+ static EngineFactoryVkImpl TheFactory;
+ return &TheFactory;
+ }
+
+ void CreateDeviceAndContextsVk( const EngineVkAttribs& CreationAttribs,
+ IRenderDevice **ppDevice,
+ IDeviceContext **ppContexts,
+ Uint32 NumDeferredContexts)override final;
+
+ /*void AttachToVkDevice(void *pVkNativeDevice,
+ ICommandQueueVk *pCommandQueue,
+ const EngineVkAttribs& EngineAttribs,
+ IRenderDevice **ppDevice,
+ IDeviceContext **ppContexts,
+ Uint32 NumDeferredContexts)override final;
+ */
+
+ void CreateSwapChainVk( IRenderDevice *pDevice,
+ IDeviceContext *pImmediateContext,
+ const SwapChainDesc& SwapChainDesc,
+ void* pNativeWndHandle,
+ ISwapChain **ppSwapChain )override final;
+
+};
+
+#if 0
+void GetHardwareAdapter(IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter)
+{
+ CComPtr<IDXGIAdapter1> adapter;
+ *ppAdapter = nullptr;
+
+ for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &adapter); ++adapterIndex)
+ {
+ DXGI_ADAPTER_DESC1 desc;
+ adapter->GetDesc1(&desc);
+
+ if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
+ {
+ // Don't select the Basic Render Driver adapter.
+ // If you want a software adapter, pass in "/warp" on the command line.
+ continue;
+ }
+
+ // Check to see if the adapter supports Direct3D 12, but don't create the
+ // actual device yet.
+ if (SUCCEEDED(VkCreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(IVkDevice), nullptr)))
+ {
+ LOG_INFO_MESSAGE("Vk-capabale hardware found: ", NarrowString(desc.Description), " (", desc.DedicatedVideoMemory>>20, " MB)");
+ break;
+ }
+ }
+
+ *ppAdapter = adapter.Detach();
+}
+#endif
+
+/// Creates render device and device contexts for Direct3D12-based engine implementation
+
+/// \param [in] CreationAttribs - Engine creation attributes.
+/// \param [out] ppDevice - Address of the memory location where pointer to
+/// the created device will be written
+/// \param [out] ppContexts - Address of the memory location where pointers to
+/// the contexts will be written. The new immediate
+/// context goes at position 0. If NumDeferredContexts > 0,
+/// pointers to the deferred contexts are written afterwards.
+/// \param [in] NumDeferredContexts - Number of deferred contexts. If non-zero number
+/// of deferred contexts is requested, pointers to the
+/// contexts are written to ppContexts array starting
+/// at position 1
+void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& CreationAttribs,
+ IRenderDevice **ppDevice,
+ IDeviceContext **ppContexts,
+ Uint32 NumDeferredContexts)
+{
+ VERIFY( ppDevice && ppContexts, "Null pointer provided" );
+ if( !ppDevice || !ppContexts )
+ return;
+
+#if 0
+ for(Uint32 Type=Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; Type < Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++Type)
+ {
+ auto CPUHeapAllocSize = CreationAttribs.CPUDescriptorHeapAllocationSize[Type];
+ Uint32 MaxSize = 1 << 20;
+ if( CPUHeapAllocSize > 1 << 20 )
+ {
+ LOG_ERROR( "CPU Heap allocation size is too large (", CPUHeapAllocSize, "). Max allowed size is ", MaxSize );
+ return;
+ }
+
+ if( (CPUHeapAllocSize % 16) != 0 )
+ {
+ LOG_ERROR( "CPU Heap allocation size (", CPUHeapAllocSize, ") is expected to be multiple of 16" );
+ return;
+ }
+ }
+
+ SetRawAllocator(CreationAttribs.pRawMemAllocator);
+
+ *ppDevice = nullptr;
+ memset(ppContexts, 0, sizeof(*ppContexts) * (1+NumDeferredContexts));
+
+ RefCntAutoPtr<CommandQueueVkImpl> pCmdQueueVk;
+ CComPtr<IVkDevice> VkDevice;
+ try
+ {
+#if defined(_DEBUG)
+ // Enable the Vk debug layer.
+ {
+ CComPtr<IVkDebug> debugController;
+ if (SUCCEEDED(VkGetDebugInterface(__uuidof(debugController), reinterpret_cast<void**>(static_cast<IVkDebug**>(&debugController)) )))
+ {
+ debugController->EnableDebugLayer();
+ }
+ }
+#endif
+
+ CComPtr<IDXGIFactory4> factory;
+ HRESULT hr = CreateDXGIFactory1(__uuidof(factory), reinterpret_cast<void**>(static_cast<IDXGIFactory4**>(&factory)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create DXGI factory")
+
+ CComPtr<IDXGIAdapter1> hardwareAdapter;
+ GetHardwareAdapter(factory, &hardwareAdapter);
+
+ hr = VkCreateDevice(hardwareAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(VkDevice), reinterpret_cast<void**>(static_cast<IVkDevice**>(&VkDevice)) );
+ if( FAILED(hr))
+ {
+ LOG_WARNING_MESSAGE("Failed to create hardware device. Attempting to create WARP device");
+
+ CComPtr<IDXGIAdapter> warpAdapter;
+ hr = factory->EnumWarpAdapter( __uuidof(warpAdapter), reinterpret_cast<void**>(static_cast<IDXGIAdapter**>(&warpAdapter)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to enum warp adapter")
+
+ hr = VkCreateDevice( warpAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(VkDevice), reinterpret_cast<void**>(static_cast<IVkDevice**>(&VkDevice)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to crate warp device")
+ }
+
+#if _DEBUG
+ {
+ CComPtr<IVkInfoQueue> pInfoQueue;
+ hr = VkDevice->QueryInterface(__uuidof(pInfoQueue), reinterpret_cast<void**>(static_cast<IVkInfoQueue**>(&pInfoQueue)));
+ if( SUCCEEDED(hr) )
+ {
+ // Suppress whole categories of messages
+ //Vk_MESSAGE_CATEGORY Categories[] = {};
+
+ // Suppress messages based on their severity level
+ Vk_MESSAGE_SEVERITY Severities[] =
+ {
+ Vk_MESSAGE_SEVERITY_INFO
+ };
+
+ // Suppress individual messages by their ID
+ //Vk_MESSAGE_ID DenyIds[] = {};
+
+ Vk_INFO_QUEUE_FILTER NewFilter = {};
+ //NewFilter.DenyList.NumCategories = _countof(Categories);
+ //NewFilter.DenyList.pCategoryList = Categories;
+ NewFilter.DenyList.NumSeverities = _countof(Severities);
+ NewFilter.DenyList.pSeverityList = Severities;
+ //NewFilter.DenyList.NumIDs = _countof(DenyIds);
+ //NewFilter.DenyList.pIDList = DenyIds;
+
+ hr = pInfoQueue->PushStorageFilter(&NewFilter);
+ VERIFY(SUCCEEDED(hr), "Failed to push storage filter");
+ }
+ }
+#endif
+
+#ifndef RELEASE
+ // Prevent the GPU from overclocking or underclocking to get consistent timings
+ //VkDevice->SetStablePowerState(TRUE);
+#endif
+
+ // Describe and create the command queue.
+ Vk_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Flags = Vk_COMMAND_QUEUE_FLAG_NONE;
+ queueDesc.Type = Vk_COMMAND_LIST_TYPE_DIRECT;
+
+ CComPtr<IVkCommandQueue> pVkCmdQueue;
+ hr = VkDevice->CreateCommandQueue(&queueDesc, __uuidof(pVkCmdQueue), reinterpret_cast<void**>(static_cast<IVkCommandQueue**>(&pVkCmdQueue)));
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create command queue");
+ hr = pVkCmdQueue->SetName(L"Main Command Queue");
+ VERIFY_EXPR(SUCCEEDED(hr));
+
+ CComPtr<IVkFence> pVkFence;
+ hr = VkDevice->CreateFence(0, Vk_FENCE_FLAG_NONE, __uuidof(pVkFence), reinterpret_cast<void**>(static_cast<IVkFence**>(&pVkFence)));
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create main command queue fence");
+ VkDevice->SetName(L"Main Command Queue fence");
+
+ auto &RawMemAllocator = GetRawAllocator();
+ pCmdQueueVk = NEW_RC_OBJ(RawMemAllocator, "CommandQueueVk instance", CommandQueueVkImpl)(pVkCmdQueue, pVkFence);
+ }
+ catch( const std::runtime_error & )
+ {
+ LOG_ERROR( "Failed to initialize Vk resources" );
+ return;
+ }
+
+ AttachToVkDevice(VkDevice, pCmdQueueVk, CreationAttribs, ppDevice, ppContexts, NumDeferredContexts);
+#endif
+}
+
+#if 0
+/// Attaches to existing Vk device
+
+/// \param [in] pVkNativeDevice - pointer to native Vk device
+/// \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
+/// the created device will be written
+/// \param [out] ppContexts - Address of the memory location where pointers to
+/// the contexts will be written. Pointer to the immediate
+/// context goes at position 0. If NumDeferredContexts > 0,
+/// pointers to the deferred contexts go afterwards.
+/// \param [in] NumDeferredContexts - Number of deferred contexts. If non-zero number
+/// of deferred contexts is requested, pointers to the
+/// contexts are written to ppContexts array starting
+/// at position 1
+void EngineFactoryVkImpl::AttachToVkDevice(void *pVkNativeDevice,
+ ICommandQueueVk *pCommandQueue,
+ const EngineVkAttribs& EngineAttribs,
+ IRenderDevice **ppDevice,
+ IDeviceContext **ppContexts,
+ Uint32 NumDeferredContexts)
+{
+ VERIFY( pVkNativeDevice && pCommandQueue && ppDevice && ppContexts, "Null pointer provided" );
+ if( !pVkNativeDevice || !pCommandQueue || !ppDevice || !ppContexts )
+ return;
+
+ *ppDevice = nullptr;
+ memset(ppContexts, 0, sizeof(*ppContexts) * (1+NumDeferredContexts));
+
+ try
+ {
+ auto &RawMemAllocator = GetRawAllocator();
+ auto VkDevice = reinterpret_cast<IVkDevice*>(pVkNativeDevice);
+ RenderDeviceVkImpl *pRenderDeviceVk( NEW_RC_OBJ(RawMemAllocator, "RenderDeviceVkImpl instance", RenderDeviceVkImpl)(RawMemAllocator, EngineAttribs, VkDevice, pCommandQueue, NumDeferredContexts ) );
+ pRenderDeviceVk->QueryInterface(IID_RenderDevice, reinterpret_cast<IObject**>(ppDevice) );
+
+ RefCntAutoPtr<DeviceContextVkImpl> pImmediateCtxVk( NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, false, EngineAttribs, 0) );
+ // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceVk will
+ // keep a weak reference to the context
+ pImmediateCtxVk->QueryInterface(IID_DeviceContext, reinterpret_cast<IObject**>(ppContexts) );
+ pRenderDeviceVk->SetImmediateContext(pImmediateCtxVk);
+
+ for (Uint32 DeferredCtx = 0; DeferredCtx < NumDeferredContexts; ++DeferredCtx)
+ {
+ RefCntAutoPtr<DeviceContextVkImpl> pDeferredCtxVk( NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, true, EngineAttribs, 1+DeferredCtx) );
+ // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceVk will
+ // keep a weak reference to the context
+ pDeferredCtxVk->QueryInterface(IID_DeviceContext, reinterpret_cast<IObject**>(ppContexts + 1 + DeferredCtx) );
+ pRenderDeviceVk->SetDeferredContext(DeferredCtx, pDeferredCtxVk);
+ }
+ }
+ catch( const std::runtime_error & )
+ {
+ if( *ppDevice )
+ {
+ (*ppDevice)->Release();
+ *ppDevice = nullptr;
+ }
+ for(Uint32 ctx=0; ctx < 1 + NumDeferredContexts; ++ctx)
+ {
+ if( ppContexts[ctx] != nullptr )
+ {
+ ppContexts[ctx]->Release();
+ ppContexts[ctx] = nullptr;
+ }
+ }
+
+ LOG_ERROR( "Failed to create device and contexts" );
+ }
+}
+#endif
+
+/// Creates a swap chain for Direct3D12-based engine implementation
+
+/// \param [in] pDevice - Pointer to the render device
+/// \param [in] pImmediateContext - Pointer to the immediate device context
+/// \param [in] SCDesc - Swap chain description
+/// \param [in] pNativeWndHandle - Platform-specific native handle of the window
+/// the swap chain will be associated with:
+/// * On Win32 platform, this should be window handle (HWND)
+/// * On Universal Windows Platform, this should be reference to the
+/// core window (Windows::UI::Core::CoreWindow)
+///
+/// \param [out] ppSwapChain - Address of the memory location where pointer to the new
+/// swap chain will be written
+void EngineFactoryVkImpl::CreateSwapChainVk( IRenderDevice *pDevice,
+ IDeviceContext *pImmediateContext,
+ const SwapChainDesc& SCDesc,
+ void* pNativeWndHandle,
+ ISwapChain **ppSwapChain )
+{
+ VERIFY( ppSwapChain, "Null pointer provided" );
+ if( !ppSwapChain )
+ return;
+
+ *ppSwapChain = nullptr;
+
+#if 0
+ try
+ {
+ auto *pDeviceVk = ValidatedCast<RenderDeviceVkImpl>( pDevice );
+ auto *pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pImmediateContext);
+ auto &RawMemAllocator = GetRawAllocator();
+ auto *pSwapChainVk = NEW_RC_OBJ(RawMemAllocator, "SwapChainVkImpl instance", SwapChainVkImpl)(SCDesc, pDeviceVk, pDeviceContextVk, pNativeWndHandle);
+ pSwapChainVk->QueryInterface( IID_SwapChain, reinterpret_cast<IObject**>(ppSwapChain) );
+
+ pDeviceContextVk->SetSwapChain(pSwapChainVk);
+ // Bind default render target
+ pDeviceContextVk->SetRenderTargets( 0, nullptr, nullptr );
+ // Set default viewport
+ pDeviceContextVk->SetViewports( 1, nullptr, 0, 0 );
+
+ auto NumDeferredCtx = pDeviceVk->GetNumDeferredContexts();
+ for (size_t ctx = 0; ctx < NumDeferredCtx; ++ctx)
+ {
+ if (auto pDeferredCtx = pDeviceVk->GetDeferredContext(ctx))
+ {
+ auto *pDeferredCtxVk = ValidatedCast<DeviceContextVkImpl>(pDeferredCtx.RawPtr());
+ pDeferredCtxVk->SetSwapChain(pSwapChainVk);
+ // We cannot bind default render target here because
+ // there is no guarantee that deferred context will be used
+ // in this frame. It is an error to bind
+ // RTV of an inactive buffer in the swap chain
+ }
+ }
+ }
+ catch( const std::runtime_error & )
+ {
+ if( *ppSwapChain )
+ {
+ (*ppSwapChain)->Release();
+ *ppSwapChain = nullptr;
+ }
+
+ LOG_ERROR( "Failed to create the swap chain" );
+ }
+#endif
+}
+
+
+#ifdef DOXYGEN
+/// Loads Direct3D12-based engine implementation and exports factory functions
+/// \param [out] GetFactoryFunc - Pointer to the function that returns factory for Vk engine implementation.
+/// See EngineFactoryVkImpl.
+/// \remarks Depending on the configuration and platform, the function loads different dll:
+/// Platform\\Configuration | Debug | Release
+/// --------------------------|-------------------------------|----------------------------
+/// x86 | GraphicsEngineVk_32d.dll | GraphicsEngineVk_32r.dll
+/// x64 | GraphicsEngineVk_64d.dll | GraphicsEngineVk_64r.dll
+///
+void LoadGraphicsEngineVk(GetEngineFactoryVkType &GetFactoryFunc)
+{
+ // This function is only required because DoxyGen refuses to generate documentation for a static function when SHOW_FILES==NO
+ #error This function must never be compiled;
+}
+#endif
+
+
+IEngineFactoryVk* GetEngineFactoryVk()
+{
+ return EngineFactoryVkImpl::GetInstance();
+}
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
new file mode 100644
index 00000000..36f2bfd8
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
@@ -0,0 +1,634 @@
+/* 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 "RenderDeviceVkImpl.h"
+#include "PipelineStateVkImpl.h"
+#include "ShaderVkImpl.h"
+#include "TextureVkImpl.h"
+//#include "DXGITypeConversions.h"
+#include "SamplerVkImpl.h"
+#include "BufferVkImpl.h"
+#include "ShaderResourceBindingVkImpl.h"
+#include "DeviceContextVkImpl.h"
+
+#include "EngineMemory.h"
+namespace Diligent
+{
+
+RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters, IMemoryAllocator &RawMemAllocator, const EngineVkAttribs &CreationAttribs, void *pVkDevice, ICommandQueueVk *pCmdQueue, Uint32 NumDeferredContexts) :
+ TRenderDeviceBase(pRefCounters, RawMemAllocator, NumDeferredContexts, sizeof(TextureVkImpl), sizeof(TextureViewVkImpl), sizeof(BufferVkImpl), sizeof(BufferViewVkImpl), sizeof(ShaderVkImpl), sizeof(SamplerVkImpl), sizeof(PipelineStateVkImpl), sizeof(ShaderResourceBindingVkImpl))/*,
+ m_pVkDevice(pVkDevice),
+ m_pCommandQueue(pCmdQueue),
+ m_EngineAttribs(CreationAttribs),
+ m_FrameNumber(0),
+ m_NextCmdListNumber(0),
+ m_CmdListManager(this),
+ m_CPUDescriptorHeaps
+ {
+ {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[0], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Vk_DESCRIPTOR_HEAP_FLAG_NONE},
+ {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[1], Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, Vk_DESCRIPTOR_HEAP_FLAG_NONE},
+ {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[2], Vk_DESCRIPTOR_HEAP_TYPE_RTV, Vk_DESCRIPTOR_HEAP_FLAG_NONE},
+ {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[3], Vk_DESCRIPTOR_HEAP_TYPE_DSV, Vk_DESCRIPTOR_HEAP_FLAG_NONE}
+ },
+ m_GPUDescriptorHeaps
+ {
+ {RawMemAllocator, this, CreationAttribs.GPUDescriptorHeapSize[0], CreationAttribs.GPUDescriptorHeapDynamicSize[0], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE},
+ {RawMemAllocator, this, CreationAttribs.GPUDescriptorHeapSize[1], CreationAttribs.GPUDescriptorHeapDynamicSize[1], Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}
+ },
+ m_DynamicDescriptorAllocationChunkSize
+ {
+ CreationAttribs.DynamicDescriptorAllocationChunkSize[0], // Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV
+ 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_VkObjReleaseQueue(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_DeviceCaps.DevType = DeviceType::Vulkan;
+ m_DeviceCaps.MajorVersion = 12;
+ m_DeviceCaps.MinorVersion = 0;
+ m_DeviceCaps.bSeparableProgramSupported = True;
+ m_DeviceCaps.bMultithreadedResourceCreationSupported = True;
+}
+
+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();
+ // Wait for the GPU to complete all its operations
+ IdleGPU(true);
+ // Call FinishFrame() again to destroy resources in
+ // release queues
+ FinishFrame(true);
+
+ m_ContextPool.clear();
+#endif
+}
+
+#if 0
+void RenderDeviceVkImpl::DisposeCommandContext(CommandContext* pCtx)
+{
+ std::lock_guard<std::mutex> LockGuard(m_ContextAllocationMutex);
+ m_AvailableContexts.push_back(pCtx);
+}
+
+void RenderDeviceVkImpl::CloseAndExecuteCommandContext(CommandContext *pCtx, bool DiscardStaleObjects)
+{
+ CComPtr<IVkCommandAllocator> pAllocator;
+ auto *pCmdList = pCtx->Close(&pAllocator);
+
+ Uint64 FenceValue = 0;
+ Uint64 CmdListNumber = 0;
+ {
+ 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);
+ 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;
+ Atomics::AtomicIncrement(m_NextCmdListNumber);
+ }
+
+ if (DiscardStaleObjects)
+ {
+ // 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
+ //
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+
+ // Stale objects should only be discarded when submitting cmd list from
+ // the immediate context, otherwise the basic requirement may be violated
+ // as in the following scenario
+ //
+ // Signaled | |
+ // Fence Value | Immediate Context | InitContext |
+ // | | |
+ // N | Draw(ResourceX) | |
+ // | Release(ResourceX) | |
+ // | - (ResourceX, N) -> Release Queue | |
+ // | | CopyResource() |
+ // N+1 | | CloseAndExecuteCommandContext() |
+ // | | |
+ // N+2 | CloseAndExecuteCommandContext() | |
+ // | - Cmd list is submitted with number | |
+ // | N+1, but resource it references | |
+ // | was added to the delete queue | |
+ // | with number N | |
+
+ // Move stale objects into a release queue.
+ // Note that objects are moved from stale list to release queue based on the
+ // cmd list number, not the fence value. This makes sure that basic requirement
+ // is met even when the fence value is not incremented while executing
+ // the command list (as is the case with Unity command queue).
+ DiscardStaleVkObjects(CmdListNumber, FenceValue);
+ }
+
+ // DiscardAllocator() is thread-safe
+ m_CmdListManager.DiscardAllocator(FenceValue, pAllocator);
+
+ pCtx->DiscardDynamicDescriptors(FenceValue);
+
+ {
+ 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();
+ // 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.
+ // This is necessary to release outstanding references to the
+ // swap chain buffers when it is resized in the middle of the frame.
+ // Since GPU has been idled, it it is safe to do so
+ DiscardStaleVkObjects(CmdListNumber, FenceValue);
+ ProcessReleaseQueue(FenceValue);
+ }
+}
+
+Bool RenderDeviceVkImpl::IsFenceSignaled(Uint64 FenceValue)
+{
+ return FenceValue <= GetCompletedFenceValue();
+}
+
+Uint64 RenderDeviceVkImpl::GetCompletedFenceValue()
+{
+ return m_pCommandQueue->GetCompletedFenceValue();
+}
+
+void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources)
+{
+ {
+ if (auto pImmediateCtx = m_wpImmediateContext.Lock())
+ {
+ auto pImmediateCtxVk = ValidatedCast<DeviceContextVkImpl>(pImmediateCtx.RawPtr());
+ if(pImmediateCtxVk->GetNumCommandsInCtx() != 0)
+ LOG_ERROR_MESSAGE("There are outstanding commands in the immediate device context when finishing the frame. This is an error and may cause unpredicted behaviour. Call Flush() to submit all commands for execution before finishing the frame");
+ }
+
+ for (auto wpDeferredCtx : m_wpDeferredContexts)
+ {
+ if (auto pDeferredCtx = wpDeferredCtx.Lock())
+ {
+ auto pDeferredCtxVk = ValidatedCast<DeviceContextVkImpl>(pDeferredCtx.RawPtr());
+ if(pDeferredCtxVk->GetNumCommandsInCtx() != 0)
+ LOG_ERROR_MESSAGE("There are outstanding commands in the deferred device context when finishing the frame. This is an error and may cause unpredicted behaviour. Close all deferred contexts and execute them before finishing the frame");
+ }
+ }
+ }
+
+ auto CompletedFenceValue = ReleaseAllResources ? std::numeric_limits<Uint64>::max() : GetCompletedFenceValue();
+
+ // We must use NextFenceValue here, NOT current value, because the
+ // fence value may or may not have been incremented when the last
+ // command list was submitted for execution (Unity only
+ // increments fence value once per frame)
+ Uint64 NextFenceValue = 0;
+ Uint64 CmdListNumber = 0;
+ {
+ // Lock the command queue to avoid other threads interfering with the GPU
+ std::lock_guard<std::mutex> LockGuard(m_CmdQueueMutex);
+ NextFenceValue = m_pCommandQueue->GetNextFenceValue();
+ // 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);
+ }
+
+ {
+ // There is no need to lock as new heaps are only created during initialization
+ // time for every context
+ //std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex);
+
+ // Upload heaps are used to update resource contents as well as to allocate
+ // space for dynamic resources.
+ // Initial resource data is uploaded using temporary one-time upload buffers,
+ // so can be performed in parallel across frame boundaries
+ for (auto &UploadHeap : m_UploadHeaps)
+ {
+ // Currently upload heaps are free-threaded, so other threads must not allocate
+ // resources at the same time. This means that all dynamic buffers must be unmaped
+ // in the same frame and all resources must be updated within boundaries of a single frame.
+ //
+ // worker thread 3 | pDevice->CrateTexture(InitData) | | pDevice->CrateBuffer(InitData) | | pDevice->CrateTexture(InitData) |
+ //
+ // worker thread 2 | pDfrdCtx2->UpdateResource() | ||
+ // ||
+ // worker thread 1 | pDfrdCtx1->Map(WRITE_DISCARD) | | pDfrdCtx1->UpdateResource() | ||
+ // ||
+ // main thread | pCtx->Map(WRITE_DISCARD )| | pCtx->UpdateResource() | || | Present() |
+ //
+ //
+
+ UploadHeap->FinishFrame(NextFenceValue, CompletedFenceValue);
+ }
+ }
+
+ for(Uint32 CPUHeap=0; CPUHeap < _countof(m_CPUDescriptorHeaps); ++CPUHeap)
+ {
+ // This is OK if other thread disposes descriptor heap allocation at this time
+ // The allocation will be registered as part of the current frame
+ m_CPUDescriptorHeaps[CPUHeap].ReleaseStaleAllocations(CompletedFenceValue);
+ }
+
+ for(Uint32 GPUHeap=0; GPUHeap < _countof(m_GPUDescriptorHeaps); ++GPUHeap)
+ {
+ m_GPUDescriptorHeaps[GPUHeap].ReleaseStaleAllocations(CompletedFenceValue);
+ }
+
+ // Discard all remaining objects. This is important to do if there were
+ // no command lists submitted during the frame
+ DiscardStaleVkObjects(CmdListNumber, NextFenceValue);
+ ProcessReleaseQueue(CompletedFenceValue);
+
+ Atomics::AtomicIncrement(m_FrameNumber);
+}
+
+DynamicUploadHeap* RenderDeviceVkImpl::RequestUploadHeap()
+{
+ std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex);
+
+#ifdef _DEBUG
+ size_t InitialSize = 1024+64;
+#else
+ size_t InitialSize = 64<<10;//16<<20;
+#endif
+
+ auto &UploadHeapAllocator = GetRawAllocator();
+ auto *pRawMem = ALLOCATE(UploadHeapAllocator, "DynamicUploadHeap instance", sizeof(DynamicUploadHeap));
+ auto *pNewHeap = new (pRawMem) DynamicUploadHeap(GetRawAllocator(), true, this, InitialSize);
+ m_UploadHeaps.emplace_back( pNewHeap, STDDeleterRawMem<DynamicUploadHeap>(UploadHeapAllocator) );
+ return pNewHeap;
+}
+
+void RenderDeviceVkImpl::ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap)
+{
+
+}
+
+CommandContext* RenderDeviceVkImpl::AllocateCommandContext(const Char *ID)
+{
+ std::lock_guard<std::mutex> LockGuard(m_ContextAllocationMutex);
+
+ CommandContext* ret = nullptr;
+ if (m_AvailableContexts.empty())
+ {
+ auto &CmdCtxAllocator = GetRawAllocator();
+ auto *pRawMem = ALLOCATE(CmdCtxAllocator, "CommandContext instance", sizeof(CommandContext));
+ ret = new (pRawMem) CommandContext( GetRawAllocator(), m_CmdListManager, m_GPUDescriptorHeaps, m_DynamicDescriptorAllocationChunkSize);
+ m_ContextPool.emplace_back(ret, STDDeleterRawMem<CommandContext>(CmdCtxAllocator) );
+ }
+ else
+ {
+ ret = m_AvailableContexts.front();
+ m_AvailableContexts.pop_front();
+ ret->Reset(m_CmdListManager);
+ }
+ VERIFY_EXPR(ret != nullptr);
+ ret->SetID(ID);
+ //if ( ID != nullptr && *ID != 0 )
+ // EngineProfiling::BeginBlock(ID, NewContext);
+
+ return ret;
+}
+
+void RenderDeviceVkImpl::SafeReleaseVkObject(IVkObject* pObj)
+{
+ // 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);
+ m_StaleVkObjects.emplace_back( m_NextCmdListNumber, CComPtr<IVkObject>(pObj) );
+}
+
+void RenderDeviceVkImpl::DiscardStaleVkObjects(Uint64 CmdListNumber, Uint64 FenceValue)
+{
+ // Only discard these stale objects that were released before CmdListNumber
+ // was executed
+ std::lock_guard<std::mutex> StaleObjectsLock(m_StaleObjectsMutex);
+ std::lock_guard<std::mutex> ReleaseQueueLock(m_ReleaseQueueMutex);
+ while (!m_StaleVkObjects.empty() )
+ {
+ auto &FirstStaleObj = m_StaleVkObjects.front();
+ if (FirstStaleObj.first <= CmdListNumber)
+ {
+ m_VkObjReleaseQueue.emplace_back(FenceValue, std::move(FirstStaleObj.second));
+ m_StaleVkObjects.pop_front();
+ }
+ else
+ break;
+ }
+}
+
+void RenderDeviceVkImpl::ProcessReleaseQueue(Uint64 CompletedFenceValue)
+{
+ std::lock_guard<std::mutex> LockGuard(m_ReleaseQueueMutex);
+
+ // Release all objects whose associated fence value is at most CompletedFenceValue
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+ while (!m_VkObjReleaseQueue.empty())
+ {
+ auto &FirstObj = m_VkObjReleaseQueue.front();
+ if (FirstObj.first <= CompletedFenceValue)
+ m_VkObjReleaseQueue.pop_front();
+ else
+ break;
+ }
+}
+
+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
+}
+
+void RenderDeviceVkImpl::TestTextureFormat( TEXTURE_FORMAT TexFormat )
+{
+ 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 );
+ }
+
+ // Create test texture 2D
+ TexFormatInfo.Tex2DFmt = false;
+ TexFormatInfo.TexCubeFmt = false;
+ TexFormatInfo.ColorRenderable = false;
+ TexFormatInfo.DepthRenderable = false;
+ TexFormatInfo.SupportsMS = false;
+ {
+ ResDesc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE2D;
+ ResDesc.Height = TestTextureDim;
+ TexFormatInfo.Tex2DFmt = CreateTestResource( m_pVkDevice, ResDesc );
+
+ if( TexFormatInfo.Tex2DFmt )
+ {
+ {
+ // Vk_TEXTURE2D_DESC CubeTexDesc = Tex2DDesc;
+ ResDesc.DepthOrArraySize = 6;
+ // CubeTexDesc.MiscFlags = Vk_RESOURCE_MISC_TEXTURECUBE;
+ TexFormatInfo.TexCubeFmt = CreateTestResource( m_pVkDevice, ResDesc );
+ ResDesc.DepthOrArraySize = 1;
+ }
+
+ 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 );
+ }
+ }
+ else if( TexFormatInfo.ComponentType != COMPONENT_TYPE_COMPRESSED &&
+ TexFormatInfo.Format != DXGI_FORMAT_R9G9B9E5_SHAREDEXP )
+ {
+ 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 );
+ }
+ }
+ }
+ }
+
+ // 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) )
+ {
+ ResDesc.SampleDesc.Count = 1;
+ ResDesc.Dimension = Vk_RESOURCE_DIMENSION_TEXTURE3D;
+ ResDesc.Flags = DefaultResourceFlags;
+ ResDesc.DepthOrArraySize = TestTextureDepth;
+ TexFormatInfo.Tex3DFmt = CreateTestResource( m_pVkDevice, ResDesc );
+ }
+}
+#endif
+
+IMPLEMENT_QUERY_INTERFACE( RenderDeviceVkImpl, IID_RenderDeviceVk, TRenderDeviceBase )
+
+void RenderDeviceVkImpl::CreatePipelineState(const PipelineStateDesc &PipelineDesc, IPipelineState **ppPipelineState)
+{
+ CreateDeviceObject("Pipeline State", PipelineDesc, ppPipelineState,
+ [&]()
+ {
+ PipelineStateVkImpl *pPipelineStateVk( NEW_RC_OBJ(m_PSOAllocator, "PipelineStateVkImpl instance", PipelineStateVkImpl)(this, PipelineDesc ) );
+ pPipelineStateVk->QueryInterface( IID_PipelineState, reinterpret_cast<IObject**>(ppPipelineState) );
+ OnCreateDeviceObject( pPipelineStateVk );
+ }
+ );
+}
+
+#if 0
+void RenderDeviceVkImpl :: CreateBufferFromD3DResource(IVkResource *pVkBuffer, const BufferDesc& BuffDesc, IBuffer **ppBuffer)
+{
+ CreateDeviceObject("buffer", BuffDesc, ppBuffer,
+ [&]()
+ {
+ BufferVkImpl *pBufferVk( NEW_RC_OBJ(m_BufObjAllocator, "BufferVkImpl instance", BufferVkImpl)(m_BuffViewObjAllocator, this, BuffDesc, pVkBuffer ) );
+ pBufferVk->QueryInterface( IID_Buffer, reinterpret_cast<IObject**>(ppBuffer) );
+ pBufferVk->CreateDefaultViews();
+ OnCreateDeviceObject( pBufferVk );
+ }
+ );
+}
+#endif
+
+void RenderDeviceVkImpl :: CreateBuffer(const BufferDesc& BuffDesc, const BufferData &BuffData, IBuffer **ppBuffer)
+{
+ CreateDeviceObject("buffer", BuffDesc, ppBuffer,
+ [&]()
+ {
+ BufferVkImpl *pBufferVk( NEW_RC_OBJ(m_BufObjAllocator, "BufferVkImpl instance", BufferVkImpl)(m_BuffViewObjAllocator, this, BuffDesc, BuffData ) );
+ pBufferVk->QueryInterface( IID_Buffer, reinterpret_cast<IObject**>(ppBuffer) );
+ pBufferVk->CreateDefaultViews();
+ OnCreateDeviceObject( pBufferVk );
+ }
+ );
+}
+
+
+void RenderDeviceVkImpl :: CreateShader(const ShaderCreationAttribs &ShaderCreationAttribs, IShader **ppShader)
+{
+ CreateDeviceObject( "shader", ShaderCreationAttribs.Desc, ppShader,
+ [&]()
+ {
+ ShaderVkImpl *pShaderVk( NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderVkImpl instance", ShaderVkImpl)(this, ShaderCreationAttribs ) );
+ pShaderVk->QueryInterface( IID_Shader, reinterpret_cast<IObject**>(ppShader) );
+
+ OnCreateDeviceObject( pShaderVk );
+ }
+ );
+}
+
+#if 0
+void RenderDeviceVkImpl::CreateTextureFromD3DResource(IVkResource *pVkTexture, ITexture **ppTexture)
+{
+ TextureDesc TexDesc;
+ TexDesc.Name = "Texture from Vk resource";
+ CreateDeviceObject( "texture", TexDesc, ppTexture,
+ [&]()
+ {
+ TextureVkImpl *pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, pVkTexture );
+
+ pTextureVk->QueryInterface( IID_Texture, reinterpret_cast<IObject**>(ppTexture) );
+ pTextureVk->CreateDefaultViews();
+ OnCreateDeviceObject( pTextureVk );
+ }
+ );
+}
+
+
+void RenderDeviceVkImpl::CreateTexture(const TextureDesc& TexDesc, IVkResource *pVkTexture, class TextureVkImpl **ppTexture)
+{
+ CreateDeviceObject( "texture", TexDesc, ppTexture,
+ [&]()
+ {
+ TextureVkImpl *pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, pVkTexture );
+ pTextureVk->QueryInterface( IID_TextureVk, reinterpret_cast<IObject**>(ppTexture) );
+ }
+ );
+}
+
+#endif
+
+void RenderDeviceVkImpl :: CreateTexture(const TextureDesc& TexDesc, const TextureData &Data, ITexture **ppTexture)
+{
+ CreateDeviceObject( "texture", TexDesc, ppTexture,
+ [&]()
+ {
+ TextureVkImpl *pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, Data );
+
+ pTextureVk->QueryInterface( IID_Texture, reinterpret_cast<IObject**>(ppTexture) );
+ pTextureVk->CreateDefaultViews();
+ OnCreateDeviceObject( pTextureVk );
+ }
+ );
+}
+
+void RenderDeviceVkImpl :: CreateSampler(const SamplerDesc& SamplerDesc, ISampler **ppSampler)
+{
+ CreateDeviceObject( "sampler", SamplerDesc, ppSampler,
+ [&]()
+ {
+ m_SamplersRegistry.Find( SamplerDesc, reinterpret_cast<IDeviceObject**>(ppSampler) );
+ if( *ppSampler == nullptr )
+ {
+ SamplerVkImpl *pSamplerVk( NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerVkImpl instance", SamplerVkImpl)(this, SamplerDesc ) );
+ pSamplerVk->QueryInterface( IID_Sampler, reinterpret_cast<IObject**>(ppSampler) );
+ OnCreateDeviceObject( pSamplerVk );
+ m_SamplersRegistry.Add( SamplerDesc, *ppSampler );
+ }
+ }
+ );
+}
+
+#if 0
+DescriptorHeapAllocation RenderDeviceVkImpl :: AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE Type, UINT Count /*= 1*/)
+{
+ VERIFY(Type >= Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && Type < Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES, "Invalid heap type");
+ return m_CPUDescriptorHeaps[Type].Allocate(Count);
+}
+
+DescriptorHeapAllocation RenderDeviceVkImpl :: AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE Type, UINT Count /*= 1*/)
+{
+ VERIFY(Type >= Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && Type <= Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, "Invalid heap type");
+ return m_GPUDescriptorHeaps[Type].Allocate(Count);
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/RootSignature.cpp b/Graphics/GraphicsEngineVulkan/src/RootSignature.cpp
new file mode 100644
index 00000000..6a72824c
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/RootSignature.cpp
@@ -0,0 +1,1033 @@
+/* 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 "RootSignature.h"
+#include "ShaderResourceLayoutVk.h"
+#include "ShaderVkImpl.h"
+#include "CommandContext.h"
+#include "RenderDeviceVkImpl.h"
+#include "TextureVkImpl.h"
+#include "BufferVkImpl.h"
+#include "VulkanTypeConversions.h"
+#include "HashUtils.h"
+
+namespace Diligent
+{
+
+#if 0
+RootSignature::RootParamsManager::RootParamsManager(IMemoryAllocator &MemAllocator):
+ m_MemAllocator(MemAllocator),
+ m_pMemory(nullptr, STDDeleter<void, IMemoryAllocator>(MemAllocator))
+{}
+
+size_t RootSignature::RootParamsManager::GetRequiredMemorySize(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges)const
+{
+ return sizeof(RootParameter) * (m_NumRootTables + NumExtraRootTables + m_NumRootViews + NumExtraRootViews) + sizeof(Vk_DESCRIPTOR_RANGE) * (m_TotalDescriptorRanges + NumExtraDescriptorRanges);
+}
+
+Vk_DESCRIPTOR_RANGE* RootSignature::RootParamsManager::Extend(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges, Uint32 RootTableToAddRanges)
+{
+ VERIFY(NumExtraRootTables > 0 || NumExtraRootViews > 0 || NumExtraDescriptorRanges > 0, "At least one root table, root view or descriptor range must be added" );
+ auto MemorySize = GetRequiredMemorySize(NumExtraRootTables, NumExtraRootViews, NumExtraDescriptorRanges);
+ VERIFY_EXPR(MemorySize > 0);
+ auto *pNewMemory = ALLOCATE(m_MemAllocator, "Memory buffer for root tables, root views & descriptor ranges", MemorySize);
+ memset(pNewMemory, 0, MemorySize);
+
+ // Note: this order is more efficient than views->tables->ranges
+ auto *pNewRootTables = reinterpret_cast<RootParameter*>(pNewMemory);
+ auto *pNewRootViews = pNewRootTables + (m_NumRootTables + NumExtraRootTables);
+ auto *pCurrDescriptorRangePtr = reinterpret_cast<Vk_DESCRIPTOR_RANGE*>(pNewRootViews+m_NumRootViews+NumExtraRootViews);
+
+ // Copy existing root tables to new memory
+ for (Uint32 rt = 0; rt < m_NumRootTables; ++rt)
+ {
+ const auto &SrcTbl = GetRootTable(rt);
+ auto &VkSrcTbl = static_cast<const Vk_ROOT_PARAMETER&>(SrcTbl).DescriptorTable;
+ auto NumRanges = VkSrcTbl.NumDescriptorRanges;
+ if(rt == RootTableToAddRanges)
+ {
+ VERIFY(NumExtraRootTables == 0 || NumExtraRootTables == 1, "Up to one descriptor table can be extended at a time");
+ NumRanges += NumExtraDescriptorRanges;
+ }
+ new(pNewRootTables + rt) RootParameter(SrcTbl, NumRanges, pCurrDescriptorRangePtr);
+ pCurrDescriptorRangePtr += NumRanges;
+ }
+
+ // Copy existing root views to new memory
+ for (Uint32 rv = 0; rv < m_NumRootViews; ++rv)
+ {
+ const auto &SrcView = GetRootView(rv);
+ new(pNewRootViews + rv) RootParameter(SrcView);
+ }
+
+ m_pMemory.reset(pNewMemory);
+ m_NumRootTables += NumExtraRootTables;
+ m_NumRootViews += NumExtraRootViews;
+ m_TotalDescriptorRanges += NumExtraDescriptorRanges;
+ m_pRootTables = m_NumRootTables != 0 ? pNewRootTables : nullptr;
+ m_pRootViews = m_NumRootViews != 0 ? pNewRootViews : nullptr;
+
+ return pCurrDescriptorRangePtr;
+}
+
+void RootSignature::RootParamsManager::AddRootView(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType)
+{
+ auto *pRangePtr = Extend(0, 1, 0);
+ VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0));
+ new(m_pRootViews + m_NumRootViews-1) RootParameter(ParameterType, RootIndex, Register, 0u, Visibility, VarType);
+}
+
+void RootSignature::RootParamsManager::AddRootTable(Uint32 RootIndex, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType, Uint32 NumRangesInNewTable)
+{
+ auto *pRangePtr = Extend(1, 0, NumRangesInNewTable);
+ VERIFY_EXPR( (char*)(pRangePtr + NumRangesInNewTable) == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0));
+ new(m_pRootTables + m_NumRootTables-1) RootParameter(Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, RootIndex, NumRangesInNewTable, pRangePtr, Visibility, VarType);
+}
+
+void RootSignature::RootParamsManager::AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges)
+{
+ auto *pRangePtr = Extend(0, 0, NumExtraRanges, RootTableInd);
+ VERIFY_EXPR( (char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0));
+}
+
+bool RootSignature::RootParamsManager::operator == (const RootParamsManager& RootParams)const
+{
+ if (m_NumRootTables != RootParams.m_NumRootTables ||
+ m_NumRootViews != RootParams.m_NumRootViews)
+ return false;
+
+ for (Uint32 rv = 0; rv < m_NumRootViews; ++rv)
+ {
+ const auto &RV0 = GetRootView(rv);
+ const auto &RV1 = RootParams.GetRootView(rv);
+ if (RV0 != RV1)
+ return false;
+ }
+
+ for (Uint32 rv = 0; rv < m_NumRootTables; ++rv)
+ {
+ const auto &RT0 = GetRootTable(rv);
+ const auto &RT1 = RootParams.GetRootTable(rv);
+ if (RT0 != RT1)
+ return false;
+ }
+
+ return true;
+}
+
+size_t RootSignature::RootParamsManager::GetHash()const
+{
+ size_t hash = ComputeHash(m_NumRootTables, m_NumRootViews);
+ for (Uint32 rv = 0; rv < m_NumRootViews; ++rv)
+ HashCombine(hash, GetRootView(rv).GetHash());
+
+ for (Uint32 rv = 0; rv < m_NumRootTables; ++rv)
+ HashCombine(hash, GetRootTable(rv).GetHash());
+
+ return hash;
+}
+
+RootSignature::RootSignature() :
+ m_RootParams(GetRawAllocator()),
+ m_MemAllocator(GetRawAllocator()),
+ m_StaticSamplers( STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector<StaticSamplerAttribs>") )
+{
+ for(size_t s=0; s < SHADER_VARIABLE_TYPE_NUM_TYPES; ++s)
+ {
+ m_TotalSrvCbvUavSlots[s] = 0;
+ m_TotalSamplerSlots[s] = 0;
+ }
+
+ for(size_t i=0; i < _countof(m_SrvCbvUavRootTablesMap); ++i)
+ m_SrvCbvUavRootTablesMap[i] = InvalidRootTableIndex;
+ for(size_t i=0; i < _countof(m_SamplerRootTablesMap); ++i)
+ m_SamplerRootTablesMap[i] = InvalidRootTableIndex;
+
+}
+
+static Vk_SHADER_VISIBILITY ShaderTypeInd2ShaderVisibilityMap[]
+{
+ Vk_SHADER_VISIBILITY_VERTEX, // 0
+ Vk_SHADER_VISIBILITY_PIXEL, // 1
+ Vk_SHADER_VISIBILITY_GEOMETRY, // 2
+ Vk_SHADER_VISIBILITY_HULL, // 3
+ Vk_SHADER_VISIBILITY_DOMAIN, // 4
+ Vk_SHADER_VISIBILITY_ALL // 5
+};
+Vk_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType)
+{
+ auto ShaderInd = GetShaderTypeIndex(ShaderType);
+ auto ShaderVisibility = ShaderTypeInd2ShaderVisibilityMap[ShaderInd];
+#ifdef _DEBUG
+ switch (ShaderType)
+ {
+ case SHADER_TYPE_VERTEX: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_VERTEX); break;
+ case SHADER_TYPE_PIXEL: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_PIXEL); break;
+ case SHADER_TYPE_GEOMETRY: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_GEOMETRY); break;
+ case SHADER_TYPE_HULL: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_HULL); break;
+ case SHADER_TYPE_DOMAIN: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_DOMAIN); break;
+ case SHADER_TYPE_COMPUTE: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_ALL); break;
+ default: LOG_ERROR("Unknown shader type (", ShaderType, ")"); break;
+ }
+#endif
+ return ShaderVisibility;
+}
+
+static SHADER_TYPE ShaderVisibility2ShaderTypeMap[] =
+{
+ SHADER_TYPE_COMPUTE, // Vk_SHADER_VISIBILITY_ALL = 0
+ SHADER_TYPE_VERTEX, // Vk_SHADER_VISIBILITY_VERTEX = 1
+ SHADER_TYPE_HULL, // Vk_SHADER_VISIBILITY_HULL = 2
+ SHADER_TYPE_DOMAIN, // Vk_SHADER_VISIBILITY_DOMAIN = 3
+ SHADER_TYPE_GEOMETRY, // Vk_SHADER_VISIBILITY_GEOMETRY = 4
+ SHADER_TYPE_PIXEL // Vk_SHADER_VISIBILITY_PIXEL = 5
+};
+SHADER_TYPE ShaderTypeFromShaderVisibility(Vk_SHADER_VISIBILITY ShaderVisibility)
+{
+ VERIFY_EXPR(ShaderVisibility >= Vk_SHADER_VISIBILITY_ALL && ShaderVisibility <= Vk_SHADER_VISIBILITY_PIXEL );
+ auto ShaderType = ShaderVisibility2ShaderTypeMap[ShaderVisibility];
+#ifdef _DEBUG
+ switch (ShaderVisibility)
+ {
+ case Vk_SHADER_VISIBILITY_VERTEX: VERIFY_EXPR(ShaderType == SHADER_TYPE_VERTEX); break;
+ case Vk_SHADER_VISIBILITY_PIXEL: VERIFY_EXPR(ShaderType == SHADER_TYPE_PIXEL); break;
+ case Vk_SHADER_VISIBILITY_GEOMETRY: VERIFY_EXPR(ShaderType == SHADER_TYPE_GEOMETRY); break;
+ case Vk_SHADER_VISIBILITY_HULL: VERIFY_EXPR(ShaderType == SHADER_TYPE_HULL); break;
+ case Vk_SHADER_VISIBILITY_DOMAIN: VERIFY_EXPR(ShaderType == SHADER_TYPE_DOMAIN); break;
+ case Vk_SHADER_VISIBILITY_ALL: VERIFY_EXPR(ShaderType == SHADER_TYPE_COMPUTE); break;
+ default: LOG_ERROR("Unknown shader visibility (", ShaderVisibility, ")"); break;
+ }
+#endif
+ return ShaderType;
+}
+
+
+static Vk_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[]
+{
+ Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_SRV = 0,
+ Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_UAV = ( Vk_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) ,
+ Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_CBV = ( Vk_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) ,
+ Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER //Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( Vk_DESCRIPTOR_RANGE_TYPE_CBV + 1 )
+};
+Vk_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(Vk_DESCRIPTOR_RANGE_TYPE RangeType)
+{
+ VERIFY_EXPR(RangeType >= Vk_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER);
+ auto HeapType = RangeType2HeapTypeMap[RangeType];
+
+#ifdef _DEBUG
+ switch (RangeType)
+ {
+ case Vk_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break;
+ case Vk_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break;
+ case Vk_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break;
+ case Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER); break;
+ default: UNEXPECTED("Unexpected descriptor range type"); break;
+ }
+#endif
+ return HeapType;
+}
+
+
+void RootSignature::InitStaticSampler(SHADER_TYPE ShaderType, const String &TextureName, const D3DShaderResourceAttribs &SamplerAttribs)
+{
+ auto ShaderVisibility = GetShaderVisibility(ShaderType);
+ auto SamplerFound = false;
+ for (auto &StSmplr : m_StaticSamplers)
+ {
+ if (StSmplr.ShaderVisibility == ShaderVisibility &&
+ TextureName.compare(StSmplr.SamplerDesc.TextureName) == 0)
+ {
+ StSmplr.ShaderRegister = SamplerAttribs.BindPoint;
+ StSmplr.ArraySize = SamplerAttribs.BindCount;
+ StSmplr.RegisterSpace = 0;
+ SamplerFound = true;
+ break;
+ }
+ }
+
+ if (!SamplerFound)
+ {
+ LOG_ERROR("Failed to find static sampler for variable \"", TextureName, '\"');
+ }
+}
+
+// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object
+void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderType,
+ const D3DShaderResourceAttribs &ShaderResAttribs,
+ Vk_DESCRIPTOR_RANGE_TYPE RangeType,
+ Uint32 &RootIndex, // Output parameter
+ Uint32 &OffsetFromTableStart // Output parameter
+ )
+{
+ auto ShaderInd = GetShaderTypeIndex(ShaderType);
+ auto ShaderVisibility = GetShaderVisibility(ShaderType);
+ if (RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV && ShaderResAttribs.BindCount == 1)
+ {
+ // Allocate single CBV directly in the root signature
+
+ // Get the next available root index past all allocated tables and root views
+ RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews();
+ OffsetFromTableStart = 0;
+
+ // Add new root view to existing root parameters
+ m_RootParams.AddRootView(Vk_ROOT_PARAMETER_TYPE_CBV, RootIndex, ShaderResAttribs.BindPoint, ShaderVisibility, ShaderResAttribs.GetVariableType());
+ }
+ else
+ {
+ // Use the same table for static and mutable resources. Treat both as static
+ auto RootTableType = (ShaderResAttribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC) ? SHADER_VARIABLE_TYPE_DYNAMIC : SHADER_VARIABLE_TYPE_STATIC;
+ auto TableIndKey = ShaderInd * SHADER_VARIABLE_TYPE_NUM_TYPES + RootTableType;
+ // Get the table array index (this is not the root index!)
+ auto &RootTableArrayInd = (( RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER ) ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[ TableIndKey ];
+ if (RootTableArrayInd == InvalidRootTableIndex)
+ {
+ // Root table has not been assigned to this combination yet
+
+ // Get the next available root index past all allocated tables and root views
+ RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews();
+ VERIFY_EXPR(m_RootParams.GetNumRootTables() < 255);
+ RootTableArrayInd = static_cast<Uint8>( m_RootParams.GetNumRootTables() );
+ // Add root table with one single-descriptor range
+ m_RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1);
+ }
+ else
+ {
+ // Add a new single-descriptor range to the existing table at index RootTableArrayInd
+ m_RootParams.AddDescriptorRanges(RootTableArrayInd, 1);
+ }
+
+ // Reference to either existing or just added table
+ auto &CurrParam = m_RootParams.GetRootTable(RootTableArrayInd);
+ RootIndex = CurrParam.GetRootIndex();
+
+ const auto& VkRootParam = static_cast<const Vk_ROOT_PARAMETER&>(CurrParam);
+
+ VERIFY( VkRootParam.ShaderVisibility == ShaderVisibility, "Shader visibility is not correct" );
+
+ // Descriptors are tightly packed, so the next descriptor offset is the
+ // current size of the table
+ OffsetFromTableStart = CurrParam.GetDescriptorTableSize();
+
+ // New just added range is the last range in the descriptor table
+ Uint32 NewDescriptorRangeIndex = VkRootParam.DescriptorTable.NumDescriptorRanges-1;
+ CurrParam.SetDescriptorRange(NewDescriptorRangeIndex,
+ RangeType, // Range type (CBV, SRV, UAV or SAMPLER)
+ ShaderResAttribs.BindPoint, // Shader register
+ ShaderResAttribs.BindCount, // Number of registers used (1 for non-array resources)
+ 0, // Register space. Always 0 for now
+ OffsetFromTableStart // Offset in descriptors from the table start
+ );
+ }
+}
+
+
+#ifdef _DEBUG
+void RootSignature::dbgVerifyRootParameters()const
+{
+ Uint32 dbgTotalSrvCbvUavSlots = 0;
+ Uint32 dbgTotalSamplerSlots = 0;
+ for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt)
+ {
+ auto &RootTable = m_RootParams.GetRootTable(rt);
+ auto &Param = static_cast<const Vk_ROOT_PARAMETER&>( RootTable );
+ VERIFY(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table");
+ auto &Table = Param.DescriptorTable;
+ VERIFY(Table.NumDescriptorRanges > 0, "Descriptor table is expected to be non-empty");
+ VERIFY(Table.pDescriptorRanges[0].OffsetInDescriptorsFromTableStart == 0, "Descriptor table is expected to start at 0 offset");
+ bool IsResourceTable = Table.pDescriptorRanges[0].RangeType != Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ for (Uint32 r = 0; r < Table.NumDescriptorRanges; ++r)
+ {
+ const auto &range = Table.pDescriptorRanges[r];
+ if(IsResourceTable)
+ {
+ VERIFY( range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV ||
+ range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV ||
+ range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Resource type is expected to be SRV, CBV or UAV");
+ dbgTotalSrvCbvUavSlots += range.NumDescriptors;
+ }
+ else
+ {
+ VERIFY(range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Resource type is expected to be sampler");
+ dbgTotalSamplerSlots += range.NumDescriptors;
+ }
+
+ if(r>0)
+ {
+ VERIFY(Table.pDescriptorRanges[r].OffsetInDescriptorsFromTableStart == Table.pDescriptorRanges[r-1].OffsetInDescriptorsFromTableStart+Table.pDescriptorRanges[r-1].NumDescriptors, "Ranges in a descriptor table are expected to be consequtive");
+ }
+ }
+ }
+
+ for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv)
+ {
+ auto &RootView = m_RootParams.GetRootView(rv);
+ auto &Param = static_cast<const Vk_ROOT_PARAMETER&>( RootView );
+ VERIFY(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV, "Root parameter is expected to be a CBV");
+ }
+
+ VERIFY(dbgTotalSrvCbvUavSlots ==
+ m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] +
+ m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE] +
+ m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC], "Unexpected number of SRV CBV UAV resource slots");
+ VERIFY(dbgTotalSamplerSlots ==
+ m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_STATIC] +
+ m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_MUTABLE] +
+ m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC], "Unexpected number of sampler slots");
+}
+#endif
+
+void RootSignature::AllocateStaticSamplers(IShader* const*ppShaders, Uint32 NumShaders)
+{
+ Uint32 TotalSamplers = 0;
+ for(Uint32 s=0;s < NumShaders; ++s)
+ TotalSamplers += ppShaders[s]->GetDesc().NumStaticSamplers;
+ if (TotalSamplers > 0)
+ {
+ m_StaticSamplers.reserve(TotalSamplers);
+ for(Uint32 sh=0;sh < NumShaders; ++sh)
+ {
+ const auto &Desc = ppShaders[sh]->GetDesc();
+ for(Uint32 sam=0; sam < Desc.NumStaticSamplers; ++sam)
+ {
+ m_StaticSamplers.emplace_back(Desc.StaticSamplers[sam], GetShaderVisibility(Desc.ShaderType));
+ }
+ }
+ VERIFY_EXPR(m_StaticSamplers.size() == TotalSamplers);
+ }
+}
+
+void RootSignature::Finalize(IVkDevice *pVkDevice)
+{
+ for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt)
+ {
+ auto &RootTbl = m_RootParams.GetRootTable(rt);
+ auto &VkRootParam = static_cast<const Vk_ROOT_PARAMETER&>(RootTbl);
+ VERIFY_EXPR(VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE);
+
+ auto TableSize = RootTbl.GetDescriptorTableSize();
+ VERIFY(VkRootParam.DescriptorTable.NumDescriptorRanges > 0 && TableSize > 0, "Unexpected empty descriptor table");
+ auto IsSamplerTable = VkRootParam.DescriptorTable.pDescriptorRanges[0].RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ auto VarType = RootTbl.GetShaderVariableType();
+ (IsSamplerTable ? m_TotalSamplerSlots : m_TotalSrvCbvUavSlots)[VarType] += TableSize;
+ }
+
+#ifdef _DEBUG
+ dbgVerifyRootParameters();
+#endif
+
+ Vk_ROOT_SIGNATURE_DESC rootSignatureDesc;
+ rootSignatureDesc.Flags = Vk_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ auto TotalParams = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews();
+ std::vector<Vk_ROOT_PARAMETER, STDAllocatorRawMem<Vk_ROOT_PARAMETER> > VkParameters( TotalParams, Vk_ROOT_PARAMETER(), STD_ALLOCATOR_RAW_MEM(Vk_ROOT_PARAMETER, GetRawAllocator(), "Allocator for vector<Vk_ROOT_PARAMETER>") );
+ for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt)
+ {
+ auto &RootTable = m_RootParams.GetRootTable(rt);
+ const Vk_ROOT_PARAMETER &SrcParam = RootTable;
+ VERIFY( SrcParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && SrcParam.DescriptorTable.NumDescriptorRanges > 0, "Non-empty descriptor table is expected" );
+ VkParameters[RootTable.GetRootIndex()] = SrcParam;
+ }
+ for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv)
+ {
+ auto &RootView = m_RootParams.GetRootView(rv);
+ const Vk_ROOT_PARAMETER &SrcParam = RootView;
+ VERIFY( SrcParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV, "Root CBV is expected" );
+ VkParameters[RootView.GetRootIndex()] = SrcParam;
+ }
+
+
+ rootSignatureDesc.NumParameters = static_cast<UINT>(VkParameters.size());
+ rootSignatureDesc.pParameters = VkParameters.size() ? VkParameters.data() : nullptr;
+
+ UINT TotalVkStaticSamplers = 0;
+ for(const auto &StSam : m_StaticSamplers)
+ TotalVkStaticSamplers += StSam.ArraySize;
+ rootSignatureDesc.NumStaticSamplers = TotalVkStaticSamplers;
+ rootSignatureDesc.pStaticSamplers = nullptr;
+ std::vector<Vk_STATIC_SAMPLER_DESC, STDAllocatorRawMem<Vk_STATIC_SAMPLER_DESC> > VkStaticSamplers( STD_ALLOCATOR_RAW_MEM(Vk_STATIC_SAMPLER_DESC, GetRawAllocator(), "Allocator for vector<Vk_STATIC_SAMPLER_DESC>") );
+ VkStaticSamplers.reserve(TotalVkStaticSamplers);
+ if ( !m_StaticSamplers.empty() )
+ {
+ for(size_t s=0; s < m_StaticSamplers.size(); ++s)
+ {
+ const auto &StSmplrDesc = m_StaticSamplers[s];
+ const auto &SamDesc = StSmplrDesc.SamplerDesc.Desc;
+ for(UINT ArrInd = 0; ArrInd < StSmplrDesc.ArraySize; ++ArrInd)
+ {
+ VkStaticSamplers.emplace_back(
+ Vk_STATIC_SAMPLER_DESC{
+ FilterTypeToVkFilter(SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter),
+ TexAddressModeToVkAddressMode(SamDesc.AddressU),
+ TexAddressModeToVkAddressMode(SamDesc.AddressV),
+ TexAddressModeToVkAddressMode(SamDesc.AddressW),
+ SamDesc.MipLODBias,
+ SamDesc.MaxAnisotropy,
+ ComparisonFuncToVkComparisonFunc(SamDesc.ComparisonFunc),
+ BorderColorToVkStaticBorderColor(SamDesc.BorderColor),
+ SamDesc.MinLOD,
+ SamDesc.MaxLOD,
+ StSmplrDesc.ShaderRegister + ArrInd,
+ StSmplrDesc.RegisterSpace,
+ StSmplrDesc.ShaderVisibility
+ }
+ );
+ }
+ }
+ rootSignatureDesc.pStaticSamplers = VkStaticSamplers.data();
+
+ // Release static samplers array, we no longer need it
+ std::vector<StaticSamplerAttribs, STDAllocatorRawMem<StaticSamplerAttribs> > EmptySamplers( STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector<StaticSamplerAttribs>") );
+ m_StaticSamplers.swap( EmptySamplers );
+
+ VERIFY_EXPR(VkStaticSamplers.size() == TotalVkStaticSamplers);
+ }
+
+
+ CComPtr<ID3DBlob> signature;
+ CComPtr<ID3DBlob> error;
+ HRESULT hr = VkSerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
+ hr = pVkDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(m_pVkRootSignature), reinterpret_cast<void**>( static_cast<IVkRootSignature**>(&m_pVkRootSignature)));
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature");
+
+ bool bHasDynamicResources = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC]!=0 || m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC]!=0;
+ if(bHasDynamicResources)
+ {
+ CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<false>;
+ TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<true>;
+ }
+ else
+ {
+ CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<false>;
+ TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<true>;
+ }
+}
+
+//http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Initializing-the-Cache-for-Shader-Resource-Binding-Object
+void RootSignature::InitResourceCache(RenderDeviceVkImpl *pDeviceVkImpl, ShaderResourceCacheVk& ResourceCache, IMemoryAllocator &CacheMemAllocator)const
+{
+ // Get root table size for every root index
+ // m_RootParams keeps root tables sorted by the array index, not the root index
+ // Root views are treated as one-descriptor tables
+ std::vector<Uint32, STDAllocatorRawMem<Uint32> > CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector<Uint32>") );
+ for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt)
+ {
+ auto &RootParam = m_RootParams.GetRootTable(rt);
+ CacheTableSizes[RootParam.GetRootIndex()] = RootParam.GetDescriptorTableSize();
+ }
+
+ for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv)
+ {
+ auto &RootParam = m_RootParams.GetRootView(rv);
+ CacheTableSizes[RootParam.GetRootIndex()] = 1;
+ }
+ // Initialize resource cache to hold root tables
+ ResourceCache.Initialize(CacheMemAllocator, static_cast<Uint32>(CacheTableSizes.size()), CacheTableSizes.data());
+
+ // Allocate space in GPU-visible descriptor heap for static and mutable variables only
+ Uint32 TotalSrvCbvUavDescriptors =
+ m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] +
+ m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE];
+ Uint32 TotalSamplerDescriptors =
+ m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_STATIC] +
+ m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_MUTABLE];
+
+ DescriptorHeapAllocation CbcSrvUavHeapSpace, SamplerHeapSpace;
+ if(TotalSrvCbvUavDescriptors)
+ CbcSrvUavHeapSpace = pDeviceVkImpl->AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, TotalSrvCbvUavDescriptors);
+ VERIFY_EXPR(TotalSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.IsNull() || CbcSrvUavHeapSpace.GetNumHandles() == TotalSrvCbvUavDescriptors);
+
+ if(TotalSamplerDescriptors)
+ SamplerHeapSpace = pDeviceVkImpl->AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, TotalSamplerDescriptors);
+ VERIFY_EXPR(TotalSamplerDescriptors == 0 && SamplerHeapSpace.IsNull() || SamplerHeapSpace.GetNumHandles() == TotalSamplerDescriptors);
+
+ // Iterate through all root static/mutable tables and assign start offsets. The tables are tightly packed, so
+ // start offset of table N+1 is start offset of table N plus the size of table N.
+ // Root tables with dynamic resources as well as root views are not assigned space in GPU-visible allocation
+ // (root views are simply not processed)
+ Uint32 SrvCbvUavTblStartOffset = 0;
+ Uint32 SamplerTblStartOffset = 0;
+ for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt)
+ {
+ auto &RootParam = m_RootParams.GetRootTable(rt);
+ const auto& VkRootParam = static_cast<const Vk_ROOT_PARAMETER&>(RootParam);
+ auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex());
+
+ SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN;
+#ifdef _DEBUG
+ dbgShaderType = ShaderTypeFromShaderVisibility(VkRootParam.ShaderVisibility);
+#endif
+ VERIFY_EXPR( VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE );
+
+ auto TableSize = RootParam.GetDescriptorTableSize();
+ VERIFY(TableSize > 0, "Unexpected empty descriptor table");
+
+ auto HeapType = HeapTypeFromRangeType(VkRootParam.DescriptorTable.pDescriptorRanges[0].RangeType);
+
+#ifdef _DEBUG
+ RootTableCache.SetDebugAttribs( TableSize, HeapType, dbgShaderType );
+#endif
+
+ // Space for dynamic variables is allocated at every draw call
+ if( RootParam.GetShaderVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC )
+ {
+ if( HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV )
+ {
+ RootTableCache.m_TableStartOffset = SrvCbvUavTblStartOffset;
+ SrvCbvUavTblStartOffset += TableSize;
+ }
+ else
+ {
+ RootTableCache.m_TableStartOffset = SamplerTblStartOffset;
+ SamplerTblStartOffset += TableSize;
+ }
+ }
+ else
+ {
+ VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheVk::InvalidDescriptorOffset);
+ }
+ }
+
+#ifdef _DEBUG
+ for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv)
+ {
+ auto &RootParam = m_RootParams.GetRootView(rv);
+ const auto& VkRootParam = static_cast<const Vk_ROOT_PARAMETER&>(RootParam);
+ auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex());
+ // Root views are not assigned valid table start offset
+ VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheVk::InvalidDescriptorOffset);
+
+ SHADER_TYPE dbgShaderType = ShaderTypeFromShaderVisibility(VkRootParam.ShaderVisibility);
+ VERIFY_EXPR(VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV);
+ RootTableCache.SetDebugAttribs( 1, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType );
+ }
+#endif
+
+ VERIFY_EXPR(SrvCbvUavTblStartOffset == TotalSrvCbvUavDescriptors);
+ VERIFY_EXPR(SamplerTblStartOffset == TotalSamplerDescriptors);
+
+ ResourceCache.SetDescriptorHeapSpace(std::move(CbcSrvUavHeapSpace), std::move(SamplerHeapSpace));
+}
+
+const Vk_RESOURCE_STATES Vk_RESOURCE_STATE_SHADER_RESOURCE = Vk_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | Vk_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+
+__forceinline
+void TransitionResource(CommandContext &Ctx,
+ ShaderResourceCacheVk::Resource &Res,
+ Vk_DESCRIPTOR_RANGE_TYPE RangeType)
+{
+ switch (Res.Type)
+ {
+ case CachedResourceType::CBV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type");
+ // Not using QueryInterface() for the sake of efficiency
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(Res.pObject.RawPtr());
+ if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) )
+ Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER );
+ }
+ break;
+
+ case CachedResourceType::BufSRV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type");
+ auto *pBuffViewVk = ValidatedCast<BufferViewVkImpl>(Res.pObject.RawPtr());
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer());
+ if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_SHADER_RESOURCE) )
+ Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_SHADER_RESOURCE );
+ }
+ break;
+
+ case CachedResourceType::BufUAV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type");
+ auto *pBuffViewVk = ValidatedCast<BufferViewVkImpl>(Res.pObject.RawPtr());
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer());
+ if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_UNORDERED_ACCESS) )
+ Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_UNORDERED_ACCESS );
+ }
+ break;
+
+ case CachedResourceType::TexSRV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type");
+ auto *pTexViewVk = ValidatedCast<TextureViewVkImpl>(Res.pObject.RawPtr());
+ auto *pTexToTransition = ValidatedCast<TextureVkImpl>(pTexViewVk->GetTexture());
+ if( !pTexToTransition->CheckAllStates(Vk_RESOURCE_STATE_SHADER_RESOURCE) )
+ Ctx.TransitionResource(pTexToTransition, Vk_RESOURCE_STATE_SHADER_RESOURCE );
+ }
+ break;
+
+ case CachedResourceType::TexUAV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type");
+ auto *pTexViewVk = ValidatedCast<TextureViewVkImpl>(Res.pObject.RawPtr());
+ auto *pTexToTransition = ValidatedCast<TextureVkImpl>(pTexViewVk->GetTexture());
+ if( !pTexToTransition->CheckAllStates(Vk_RESOURCE_STATE_UNORDERED_ACCESS) )
+ Ctx.TransitionResource(pTexToTransition, Vk_RESOURCE_STATE_UNORDERED_ACCESS );
+ }
+ break;
+
+ case CachedResourceType::Sampler:
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type");
+ break;
+
+ default:
+ // Resource not bound
+ VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type");
+ VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected");
+ }
+}
+
+
+#ifdef _DEBUG
+void DbgVerifyResourceState(ShaderResourceCacheVk::Resource &Res,
+ Vk_DESCRIPTOR_RANGE_TYPE RangeType)
+{
+ switch (Res.Type)
+ {
+ case CachedResourceType::CBV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type");
+ // Not using QueryInterface() for the sake of efficiency
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(Res.pObject.RawPtr());
+ auto State = pBuffToTransition->GetState();
+ if( (State & Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) != Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER )
+ LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" );
+ }
+ break;
+
+ case CachedResourceType::BufSRV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type");
+ auto *pBuffViewVk = ValidatedCast<BufferViewVkImpl>(Res.pObject.RawPtr());
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer());
+ auto State = pBuffToTransition->GetState();
+ if( (State & Vk_RESOURCE_STATE_SHADER_RESOURCE) != Vk_RESOURCE_STATE_SHADER_RESOURCE )
+ LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in correct state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" );
+ }
+ break;
+
+ case CachedResourceType::BufUAV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type");
+ auto *pBuffViewVk = ValidatedCast<BufferViewVkImpl>(Res.pObject.RawPtr());
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer());
+ auto State = pBuffToTransition->GetState();
+ if( (State & Vk_RESOURCE_STATE_UNORDERED_ACCESS) != Vk_RESOURCE_STATE_UNORDERED_ACCESS )
+ LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_UNORDERED_ACCESS state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" );
+ }
+ break;
+
+ case CachedResourceType::TexSRV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type");
+ auto *pTexViewVk = ValidatedCast<TextureViewVkImpl>(Res.pObject.RawPtr());
+ auto *pTexToTransition = ValidatedCast<TextureVkImpl>(pTexViewVk->GetTexture());
+ auto State = pTexToTransition->GetState();
+ if( (State & Vk_RESOURCE_STATE_SHADER_RESOURCE) != Vk_RESOURCE_STATE_SHADER_RESOURCE )
+ LOG_ERROR_MESSAGE("Resource \"", pTexToTransition->GetDesc().Name, "\" is not in correct state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" );
+ }
+ break;
+
+ case CachedResourceType::TexUAV:
+ {
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type");
+ auto *pTexViewVk = ValidatedCast<TextureViewVkImpl>(Res.pObject.RawPtr());
+ auto *pTexToTransition = ValidatedCast<TextureVkImpl>(pTexViewVk->GetTexture());
+ auto State = pTexToTransition->GetState();
+ if( (State & Vk_RESOURCE_STATE_UNORDERED_ACCESS) != Vk_RESOURCE_STATE_UNORDERED_ACCESS )
+ LOG_ERROR_MESSAGE("Resource \"", pTexToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_UNORDERED_ACCESS state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" );
+ }
+ break;
+
+ case CachedResourceType::Sampler:
+ VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type");
+ break;
+
+ default:
+ // Resource not bound
+ VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type");
+ VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected");
+ }
+}
+#endif
+
+template<class TOperation>
+__forceinline void RootSignature::RootParamsManager::ProcessRootTables(TOperation Operation)const
+{
+ for(Uint32 rt = 0; rt < m_NumRootTables; ++rt)
+ {
+ auto &RootTable = GetRootTable(rt);
+ auto RootInd = RootTable.GetRootIndex();
+ const Vk_ROOT_PARAMETER& VkParam = RootTable;
+
+ VERIFY_EXPR(VkParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE);
+
+ auto &VkTable = VkParam.DescriptorTable;
+ VERIFY(VkTable.NumDescriptorRanges > 0 && RootTable.GetDescriptorTableSize() > 0, "Unexepected empty descriptor table");
+ bool IsResourceTable = VkTable.pDescriptorRanges[0].RangeType != Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType = Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES;
+#ifdef _DEBUG
+ dbgHeapType = IsResourceTable ? Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV : Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER;
+#endif
+ Operation(RootInd, RootTable, VkParam, IsResourceTable, dbgHeapType);
+ }
+}
+
+template<class TOperation>
+__forceinline void ProcessCachedTableResources(Uint32 RootInd,
+ const Vk_ROOT_PARAMETER& VkParam,
+ ShaderResourceCacheVk& ResourceCache,
+ Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType,
+ TOperation Operation)
+{
+ for (UINT r = 0; r < VkParam.DescriptorTable.NumDescriptorRanges; ++r)
+ {
+ const auto &range = VkParam.DescriptorTable.pDescriptorRanges[r];
+ for (UINT d = 0; d < range.NumDescriptors; ++d)
+ {
+ SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN;
+#ifdef _DEBUG
+ dbgShaderType = ShaderTypeFromShaderVisibility(VkParam.ShaderVisibility);
+ VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type");
+#endif
+ auto OffsetFromTableStart = range.OffsetInDescriptorsFromTableStart + d;
+ auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(OffsetFromTableStart, dbgHeapType, dbgShaderType);
+
+ Operation(OffsetFromTableStart, range, Res);
+ }
+ }
+}
+
+
+template<bool PerformResourceTransitions>
+void RootSignature::CommitDescriptorHandlesInternal_SMD(RenderDeviceVkImpl *pRenderDeviceVk,
+ ShaderResourceCacheVk& ResourceCache,
+ CommandContext &Ctx,
+ bool IsCompute)const
+{
+ auto *pVkDevice = pRenderDeviceVk->GetVkDevice();
+
+ Uint32 NumDynamicCbvSrvUavDescriptors = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC];
+ Uint32 NumDynamicSamplerDescriptors = m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC];
+ VERIFY_EXPR(NumDynamicCbvSrvUavDescriptors > 0 || NumDynamicSamplerDescriptors > 0);
+
+ DescriptorHeapAllocation DynamicCbvSrvUavDescriptors, DynamicSamplerDescriptors;
+ if(NumDynamicCbvSrvUavDescriptors)
+ DynamicCbvSrvUavDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, NumDynamicCbvSrvUavDescriptors);
+ if(NumDynamicSamplerDescriptors)
+ DynamicSamplerDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, NumDynamicSamplerDescriptors);
+
+ CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap());
+ if(Heaps.pSamplerHeap == nullptr)
+ Heaps.pSamplerHeap = DynamicSamplerDescriptors.GetDescriptorHeap();
+
+ if(Heaps.pSrvCbvUavHeap == nullptr)
+ Heaps.pSrvCbvUavHeap = DynamicCbvSrvUavDescriptors.GetDescriptorHeap();
+
+ if(NumDynamicCbvSrvUavDescriptors)
+ VERIFY(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() == Heaps.pSrvCbvUavHeap, "Inconsistent CbvSrvUav descriptor heaps" );
+ if(NumDynamicSamplerDescriptors)
+ VERIFY(DynamicSamplerDescriptors.GetDescriptorHeap() == Heaps.pSamplerHeap, "Inconsistent Sampler descriptor heaps" );
+
+ if(Heaps)
+ Ctx.SetDescriptorHeaps(Heaps);
+
+ // Offset to the beginning of the current dynamic CBV_SRV_UAV/SAMPLER table from
+ // the start of the allocation
+ Uint32 DynamicCbvSrvUavTblOffset = 0;
+ Uint32 DynamicSamplerTblOffset = 0;
+
+ m_RootParams.ProcessRootTables(
+ [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType )
+ {
+ Vk_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle;
+ bool IsDynamicTable = RootTable.GetShaderVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC;
+ if (IsDynamicTable)
+ {
+ if( IsResourceTable )
+ RootTableGPUDescriptorHandle = DynamicCbvSrvUavDescriptors.GetGpuHandle(DynamicCbvSrvUavTblOffset);
+ else
+ RootTableGPUDescriptorHandle = DynamicSamplerDescriptors.GetGpuHandle(DynamicSamplerTblOffset);
+ }
+ else
+ {
+ RootTableGPUDescriptorHandle = IsResourceTable ?
+ ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootInd) :
+ ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootInd);
+ VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle");
+ }
+
+ if(IsCompute)
+ Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle);
+ else
+ Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle);
+
+ ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType,
+ [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res)
+ {
+ if(PerformResourceTransitions)
+ {
+ TransitionResource(Ctx, Res, range.RangeType);
+ }
+#ifdef _DEBUG
+ else
+ {
+ DbgVerifyResourceState(Res, range.RangeType);
+ }
+#endif
+
+ if(IsDynamicTable)
+ {
+ if (IsResourceTable)
+ {
+ if( Res.CPUDescriptorHandle.ptr == 0 )
+ LOG_ERROR_MESSAGE("No valid CbvSrvUav descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart);
+
+ VERIFY( DynamicCbvSrvUavTblOffset < NumDynamicCbvSrvUavDescriptors, "Not enough space in the descriptor heap allocation");
+
+ pVkDevice->CopyDescriptorsSimple(1, DynamicCbvSrvUavDescriptors.GetCpuHandle(DynamicCbvSrvUavTblOffset), Res.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ ++DynamicCbvSrvUavTblOffset;
+ }
+ else
+ {
+ if( Res.CPUDescriptorHandle.ptr == 0 )
+ LOG_ERROR_MESSAGE("No valid sampler descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart);
+
+ VERIFY( DynamicSamplerTblOffset < NumDynamicSamplerDescriptors, "Not enough space in the descriptor heap allocation");
+
+ pVkDevice->CopyDescriptorsSimple(1, DynamicSamplerDescriptors.GetCpuHandle(DynamicSamplerTblOffset), Res.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+ ++DynamicSamplerTblOffset;
+ }
+ }
+ }
+ );
+ }
+ );
+
+ VERIFY_EXPR( DynamicCbvSrvUavTblOffset == NumDynamicCbvSrvUavDescriptors );
+ VERIFY_EXPR( DynamicSamplerTblOffset == NumDynamicSamplerDescriptors );
+}
+
+template<bool PerformResourceTransitions>
+void RootSignature::CommitDescriptorHandlesInternal_SM(RenderDeviceVkImpl *pRenderDeviceVk,
+ ShaderResourceCacheVk& ResourceCache,
+ CommandContext &Ctx,
+ bool IsCompute)const
+{
+ VERIFY_EXPR(m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC] == 0 && m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC] == 0);
+
+ CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap());
+ if(Heaps)
+ Ctx.SetDescriptorHeaps(Heaps);
+
+ m_RootParams.ProcessRootTables(
+ [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType )
+ {
+ VERIFY(RootTable.GetShaderVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC, "Unexpected dynamic resource");
+
+ Vk_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle = IsResourceTable ?
+ ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootInd) :
+ ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootInd);
+ VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle");
+
+ if(IsCompute)
+ Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle);
+ else
+ Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle);
+
+ if(PerformResourceTransitions)
+ {
+ ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType,
+ [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res)
+ {
+ TransitionResource(Ctx, Res, range.RangeType);
+ }
+ );
+ }
+#ifdef _DEBUG
+ else
+ {
+ ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType,
+ [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res)
+ {
+ DbgVerifyResourceState(Res, range.RangeType);
+ }
+ );
+ }
+#endif
+ }
+ );
+}
+
+
+void RootSignature::TransitionResources(ShaderResourceCacheVk& ResourceCache,
+ class CommandContext &Ctx)const
+{
+ m_RootParams.ProcessRootTables(
+ [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType )
+ {
+ ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType,
+ [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res)
+ {
+ TransitionResource(Ctx, Res, range.RangeType);
+ }
+ );
+ }
+ );
+}
+
+
+void RootSignature::CommitRootViews(ShaderResourceCacheVk& ResourceCache,
+ CommandContext &Ctx,
+ bool IsCompute,
+ Uint32 ContextId)const
+{
+ for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv)
+ {
+ auto &RootView = m_RootParams.GetRootView(rv);
+ auto RootInd = RootView.GetRootIndex();
+
+ SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN;
+#ifdef _DEBUG
+ auto &Param = static_cast<const Vk_ROOT_PARAMETER&>( RootView );
+ VERIFY_EXPR(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV);
+ dbgShaderType = ShaderTypeFromShaderVisibility(Param.ShaderVisibility);
+#endif
+
+ auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType);
+ auto *pBuffToTransition = ValidatedCast<BufferVkImpl>(Res.pObject.RawPtr());
+ if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) )
+ Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
+
+ Vk_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(ContextId);
+ if(IsCompute)
+ Ctx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress);
+ else
+ Ctx.GetCommandList()->SetGraphicsRootConstantBufferView(RootInd, CBVAddress);
+ }
+}
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp
new file mode 100644
index 00000000..4d84dfa3
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp
@@ -0,0 +1,64 @@
+/* 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 "SamplerVkImpl.h"
+#include "RenderDeviceVkImpl.h"
+#include "VulkanTypeConversions.h"
+
+namespace Diligent
+{
+
+SamplerVkImpl::SamplerVkImpl(IReferenceCounters *pRefCounters, class RenderDeviceVkImpl *pRenderDeviceVk, const SamplerDesc& SamplerDesc) :
+ TSamplerBase(pRefCounters, pRenderDeviceVk, SamplerDesc)
+{
+#if 0
+ auto *pVkDevice = pRenderDeviceVk->GetVkDevice();
+ Vk_SAMPLER_DESC VkSamplerDesc =
+ {
+ FilterTypeToVkFilter(SamplerDesc.MinFilter, SamplerDesc.MagFilter, SamplerDesc.MipFilter),
+ TexAddressModeToVkAddressMode(SamplerDesc.AddressU),
+ TexAddressModeToVkAddressMode(SamplerDesc.AddressV),
+ TexAddressModeToVkAddressMode(SamplerDesc.AddressW),
+ SamplerDesc.MipLODBias,
+ SamplerDesc.MaxAnisotropy,
+ ComparisonFuncToVkComparisonFunc(SamplerDesc.ComparisonFunc),
+ {SamplerDesc.BorderColor[0], SamplerDesc.BorderColor[1], SamplerDesc.BorderColor[2], SamplerDesc.BorderColor[3]},
+ SamplerDesc.MinLOD,
+ SamplerDesc.MaxLOD
+ };
+
+ auto CPUDescriptorAlloc = pRenderDeviceVk->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+ m_Descriptor = std::move(CPUDescriptorAlloc);
+ pVkDevice->CreateSampler(&VkSamplerDesc, m_Descriptor.GetCpuHandle());
+#endif
+}
+
+SamplerVkImpl::~SamplerVkImpl()
+{
+
+}
+
+IMPLEMENT_QUERY_INTERFACE( SamplerVkImpl, IID_SamplerVk, TSamplerBase )
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
new file mode 100644
index 00000000..54098c16
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
@@ -0,0 +1,152 @@
+/* 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 "ShaderResourceBindingVkImpl.h"
+#include "PipelineStateVkImpl.h"
+#include "ShaderVkImpl.h"
+#include "RenderDeviceVkImpl.h"
+
+namespace Diligent
+{
+
+ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl( IReferenceCounters *pRefCounters, PipelineStateVkImpl *pPSO, bool IsPSOInternal) :
+ TBase( pRefCounters, pPSO, IsPSOInternal )/*,
+ m_ShaderResourceCache(ShaderResourceCacheVk::DbgCacheContentType::SRBResources)*/
+{
+#if 0
+ auto *ppShaders = pPSO->GetShaders();
+ m_NumShaders = pPSO->GetNumShaders();
+
+ auto *pRenderDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(pPSO->GetDevice());
+ pPSO->GetRootSignature().InitResourceCache(pRenderDeviceVkImpl, m_ShaderResourceCache, pPSO->GetResourceCacheDataAllocator());
+
+ auto *pResLayoutRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceLayoutVk", m_NumShaders * sizeof(ShaderResourceLayoutVk));
+ m_pResourceLayouts = reinterpret_cast<ShaderResourceLayoutVk*>(pResLayoutRawMem);
+
+ for (Uint32 s = 0; s < m_NumShaders; ++s)
+ {
+ auto *pShader = ppShaders[s];
+ auto ShaderType = pShader->GetDesc().ShaderType;
+ auto ShaderInd = GetShaderTypeIndex(ShaderType);
+
+ auto &ShaderResLayoutDataAllocator = pPSO->GetShaderResourceLayoutDataAllocator(s);
+
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object
+ SHADER_VARIABLE_TYPE Types[] = {SHADER_VARIABLE_TYPE_STATIC, SHADER_VARIABLE_TYPE_MUTABLE, SHADER_VARIABLE_TYPE_DYNAMIC};
+ const auto &SrcLayout = pPSO->GetShaderResLayout(ShaderType);
+ new (m_pResourceLayouts + s) ShaderResourceLayoutVk(*this, SrcLayout, ShaderResLayoutDataAllocator, Types, _countof(Types), m_ShaderResourceCache);
+
+ m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s);
+ }
+#endif
+}
+
+ShaderResourceBindingVkImpl::~ShaderResourceBindingVkImpl()
+{
+#if 0
+ for(Uint32 l = 0; l < m_NumShaders; ++l)
+ m_pResourceLayouts[l].~ShaderResourceLayoutVk();
+
+ GetRawAllocator().Free(m_pResourceLayouts);
+#endif
+}
+
+IMPLEMENT_QUERY_INTERFACE( ShaderResourceBindingVkImpl, IID_ShaderResourceBindingVk, TBase )
+
+void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMapping *pResMapping, Uint32 Flags)
+{
+#if 0
+ for (auto ShaderInd = 0; ShaderInd <= CSInd; ++ShaderInd )
+ {
+ if (ShaderFlags & GetShaderTypeFromIndex(ShaderInd))
+ {
+ auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
+ if(ResLayoutInd >= 0)
+ {
+ m_pResourceLayouts[ResLayoutInd].BindResources(pResMapping, Flags, &m_ShaderResourceCache);
+ }
+ }
+ }
+#endif
+}
+
+IShaderVariable *ShaderResourceBindingVkImpl::GetVariable(SHADER_TYPE ShaderType, const char *Name)
+{
+#if 0
+ auto ShaderInd = GetShaderTypeIndex(ShaderType);
+ auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
+ if (ResLayoutInd < 0)
+ {
+ LOG_ERROR_MESSAGE("Failed to find shader variable \"", Name,"\" in shader resource binding: shader type ", GetShaderTypeLiteralName(ShaderType), " is not initialized");
+ return ValidatedCast<PipelineStateVkImpl>(GetPipelineState())->GetDummyShaderVar();
+ }
+ auto *pVar = m_pResourceLayouts[ResLayoutInd].GetShaderVariable(Name);
+ if(pVar == nullptr)
+ pVar = ValidatedCast<PipelineStateVkImpl>(GetPipelineState())->GetDummyShaderVar();
+
+ return pVar;
+#endif
+ return nullptr;
+}
+
+#if 0
+#ifdef VERIFY_SHADER_BINDINGS
+void ShaderResourceBindingVkImpl::dbgVerifyResourceBindings(const PipelineStateVkImpl *pPSO)
+{
+ auto *pRefPSO = GetPipelineState();
+ if (pPSO->IsIncompatibleWith(pRefPSO))
+ {
+ LOG_ERROR("Shader resource binding is incompatible with the pipeline state \"", pPSO->GetDesc().Name, '\"');
+ return;
+ }
+ for(Uint32 l = 0; l < m_NumShaders; ++l)
+ m_pResourceLayouts[l].dbgVerifyBindings();
+}
+#endif
+#endif
+
+#if 0
+void ShaderResourceBindingVkImpl::InitializeStaticResources(const PipelineStateVkImpl *pPSO)
+{
+ VERIFY(!StaticResourcesInitialized(), "Static resources have already been initialized");
+ VERIFY(pPSO == GetPipelineState(), "Invalid pipeline state provided");
+
+ auto NumShaders = pPSO->GetNumShaders();
+ auto ppShaders = pPSO->GetShaders();
+ // Copy static resources
+ for (Uint32 s = 0; s < NumShaders; ++s)
+ {
+ auto *pShader = ValidatedCast<ShaderVkImpl>( ppShaders[s] );
+#ifdef VERIFY_SHADER_BINDINGS
+ pShader->DbgVerifyStaticResourceBindings();
+#endif
+ auto &ConstResLayout = pShader->GetConstResLayout();
+ GetResourceLayout(pShader->GetDesc().ShaderType).CopyStaticResourceDesriptorHandles(ConstResLayout);
+ }
+
+ m_bStaticResourcesInitialized = true;
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
new file mode 100644
index 00000000..2c779141
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
@@ -0,0 +1,87 @@
+/* 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 "ShaderResourceCacheVk.h"
+
+namespace Diligent
+{
+#if 0
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Cache-Structure
+ void ShaderResourceCacheVk::Initialize(IMemoryAllocator &MemAllocator, Uint32 NumTables, Uint32 TableSizes[])
+ {
+ // Memory layout:
+ // __________________________________________________________
+ // m_pMemory | m_pResources, m_NumResources |
+ // | | |
+ // V | V
+ // | RootTable[0] | .... | RootTable[Nrt-1] | Res[0] | ... | Res[n-1] | .... | Res[0] | ... | Res[m-1] |
+ // | A
+ // | |
+ // |________________________________________________|
+ // m_pResources, m_NumResources
+ //
+
+ VERIFY(m_pAllocator == nullptr && m_pMemory == nullptr, "Cache already initialized");
+ m_pAllocator = &MemAllocator;
+ m_NumTables = NumTables;
+ Uint32 TotalResources = 0;
+ for(Uint32 t=0; t < NumTables; ++t)
+ TotalResources += TableSizes[t];
+ auto MemorySize = NumTables * sizeof(RootTable) + TotalResources * sizeof(Resource);
+ if(MemorySize > 0)
+ {
+ m_pMemory = ALLOCATE( *m_pAllocator, "Memory for shader resource cache data", MemorySize);
+ auto *pTables = reinterpret_cast<RootTable*>(m_pMemory);
+ auto *pCurrResPtr = reinterpret_cast<Resource*>(pTables + m_NumTables);
+ for(Uint32 res=0; res < TotalResources; ++res)
+ new(pCurrResPtr + res) Resource();
+
+ for (Uint32 t = 0; t < NumTables; ++t)
+ {
+ new(&GetRootTable(t)) RootTable(TableSizes[t], TableSizes[t] > 0 ? pCurrResPtr : nullptr);
+ pCurrResPtr += TableSizes[t];
+ }
+ VERIFY_EXPR((char*)pCurrResPtr == (char*)m_pMemory + MemorySize);
+ }
+ }
+
+ ShaderResourceCacheVk::~ShaderResourceCacheVk()
+ {
+ if (m_pMemory)
+ {
+ Uint32 TotalResources = 0;
+ for (Uint32 t = 0; t < m_NumTables; ++t)
+ TotalResources += GetRootTable(t).GetSize();
+ auto *pResources = reinterpret_cast<Resource*>( reinterpret_cast<RootTable*>(m_pMemory) + m_NumTables);
+ for(Uint32 res=0; res < TotalResources; ++res)
+ pResources[res].~Resource();
+ for (Uint32 t = 0; t < m_NumTables; ++t)
+ GetRootTable(t).~RootTable();
+
+ m_pAllocator->Free(m_pMemory);
+ }
+ }
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
new file mode 100644
index 00000000..f0cb17e2
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
@@ -0,0 +1,1093 @@
+/* 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 "ShaderResourceLayoutVk.h"
+#include "ShaderResourceCacheVk.h"
+#include "BufferVkImpl.h"
+#include "BufferViewVk.h"
+#include "TextureVkImpl.h"
+#include "TextureViewVkImpl.h"
+#include "SamplerVkImpl.h"
+#include "ShaderVkImpl.h"
+#include "RootSignature.h"
+#include "PipelineStateVkImpl.h"
+
+namespace Diligent
+{
+
+#if 0
+ShaderResourceLayoutVk::ShaderResourceLayoutVk(IObject &Owner,
+ IMemoryAllocator &ResourceLayoutDataAllocator) :
+ m_Owner(Owner),
+#if USE_VARIABLE_HASH_MAP
+ m_VariableHash(STD_ALLOCATOR_RAW_MEM(VariableHashElemType, GetRawAllocator(), "Allocator for unordered_map<HashMapStringKey, IShaderVariable*>")),
+#endif
+ m_ResourceBuffer(nullptr, STDDeleterRawMem<void>(ResourceLayoutDataAllocator))
+{
+}
+
+ShaderResourceLayoutVk::~ShaderResourceLayoutVk()
+{
+ // For some reason MS compiler generates this false warning:
+ // warning C4189: 'CbvSrvUav': local variable is initialized but not referenced
+#pragma warning(push)
+#pragma warning(disable : 4189)
+ auto* CbvSrvUav = reinterpret_cast<SRV_CBV_UAV*>(m_ResourceBuffer.get());
+#pragma warning(pop)
+ for(Uint32 r=0; r < GetTotalSrvCbvUavCount(); ++r)
+ CbvSrvUav[r].~SRV_CBV_UAV();
+
+ for(Uint32 s=0; s < GetTotalSamplerCount(); ++s)
+ m_Samplers[s].~Sampler();
+}
+
+Vk_DESCRIPTOR_RANGE_TYPE GetDescriptorRangeType(CachedResourceType ResType)
+{
+ static Vk_DESCRIPTOR_RANGE_TYPE RangeTypes[(size_t)CachedResourceType::NumTypes] = {};
+ static bool Initialized = false;
+ if (!Initialized)
+ {
+ RangeTypes[(size_t)CachedResourceType::CBV] = Vk_DESCRIPTOR_RANGE_TYPE_CBV;
+ RangeTypes[(size_t)CachedResourceType::TexSRV] = Vk_DESCRIPTOR_RANGE_TYPE_SRV;
+ RangeTypes[(size_t)CachedResourceType::BufSRV] = Vk_DESCRIPTOR_RANGE_TYPE_SRV;
+ RangeTypes[(size_t)CachedResourceType::TexUAV] = Vk_DESCRIPTOR_RANGE_TYPE_UAV;
+ RangeTypes[(size_t)CachedResourceType::BufUAV] = Vk_DESCRIPTOR_RANGE_TYPE_UAV;
+ RangeTypes[(size_t)CachedResourceType::Sampler] = Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ Initialized = true;
+ }
+ auto Ind = static_cast<size_t>(ResType);
+ VERIFY(Ind >= 0 && Ind < (size_t)CachedResourceType::NumTypes, "Unexpected resource type");
+ return RangeTypes[Ind];
+}
+
+void ShaderResourceLayoutVk::AllocateMemory(IMemoryAllocator &Allocator)
+{
+ VERIFY( &m_ResourceBuffer.get_deleter().m_Allocator == &Allocator, "Inconsistent memory allocators" );
+ Uint32 TotalSrvCbvUav = GetTotalSrvCbvUavCount();
+ Uint32 TotalSamplers = GetTotalSamplerCount();
+ size_t MemSize = TotalSrvCbvUav * sizeof(SRV_CBV_UAV) + TotalSamplers * sizeof(Sampler);
+ if(MemSize == 0)
+ return;
+
+ auto *pRawMem = ALLOCATE(Allocator, "Raw memory buffer for shader resource layout resources", MemSize);
+ m_ResourceBuffer.reset(pRawMem);
+ if(TotalSamplers)
+ m_Samplers = reinterpret_cast<Sampler*>(reinterpret_cast<SRV_CBV_UAV*>(pRawMem) + TotalSrvCbvUav);
+}
+
+// Clones layout from the reference layout maintained by the pipeline state
+// Root indices and descriptor table offsets must be correct
+// Resource cache is not initialized.
+// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object
+ShaderResourceLayoutVk::ShaderResourceLayoutVk(IObject &Owner,
+ const ShaderResourceLayoutVk& SrcLayout,
+ IMemoryAllocator &ResourceLayoutDataAllocator,
+ const SHADER_VARIABLE_TYPE *AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ ShaderResourceCacheVk &ResourceCache) :
+ ShaderResourceLayoutVk(Owner, ResourceLayoutDataAllocator)
+{
+ m_pVkDevice = SrcLayout.m_pVkDevice;
+ m_pResources = SrcLayout.m_pResources;
+ m_pResourceCache = &ResourceCache;
+
+ Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
+
+ for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_VARIABLE_TYPE>(VarType+1))
+ {
+ if( !IsAllowedType(VarType, AllowedTypeBits))
+ continue;
+
+ m_NumCbvSrvUav[VarType] = SrcLayout.m_NumCbvSrvUav[VarType];
+ m_NumSamplers[VarType] = SrcLayout.m_NumSamplers[VarType];
+ }
+
+ AllocateMemory(ResourceLayoutDataAllocator);
+
+ Uint32 CurrCbvSrvUav[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0};
+ Uint32 CurrSampler[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0};
+
+ for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_VARIABLE_TYPE>(VarType+1))
+ {
+ if( !IsAllowedType(VarType, AllowedTypeBits))
+ continue;
+
+ Uint32 NumSrcCbvSrvUav = SrcLayout.m_NumCbvSrvUav[VarType];
+ VERIFY_EXPR(NumSrcCbvSrvUav == m_NumCbvSrvUav[VarType]);
+ for( Uint32 r=0; r < NumSrcCbvSrvUav; ++r )
+ {
+ const auto &SrcRes = SrcLayout.GetSrvCbvUav(VarType, r);
+ Uint32 SamplerId = SRV_CBV_UAV::InvalidSamplerId;
+ if (SrcRes.IsValidSampler())
+ {
+ const auto &SrcSamplerAttribs = SrcLayout.GetSampler(VarType, SrcRes.GetSamplerId());
+ VERIFY(!SrcSamplerAttribs.Attribs.IsStaticSampler(), "Only non-static samplers can be assigned space in shader cache");
+ VERIFY(SrcSamplerAttribs.Attribs.GetVariableType() == SrcRes.Attribs.GetVariableType(), "Inconsistent texture and sampler variable types" );
+ VERIFY(SrcSamplerAttribs.IsValidRootIndex(), "Root index must be valid");
+ VERIFY(SrcSamplerAttribs.IsValidOffset(), "Offset must be valid");
+ VERIFY_EXPR(SrcSamplerAttribs.Attribs.BindCount == SrcRes.Attribs.BindCount || SrcSamplerAttribs.Attribs.BindCount == 1);
+
+ SamplerId = CurrSampler[VarType];
+ VERIFY(SamplerId <= SRV_CBV_UAV::MaxSamplerId, "SamplerId exceeds maximum allowed value (", SRV_CBV_UAV::MaxSamplerId, ")");
+ VERIFY_EXPR(SamplerId == SrcRes.GetSamplerId());
+ ::new (&GetSampler(VarType, CurrSampler[VarType]++)) Sampler( *this, SrcSamplerAttribs );
+ }
+
+ VERIFY(SrcRes.IsValidRootIndex(), "Root index must be valid");
+ VERIFY(SrcRes.IsValidOffset(), "Offset must be valid");
+ ::new (&GetSrvCbvUav(VarType, CurrCbvSrvUav[VarType]++)) SRV_CBV_UAV( *this, SrcRes, SamplerId );
+ }
+ }
+
+#ifdef _DEBUG
+ for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_VARIABLE_TYPE>(VarType+1))
+ {
+ VERIFY_EXPR( CurrCbvSrvUav[VarType] == m_NumCbvSrvUav[VarType] );
+ VERIFY_EXPR( CurrSampler[VarType] == m_NumSamplers[VarType] );
+ }
+#endif
+}
+
+// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object
+// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Initializing-Shader-Resource-Layouts-in-a-Pipeline-State
+void ShaderResourceLayoutVk::Initialize(IVkDevice *pVkDevice,
+ const std::shared_ptr<const ShaderResourcesVk>& pSrcResources,
+ IMemoryAllocator &LayoutDataAllocator,
+ const SHADER_VARIABLE_TYPE *AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ ShaderResourceCacheVk* pResourceCache,
+ RootSignature *pRootSig)
+{
+ m_pResources = pSrcResources;
+ m_pResourceCache = pResourceCache;
+ m_pVkDevice = pVkDevice;
+
+ VERIFY_EXPR( (pResourceCache != nullptr) ^ (pRootSig != nullptr) );
+
+ Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
+
+ // Count number of resources to allocate all needed memory
+ m_pResources->ProcessResources(
+ AllowedVarTypes, NumAllowedTypes,
+
+ [&](const D3DShaderResourceAttribs &CB, Uint32)
+ {
+ VERIFY_EXPR(IsAllowedType(CB.GetVariableType(), AllowedTypeBits));
+ ++m_NumCbvSrvUav[CB.GetVariableType()];
+ },
+ [&](const D3DShaderResourceAttribs& TexSRV, Uint32)
+ {
+ auto VarType = TexSRV.GetVariableType();
+ VERIFY_EXPR(IsAllowedType(VarType, AllowedTypeBits));
+ ++m_NumCbvSrvUav[VarType];
+ if(TexSRV.IsValidSampler())
+ {
+ auto SamplerId = TexSRV.GetSamplerId();
+ const auto &SamplerAttribs = m_pResources->GetSampler(SamplerId);
+ VERIFY(SamplerAttribs.GetVariableType() == VarType, "Texture and sampler variable types are not conistent");
+ if(!SamplerAttribs.IsStaticSampler())
+ {
+ ++m_NumSamplers[VarType];
+ }
+ }
+ },
+ [&](const D3DShaderResourceAttribs &TexUAV, Uint32)
+ {
+ VERIFY_EXPR(IsAllowedType(TexUAV.GetVariableType(), AllowedTypeBits));
+ ++m_NumCbvSrvUav[TexUAV.GetVariableType()];
+ },
+ [&](const D3DShaderResourceAttribs &BufSRV, Uint32)
+ {
+ VERIFY_EXPR(IsAllowedType(BufSRV.GetVariableType(), AllowedTypeBits));
+ ++m_NumCbvSrvUav[BufSRV.GetVariableType()];
+ },
+ [&](const D3DShaderResourceAttribs &BufUAV, Uint32)
+ {
+ VERIFY_EXPR(IsAllowedType(BufUAV.GetVariableType(), AllowedTypeBits));
+ ++m_NumCbvSrvUav[BufUAV.GetVariableType()];
+ }
+ );
+
+
+ AllocateMemory(LayoutDataAllocator);
+
+ Uint32 CurrCbvSrvUav[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0};
+ Uint32 CurrSampler[SHADER_VARIABLE_TYPE_NUM_TYPES] = {0,0,0};
+ Uint32 StaticResCacheTblSizes[4] = {0, 0, 0, 0};
+
+ auto AddResource = [&](const D3DShaderResourceAttribs &Attribs, CachedResourceType ResType, Uint32 SamplerId = SRV_CBV_UAV::InvalidSamplerId)
+ {
+ Uint32 RootIndex = SRV_CBV_UAV::InvalidRootIndex;
+ Uint32 Offset = SRV_CBV_UAV::InvalidOffset;
+ Vk_DESCRIPTOR_RANGE_TYPE DescriptorRangeType = GetDescriptorRangeType(ResType);
+ if (pRootSig)
+ {
+ pRootSig->AllocateResourceSlot(m_pResources->GetShaderType(), Attribs, DescriptorRangeType, RootIndex, Offset );
+ VERIFY(RootIndex <= SRV_CBV_UAV::MaxRootIndex, "Root index excceeds allowed limit");
+ }
+ else
+ {
+ // If root signature is not provided - use artifial root signature to store
+ // static shader resources:
+ // SRVs at root index Vk_DESCRIPTOR_RANGE_TYPE_SRV (0)
+ // UAVs at root index Vk_DESCRIPTOR_RANGE_TYPE_UAV (1)
+ // CBVs at root index Vk_DESCRIPTOR_RANGE_TYPE_CBV (2)
+ // Samplers at root index Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER (3)
+
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources
+
+ VERIFY_EXPR(m_pResourceCache != nullptr);
+
+ RootIndex = DescriptorRangeType;
+ Offset = Attribs.BindPoint;
+ // Resources in the static resource cache are indexed by the bind point
+ StaticResCacheTblSizes[RootIndex] = std::max(StaticResCacheTblSizes[RootIndex], Offset + Attribs.BindCount);
+ }
+ VERIFY(RootIndex != SRV_CBV_UAV::InvalidRootIndex, "Root index must be valid");
+ VERIFY(Offset != SRV_CBV_UAV::InvalidOffset, "Offset must be valid");
+
+ // Static samplers are never copied, and SamplerId == InvalidSamplerId
+ ::new (&GetSrvCbvUav(Attribs.GetVariableType(), CurrCbvSrvUav[Attribs.GetVariableType()]++)) SRV_CBV_UAV( *this, Attribs, ResType, RootIndex, Offset, SamplerId);
+ };
+
+
+
+ m_pResources->ProcessResources(
+ AllowedVarTypes, NumAllowedTypes,
+
+ [&](const D3DShaderResourceAttribs &CB, Uint32)
+ {
+ VERIFY_EXPR( IsAllowedType(CB.GetVariableType(), AllowedTypeBits) );
+ AddResource(CB, CachedResourceType::CBV);
+ },
+ [&](const D3DShaderResourceAttribs& TexSRV, Uint32)
+ {
+ auto VarType = TexSRV.GetVariableType();
+ VERIFY_EXPR(IsAllowedType(VarType, AllowedTypeBits) );
+
+ Uint32 SamplerId = SRV_CBV_UAV::InvalidSamplerId;
+ if(TexSRV.IsValidSampler())
+ {
+ const auto &SrcSamplerAttribs = m_pResources->GetSampler(TexSRV.GetSamplerId());
+ VERIFY(SrcSamplerAttribs.GetVariableType() == VarType, "Inconsistent texture and sampler variable types" );
+
+ if (SrcSamplerAttribs.IsStaticSampler())
+ {
+ if(pRootSig != nullptr)
+ pRootSig->InitStaticSampler(m_pResources->GetShaderType(), TexSRV.Name, SrcSamplerAttribs);
+
+ // Static samplers are never copied, and SamplerId == InvalidSamplerId
+ }
+ else
+ {
+ Uint32 SamplerRootIndex = Sampler::InvalidRootIndex;
+ Uint32 SamplerOffset = Sampler::InvalidOffset;
+ if (pRootSig)
+ {
+ pRootSig->AllocateResourceSlot(m_pResources->GetShaderType(), SrcSamplerAttribs, Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, SamplerRootIndex, SamplerOffset );
+ }
+ else
+ {
+ // If root signature is not provided, we are initializing resource cache to store
+ // static shader resources.
+ VERIFY_EXPR(m_pResourceCache != nullptr);
+
+ // We use the following artifial root signature:
+ // SRVs at root index Vk_DESCRIPTOR_RANGE_TYPE_SRV (0)
+ // UAVs at root index Vk_DESCRIPTOR_RANGE_TYPE_UAV (1)
+ // CBVs at root index Vk_DESCRIPTOR_RANGE_TYPE_CBV (2)
+ // Samplers at root index Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER (3)
+ // Every resource is stored at offset that equals its bind point
+ SamplerRootIndex = Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ SamplerOffset = SrcSamplerAttribs.BindPoint;
+ // Resources in the static resource cache are indexed by the bind point
+ StaticResCacheTblSizes[SamplerRootIndex] = std::max(StaticResCacheTblSizes[SamplerRootIndex], SamplerOffset + SrcSamplerAttribs.BindCount);
+ }
+ VERIFY(SamplerRootIndex != Sampler::InvalidRootIndex, "Sampler root index must be valid");
+ VERIFY(SamplerOffset != Sampler::InvalidOffset, "Sampler offset must be valid");
+
+ SamplerId = CurrSampler[VarType];
+ VERIFY(SamplerId <= SRV_CBV_UAV::MaxSamplerId, "Sampler index excceeds allowed limit");
+ ::new (&GetSampler(VarType, CurrSampler[VarType]++)) Sampler( *this, SrcSamplerAttribs, SamplerRootIndex, SamplerOffset );
+ }
+ }
+ AddResource(TexSRV, CachedResourceType::TexSRV, SamplerId);
+ },
+ [&](const D3DShaderResourceAttribs &TexUAV, Uint32)
+ {
+ VERIFY_EXPR( IsAllowedType(TexUAV.GetVariableType(), AllowedTypeBits) );
+ AddResource(TexUAV, CachedResourceType::TexUAV);
+ },
+ [&](const D3DShaderResourceAttribs &BufSRV, Uint32)
+ {
+ VERIFY_EXPR( IsAllowedType(BufSRV.GetVariableType(), AllowedTypeBits) );
+ AddResource(BufSRV, CachedResourceType::BufSRV);
+ },
+ [&](const D3DShaderResourceAttribs &BufUAV, Uint32)
+ {
+ VERIFY_EXPR( IsAllowedType(BufUAV.GetVariableType(), AllowedTypeBits) );
+ AddResource(BufUAV, CachedResourceType::BufUAV);
+ }
+ );
+
+#ifdef _DEBUG
+ for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_VARIABLE_TYPE>(VarType+1))
+ {
+ VERIFY( CurrCbvSrvUav[VarType] == m_NumCbvSrvUav[VarType], "Not all Srv/Cbv/Uavs are initialized, which result in a crash when dtor is called" );
+ VERIFY( CurrSampler[VarType] == m_NumSamplers[VarType], "Not all Samplers are initialized, which result in a crash when dtor is called" );
+ }
+#endif
+
+ if(m_pResourceCache)
+ {
+ // Initialize resource cache to store static resources
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Initializing-the-Cache-for-Static-Shader-Resources
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Initializing-Shader-Objects
+ VERIFY_EXPR(pRootSig == nullptr);
+ m_pResourceCache->Initialize(GetRawAllocator(), _countof(StaticResCacheTblSizes), StaticResCacheTblSizes);
+#ifdef _DEBUG
+ m_pResourceCache->GetRootTable(Vk_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(StaticResCacheTblSizes[Vk_DESCRIPTOR_RANGE_TYPE_SRV], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType());
+ m_pResourceCache->GetRootTable(Vk_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(StaticResCacheTblSizes[Vk_DESCRIPTOR_RANGE_TYPE_UAV], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType());
+ m_pResourceCache->GetRootTable(Vk_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(StaticResCacheTblSizes[Vk_DESCRIPTOR_RANGE_TYPE_CBV], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType());
+ m_pResourceCache->GetRootTable(Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(StaticResCacheTblSizes[Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER], Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType());
+#endif
+ }
+
+ InitVariablesHashMap();
+}
+
+
+void ShaderResourceLayoutVk::InitVariablesHashMap()
+{
+#if USE_VARIABLE_HASH_MAP
+ Uint32 TotalResources = GetTotalSrvCbvUavCount();
+ for(Uint32 r=0; r < TotalResources; ++r)
+ {
+ auto &Res = GetSrvCbvUav(r);
+ /* HashMapStringKey will make a copy of the string*/
+ m_VariableHash.insert( std::make_pair( Diligent::HashMapStringKey(Res.Name), &Res ) );
+ }
+#endif
+}
+
+
+#define LOG_RESOURCE_BINDING_ERROR(ResType, pResource, VarName, ShaderName, ...)\
+{ \
+ const auto &ResName = pResource->GetDesc().Name; \
+ LOG_ERROR_MESSAGE( "Failed to bind ", ResType, " \"", ResName, "\" to variable \"", VarName, \
+ "\" in shader \"", ShaderName, "\". ", __VA_ARGS__ ); \
+}
+
+
+
+void ShaderResourceLayoutVk::SRV_CBV_UAV::CacheCB(IDeviceObject *pBuffer, ShaderResourceCacheVk::Resource& DstRes, Uint32 ArrayInd, Vk_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle)
+{
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Binding-Objects-to-Shader-Variables
+
+ // We cannot use ValidatedCast<> here as the resource retrieved from the
+ // resource mapping can be of wrong type
+ RefCntAutoPtr<BufferVkImpl> pBuffVk(pBuffer, IID_BufferVk);
+ if( pBuffVk )
+ {
+ if( pBuffVk->GetDesc().BindFlags & BIND_UNIFORM_BUFFER )
+ {
+ if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr )
+ {
+ if(DstRes.pObject != pBuffVk)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType());
+ LOG_ERROR_MESSAGE( "Non-null constant buffer is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayInd), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempring to bind another constant buffer is an error and will be ignored. Use another shader resource binding instance or mark shader variable as dynamic." );
+ }
+
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ DstRes.Type = GetResType();
+ DstRes.CPUDescriptorHandle = pBuffVk->GetCBVHandle();
+ VERIFY(DstRes.CPUDescriptorHandle.ptr != 0 || pBuffVk->GetDesc().Usage == USAGE_DYNAMIC, "No relevant CBV CPU descriptor handle");
+
+ if(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 )
+ {
+ // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and
+ // the descriptor is copied by the RootSignature when resources are committed
+ VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once");
+
+ IVkDevice *pVkDevice = m_ParentResLayout.m_pVkDevice;
+ pVkDevice->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ }
+
+ DstRes.pObject = pBuffVk;
+ }
+ else
+ {
+ LOG_RESOURCE_BINDING_ERROR("buffer", pBuffer, Attribs.GetPrintName(ArrayInd), m_ParentResLayout.GetShaderName(), "Buffer was not created with BIND_UNIFORM_BUFFER flag.")
+ }
+ }
+ else
+ {
+ LOG_RESOURCE_BINDING_ERROR("buffer", pBuffer, Attribs.GetPrintName(ArrayInd), m_ParentResLayout.GetShaderName(), "Incorrect resource type: buffer is expected.")
+ }
+}
+
+
+template<typename TResourceViewType>
+struct ResourceViewTraits{};
+
+template<>
+struct ResourceViewTraits<ITextureViewVk>
+{
+ static const Char *Name;
+ static const INTERFACE_ID &IID;
+};
+const Char *ResourceViewTraits<ITextureViewVk>::Name = "texture view";
+const INTERFACE_ID& ResourceViewTraits<ITextureViewVk>::IID = IID_TextureViewVk;
+
+template<>
+struct ResourceViewTraits<IBufferViewVk>
+{
+ static const Char *Name;
+ static const INTERFACE_ID &IID;
+};
+const Char *ResourceViewTraits<IBufferViewVk>::Name = "buffer view";
+const INTERFACE_ID& ResourceViewTraits<IBufferViewVk>::IID = IID_BufferViewVk;
+
+template<typename TResourceViewType, ///< ResType of the view (ITextureViewVk or IBufferViewVk)
+ typename TViewTypeEnum, ///< ResType of the expected view type enum (TEXTURE_VIEW_TYPE or BUFFER_VIEW_TYPE)
+ typename TBindSamplerProcType> ///< ResType of the procedure to set sampler
+void ShaderResourceLayoutVk::SRV_CBV_UAV::CacheResourceView(IDeviceObject *pView,
+ ShaderResourceCacheVk::Resource& DstRes,
+ Uint32 ArrayIndex,
+ Vk_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle,
+ TViewTypeEnum dbgExpectedViewType,
+ TBindSamplerProcType BindSamplerProc)
+{
+ // We cannot use ValidatedCast<> here as the resource retrieved from the
+ // resource mapping can be of wrong type
+ RefCntAutoPtr<TResourceViewType> pViewVk(pView, ResourceViewTraits<TResourceViewType>::IID);
+ if( pViewVk )
+ {
+#ifdef VERIFY_SHADER_BINDINGS
+ const auto& ViewDesc = pViewVk->GetDesc();
+ auto ViewType = ViewDesc.ViewType;
+ if( ViewType != dbgExpectedViewType )
+ {
+ const auto *ExpectedViewTypeName = GetViewTypeLiteralName( dbgExpectedViewType );
+ const auto *ActualViewTypeName = GetViewTypeLiteralName( ViewType );
+ LOG_RESOURCE_BINDING_ERROR(ResourceViewTraits<TResourceViewType>::Name, pViewVk, Attribs.GetPrintName(ArrayIndex), m_ParentResLayout.GetShaderName(),
+ "Incorrect view type: ", ExpectedViewTypeName, " is expected, ", ActualViewTypeName, " provided." );
+ return;
+ }
+#endif
+ if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr )
+ {
+ if(DstRes.pObject != pViewVk)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType());
+ LOG_ERROR_MESSAGE( "Non-null resource is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayIndex), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempting to bind another resource or null is an error and will be ignored. Use another shader resource binding instance or mark shader variable as dynamic." );
+ }
+
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ DstRes.Type = GetResType();
+ DstRes.CPUDescriptorHandle = pViewVk->GetCPUDescriptorHandle();
+ VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant Vk view");
+
+ if(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0)
+ {
+ // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and
+ // the descriptor is copied by the RootSignature when resources are committed
+ VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once");
+
+ IVkDevice *pVkDevice = m_ParentResLayout.m_pVkDevice;
+ pVkDevice->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ }
+ DstRes.pObject = pViewVk;
+
+ BindSamplerProc(pViewVk);
+ }
+ else
+ {
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, Attribs.GetPrintName(ArrayIndex), m_ParentResLayout.GetShaderName(), "Incorect resource type: ", ResourceViewTraits<TResourceViewType>::Name, " is expected.")
+ }
+}
+
+void ShaderResourceLayoutVk::Sampler::CacheSampler(ITextureViewVk *pTexViewVk, Uint32 ArrayIndex, Vk_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle)
+{
+ auto *pResourceCache = m_ParentResLayout.m_pResourceCache;
+ VERIFY(pResourceCache, "Resource cache is null");
+ VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point");
+ VERIFY_EXPR(ArrayIndex < Attribs.BindCount);
+
+ auto &DstSam = pResourceCache->GetRootTable(RootIndex).GetResource(OffsetFromTableStart + ArrayIndex, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_ParentResLayout.m_pResources->GetShaderType());
+
+#ifdef _DEBUG
+ {
+ if (pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
+ {
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space");
+ }
+ else if (pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
+ {
+ if(Attribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC)
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call");
+ else
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 || pTexViewVk == nullptr, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space");
+ }
+ else
+ {
+ UNEXPECTED("Unknown content type");
+ }
+ }
+#endif
+
+ if( pTexViewVk )
+ {
+ auto pSampler = pTexViewVk->GetSampler();
+ if( pSampler )
+ {
+ if( Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC && DstSam.pObject != nullptr)
+ {
+ if(DstSam.pObject != pSampler)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(Attribs.GetVariableType());
+ LOG_ERROR_MESSAGE( "Non-null sampler is already bound to ", VarTypeStr, " shader variable \"", Attribs.GetPrintName(ArrayIndex), "\" in shader \"", m_ParentResLayout.GetShaderName(), "\". Attempting to bind another sampler is an error and will be ignored. Use another shader resource binding instance or mark shader variable as dynamic." );
+ }
+
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ DstSam.Type = CachedResourceType::Sampler;
+
+ auto *pSamplerVk = ValidatedCast<SamplerVkImpl>(pSampler);
+ DstSam.CPUDescriptorHandle = pSamplerVk->GetCPUDescriptorHandle();
+ VERIFY(DstSam.CPUDescriptorHandle.ptr != 0, "No relevant Vk sampler descriptor handle");
+
+ if(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0)
+ {
+ // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and
+ // the descriptor is copied by the RootSignature when resources are committed
+ VERIFY(DstSam.pObject == nullptr, "Static and mutable resource descriptors must be copied only once");
+
+ IVkDevice *pVkDevice = m_ParentResLayout.m_pVkDevice;
+ pVkDevice->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstSam.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+ }
+
+ DstSam.pObject = pSampler;
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE( "Failed to bind sampler to variable \"", Attribs.Name, ". Sampler is not set in the texture view \"", pTexViewVk->GetDesc().Name, "\"" );
+ }
+ }
+ else
+ {
+ DstSam = ShaderResourceCacheVk::Resource();
+ }
+}
+
+
+ShaderResourceLayoutVk::Sampler &ShaderResourceLayoutVk::GetAssignedSampler(const SRV_CBV_UAV &TexSrv)
+{
+ VERIFY(TexSrv.GetResType() == CachedResourceType::TexSRV, "Unexpected resource type: texture SRV is expected");
+ VERIFY(TexSrv.IsValidSampler(), "Texture SRV has no associated sampler");
+ auto &SamInfo = GetSampler(TexSrv.Attribs.GetVariableType(), TexSrv.GetSamplerId());
+ VERIFY(SamInfo.Attribs.GetVariableType() == TexSrv.Attribs.GetVariableType(), "Inconsistent texture and sampler variable types");
+ VERIFY(SamInfo.Attribs.Name == TexSrv.Attribs.Name + D3DSamplerSuffix, "Sampler name \"", SamInfo.Attribs.Name, "\" does not match texture name \"", TexSrv.Attribs.Name, '\"');
+ return SamInfo;
+}
+
+
+void ShaderResourceLayoutVk::SRV_CBV_UAV::BindResource(IDeviceObject *pObj, Uint32 ArrayIndex, const ShaderResourceLayoutVk *dbgResLayout)
+{
+ auto *pResourceCache = m_ParentResLayout.m_pResourceCache;
+ VERIFY(pResourceCache, "Resource cache is null");
+ VERIFY(dbgResLayout == nullptr || pResourceCache == dbgResLayout->m_pResourceCache, "Invalid resource cache");
+ VERIFY_EXPR(ArrayIndex < Attribs.BindCount);
+
+ auto &DstRes = pResourceCache->GetRootTable(GetRootIndex()).GetResource(OffsetFromTableStart + ArrayIndex, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_ParentResLayout.m_pResources->GetShaderType());
+ auto ShdrVisibleHeapCPUDescriptorHandle = pResourceCache->GetShaderVisibleTableCPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(GetRootIndex(), OffsetFromTableStart+ArrayIndex);
+
+#ifdef _DEBUG
+ {
+ if (pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
+ {
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space");
+ }
+ else if (pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
+ {
+ if (GetResType() == CachedResourceType::CBV)
+ {
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Constant buffers are bound as root views and should not be assigned shader visible descriptor space");
+ }
+ else
+ {
+ if(Attribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC)
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call");
+ else
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space");
+ }
+ }
+ else
+ {
+ UNEXPECTED("Unknown content type");
+ }
+ }
+#endif
+
+ if( pObj )
+ {
+ switch (GetResType())
+ {
+ case CachedResourceType::CBV:
+ CacheCB(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle);
+ break;
+
+ case CachedResourceType::TexSRV:
+ CacheResourceView<ITextureViewVk>(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, TEXTURE_VIEW_SHADER_RESOURCE, [&](ITextureViewVk* pTexView)
+ {
+ if(IsValidSampler())
+ {
+ auto &Sam = m_ParentResLayout.GetAssignedSampler(*this);
+ VERIFY( !Sam.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache" );
+ VERIFY_EXPR(Attribs.BindCount == Sam.Attribs.BindCount || Sam.Attribs.BindCount == 1);
+ auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0;
+ auto ShdrVisibleSamplerHeapCPUDescriptorHandle = pResourceCache->GetShaderVisibleTableCPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER>(Sam.RootIndex, Sam.OffsetFromTableStart + SamplerArrInd);
+ Sam.CacheSampler(pTexView, SamplerArrInd, ShdrVisibleSamplerHeapCPUDescriptorHandle);
+ }
+ });
+ break;
+
+ case CachedResourceType::TexUAV:
+ CacheResourceView<ITextureViewVk>(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, TEXTURE_VIEW_UNORDERED_ACCESS, [](ITextureViewVk*){});
+ break;
+
+ case CachedResourceType::BufSRV:
+ CacheResourceView<IBufferViewVk>(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, BUFFER_VIEW_SHADER_RESOURCE, [](IBufferViewVk*){});
+ break;
+
+ case CachedResourceType::BufUAV:
+ CacheResourceView<IBufferViewVk>( pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, BUFFER_VIEW_UNORDERED_ACCESS, [](IBufferViewVk*){});
+ break;
+
+ default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(GetResType()));
+ }
+ }
+ else
+ {
+ if (DstRes.pObject && Attribs.GetVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC)
+ {
+ LOG_ERROR_MESSAGE( "Shader variable \"", Attribs.Name, "\" in shader \"", m_ParentResLayout.GetShaderName(), "\" is not dynamic but being unbound. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or mark shader variable as dynamic if you need to bind another resource." );
+ }
+
+ DstRes = ShaderResourceCacheVk::Resource();
+ if(IsValidSampler())
+ {
+ auto &Sam = m_ParentResLayout.GetAssignedSampler(*this);
+ Vk_CPU_DESCRIPTOR_HANDLE NullHandle = {0};
+ auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0;
+ Sam.CacheSampler(nullptr, SamplerArrInd, NullHandle);
+ }
+ }
+}
+
+bool ShaderResourceLayoutVk::SRV_CBV_UAV::IsBound(Uint32 ArrayIndex)
+{
+ auto *pResourceCache = m_ParentResLayout.m_pResourceCache;
+ VERIFY(pResourceCache, "Resource cache is null");
+ VERIFY_EXPR(ArrayIndex < Attribs.BindCount);
+
+ auto RootIndex = GetRootIndex();
+ if( RootIndex < pResourceCache->GetNumRootTables() )
+ {
+ auto &RootTable = pResourceCache->GetRootTable(RootIndex);
+ if(OffsetFromTableStart + ArrayIndex < RootTable.GetSize())
+ {
+ auto &CachedRes = RootTable.GetResource(OffsetFromTableStart + ArrayIndex, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_ParentResLayout.m_pResources->GetShaderType());
+ if( CachedRes.pObject != nullptr )
+ {
+ VERIFY(CachedRes.CPUDescriptorHandle.ptr != 0 || ValidatedCast<BufferVkImpl>(CachedRes.pObject.RawPtr())->GetDesc().Usage == USAGE_DYNAMIC, "No relevant descriptor handle");
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
+void ShaderResourceLayoutVk::BindResources( IResourceMapping* pResourceMapping, Uint32 Flags, const ShaderResourceCacheVk *dbgResourceCache )
+{
+ VERIFY(dbgResourceCache == m_pResourceCache, "Resource cache does not match the cache provided at initialization");
+
+ if( !pResourceMapping )
+ {
+ LOG_ERROR_MESSAGE( "Failed to bind resources in shader \"", GetShaderName(), "\": resource mapping is null" );
+ return;
+ }
+
+ Uint32 TotalResources = GetTotalSrvCbvUavCount();
+ for(Uint32 r=0; r < TotalResources; ++r)
+ {
+ auto &Res = GetSrvCbvUav(r);
+ for(Uint32 ArrInd = 0; ArrInd < Res.Attribs.BindCount; ++ArrInd)
+ {
+ if( Flags & BIND_SHADER_RESOURCES_RESET_BINDINGS )
+ Res.BindResource(nullptr, ArrInd, this);
+
+ if( (Flags & BIND_SHADER_RESOURCES_UPDATE_UNRESOLVED) && Res.IsBound(ArrInd) )
+ return;
+
+ const auto& VarName = Res.Attribs.Name;
+ RefCntAutoPtr<IDeviceObject> pObj;
+ VERIFY_EXPR(pResourceMapping != nullptr);
+ pResourceMapping->GetResource( VarName.c_str(), &pObj, ArrInd );
+ if( pObj )
+ {
+ // Call non-virtual function
+ Res.BindResource(pObj, ArrInd, this);
+ }
+ else
+ {
+ if( (Flags & BIND_SHADER_RESOURCES_ALL_RESOLVED) && !Res.IsBound(ArrInd) )
+ LOG_ERROR_MESSAGE( "Cannot bind resource to shader variable \"", Res.Attribs.GetPrintName(ArrInd), "\": resource view not found in the resource mapping" );
+ }
+ }
+ }
+}
+
+
+IShaderVariable* ShaderResourceLayoutVk::GetShaderVariable(const Char* Name)
+{
+ IShaderVariable* pVar = nullptr;
+#if USE_VARIABLE_HASH_MAP
+ // Name will be implicitly converted to HashMapStringKey without making a copy
+ auto it = m_VariableHash.find( Name );
+ if( it != m_VariableHash.end() )
+ pVar = it->second;
+#else
+ Uint32 TotalResources = GetTotalSrvCbvUavCount();
+ for(Uint32 r=0; r < TotalResources; ++r)
+ {
+ auto &Res = GetSrvCbvUav(r);
+ if(Res.Attribs.Name.compare(Name) == 0)
+ {
+ pVar = &Res;
+ break;
+ }
+ }
+#endif
+
+ if(pVar == nullptr)
+ {
+ LOG_ERROR_MESSAGE( "Shader variable \"", Name, "\" is not found in shader \"", GetShaderName(), "\" (", GetShaderTypeLiteralName(m_pResources->GetShaderType()), "). Attempts to set the variable will be silently ignored." );
+ }
+ return pVar;
+}
+
+
+
+void ShaderResourceLayoutVk::CopyStaticResourceDesriptorHandles(const ShaderResourceLayoutVk &SrcLayout)
+{
+ if (!m_pResourceCache)
+ {
+ LOG_ERROR("Resource layout has no resource cache");
+ return;
+ }
+
+ if (!SrcLayout.m_pResourceCache)
+ {
+ LOG_ERROR("Dst layout has no resource cache");
+ return;
+ }
+
+ // Static shader resources are stored as follows:
+ // CBVs at root index Vk_DESCRIPTOR_RANGE_TYPE_CBV,
+ // SRVs at root index Vk_DESCRIPTOR_RANGE_TYPE_SRV,
+ // UAVs at root index Vk_DESCRIPTOR_RANGE_TYPE_UAV, and
+ // Samplers at root index Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER
+ // Every resource is stored at offset that equals resource bind point
+
+ for(Uint32 r=0; r < m_NumCbvSrvUav[SHADER_VARIABLE_TYPE_STATIC]; ++r)
+ {
+ // Get resource attributes
+ const auto &res = GetSrvCbvUav(SHADER_VARIABLE_TYPE_STATIC, r);
+ VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types");
+ auto RangeType = GetDescriptorRangeType(res.GetResType());
+ for(Uint32 ArrInd = 0; ArrInd < res.Attribs.BindCount; ++ArrInd)
+ {
+ auto BindPoint = res.Attribs.BindPoint + ArrInd;
+ // Source resource in the static resource cache is in the root table at index RangeType, at offset BindPoint
+ // Vk_DESCRIPTOR_RANGE_TYPE_SRV = 0,
+ // Vk_DESCRIPTOR_RANGE_TYPE_UAV = 1
+ // Vk_DESCRIPTOR_RANGE_TYPE_CBV = 2
+ const auto &SrcRes = SrcLayout.m_pResourceCache->GetRootTable(RangeType).GetResource(BindPoint, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, SrcLayout.m_pResources->GetShaderType());
+ if( !SrcRes.pObject )
+ LOG_ERROR_MESSAGE( "No resource assigned to static shader variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"." );
+ // Destination resource is at the root index and offset defined by the resource layout
+ auto &DstRes = m_pResourceCache->GetRootTable(res.GetRootIndex()).GetResource(res.OffsetFromTableStart + ArrInd, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType());
+
+ if(DstRes.pObject != SrcRes.pObject)
+ {
+ VERIFY(DstRes.pObject == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource");
+
+ DstRes.pObject = SrcRes.pObject;
+ DstRes.Type = SrcRes.Type;
+ DstRes.CPUDescriptorHandle = SrcRes.CPUDescriptorHandle;
+
+ auto ShdrVisibleHeapCPUDescriptorHandle = m_pResourceCache->GetShaderVisibleTableCPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(res.GetRootIndex(), res.OffsetFromTableStart + ArrInd);
+ VERIFY_EXPR(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 || DstRes.Type == CachedResourceType::CBV);
+ // Root views are not assigned space in the GPU-visible descriptor heap allocation
+ if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0)
+ {
+ m_pVkDevice->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, SrcRes.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ }
+ }
+ else
+ {
+ VERIFY_EXPR(DstRes.pObject == SrcRes.pObject);
+ VERIFY_EXPR(DstRes.Type == SrcRes.Type);
+ VERIFY_EXPR(DstRes.CPUDescriptorHandle.ptr == SrcRes.CPUDescriptorHandle.ptr);
+ }
+ }
+
+ if(res.IsValidSampler())
+ {
+ auto &SamInfo = GetAssignedSampler(res);
+
+ VERIFY(!SamInfo.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache");
+
+ VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid");
+ VERIFY_EXPR(SamInfo.Attribs.BindCount == res.Attribs.BindCount || SamInfo.Attribs.BindCount == 1);
+
+ for(Uint32 ArrInd = 0; ArrInd < SamInfo.Attribs.BindCount; ++ArrInd)
+ {
+ auto BindPoint = SamInfo.Attribs.BindPoint + ArrInd;
+ // Source sampler in the static resource cache is in the root table at index 3
+ // (Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3), at offset BindPoint
+ auto& SrcSampler = SrcLayout.m_pResourceCache->GetRootTable(Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER).GetResource(BindPoint, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, SrcLayout.m_pResources->GetShaderType());
+ if( !SrcSampler.pObject )
+ LOG_ERROR_MESSAGE( "No sampler assigned to static shader variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"." );
+ auto &DstSampler = m_pResourceCache->GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType());
+
+ if(DstSampler.pObject != SrcSampler.pObject)
+ {
+ VERIFY(DstSampler.pObject == nullptr, "Static sampler resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource");
+
+ DstSampler.pObject = SrcSampler.pObject;
+ DstSampler.Type = SrcSampler.Type;
+ DstSampler.CPUDescriptorHandle = SrcSampler.CPUDescriptorHandle;
+
+ auto ShdrVisibleSamplerHeapCPUDescriptorHandle = m_pResourceCache->GetShaderVisibleTableCPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER>(SamInfo.RootIndex, SamInfo.OffsetFromTableStart + ArrInd);
+ VERIFY_EXPR(ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0);
+ if (ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0)
+ {
+ m_pVkDevice->CopyDescriptorsSimple(1, ShdrVisibleSamplerHeapCPUDescriptorHandle, SrcSampler.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+ }
+ }
+ else
+ {
+ VERIFY_EXPR(DstSampler.pObject == SrcSampler.pObject);
+ VERIFY_EXPR(DstSampler.Type == SrcSampler.Type);
+ VERIFY_EXPR(DstSampler.CPUDescriptorHandle.ptr == SrcSampler.CPUDescriptorHandle.ptr);
+ }
+ }
+ }
+ }
+}
+
+
+#ifdef VERIFY_SHADER_BINDINGS
+void ShaderResourceLayoutVk::dbgVerifyBindings()const
+{
+ VERIFY(m_pResourceCache, "Resource cache is null");
+
+ for(SHADER_VARIABLE_TYPE VarType = SHADER_VARIABLE_TYPE_STATIC; VarType < SHADER_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_VARIABLE_TYPE>(VarType+1))
+ {
+ for(Uint32 r=0; r < m_NumCbvSrvUav[VarType]; ++r)
+ {
+ const auto &res = GetSrvCbvUav(VarType, r);
+ VERIFY(res.Attribs.GetVariableType() == VarType, "Unexpected variable type");
+
+ for(Uint32 ArrInd = 0; ArrInd < res.Attribs.BindCount; ++ArrInd)
+ {
+ const auto &CachedRes = m_pResourceCache->GetRootTable(res.GetRootIndex()).GetResource(res.OffsetFromTableStart + ArrInd, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType());
+ if(CachedRes.pObject)
+ VERIFY(CachedRes.Type == res.GetResType(), "Inconsistent cached resource types");
+ else
+ VERIFY(CachedRes.Type == CachedResourceType::Unknown, "Unexpected cached resource types");
+
+ if( !CachedRes.pObject ||
+ // Dynamic buffers do not have CPU descriptor handle as they do not keep Vk buffer, and space is allocated from the GPU ring buffer
+ CachedRes.CPUDescriptorHandle.ptr == 0 && !(CachedRes.Type==CachedResourceType::CBV && ValidatedCast<const BufferVkImpl>(CachedRes.pObject.RawPtr())->GetDesc().Usage == USAGE_DYNAMIC) )
+ LOG_ERROR_MESSAGE( "No resource is bound to ", GetShaderVariableTypeLiteralName(res.Attribs.GetVariableType()), " variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"" );
+
+ if (res.Attribs.BindCount > 1 && res.IsValidSampler())
+ {
+ // Verify that if single sampler is used for all texture array elements, all samplers set in the resource views are consistent
+ const auto &SamInfo = const_cast<ShaderResourceLayoutVk*>(this)->GetAssignedSampler(res);
+ if(SamInfo.Attribs.BindCount == 1)
+ {
+ const auto &CachedSampler = m_pResourceCache->GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType());
+ if( auto *pTexView = ValidatedCast<const ITextureView>(CachedRes.pObject.RawPtr()) )
+ {
+ auto *pSampler = const_cast<ITextureView*>(pTexView)->GetSampler();
+ if (pSampler != nullptr && CachedSampler.pObject != pSampler)
+ LOG_ERROR_MESSAGE( "All elements of texture array \"", res.Attribs.Name, "\" in shader \"", GetShaderName(), "\" share the same sampler. However, the sampler set in view for element ", ArrInd, " does not match bound sampler. This may cause incorrect behavior on GL platform." );
+ }
+ }
+ }
+
+#ifdef _DEBUG
+ {
+ auto ShdrVisibleHeapCPUDescriptorHandle = m_pResourceCache->GetShaderVisibleTableCPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(res.GetRootIndex(), res.OffsetFromTableStart + ArrInd);
+ if (m_pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
+ {
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space");
+ }
+ else if (m_pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
+ {
+ if (res.GetResType() == CachedResourceType::CBV)
+ {
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Constant buffers are bound as root views and should not be assigned shader visible descriptor space");
+ }
+ else
+ {
+ if(res.Attribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC)
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call");
+ else
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space");
+ }
+ }
+ else
+ {
+ UNEXPECTED("Unknown content type");
+ }
+ }
+#endif
+ }
+
+ if (res.IsValidSampler())
+ {
+ VERIFY(res.GetResType() == CachedResourceType::TexSRV, "Sampler can only be assigned to a texture SRV" );
+ const auto &SamInfo = const_cast<ShaderResourceLayoutVk*>(this)->GetAssignedSampler(res);
+ VERIFY( !SamInfo.Attribs.IsStaticSampler(), "Static samplers should never be assigned space in the cache" );
+ VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid");
+
+ for(Uint32 ArrInd = 0; ArrInd < SamInfo.Attribs.BindCount; ++ArrInd)
+ {
+ const auto &CachedSampler = m_pResourceCache->GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType());
+ if( CachedSampler.pObject )
+ VERIFY(CachedSampler.Type == CachedResourceType::Sampler, "Incorrect cached sampler type");
+ else
+ VERIFY(CachedSampler.Type == CachedResourceType::Unknown, "Unexpected cached sampler type");
+ if( !CachedSampler.pObject || CachedSampler.CPUDescriptorHandle.ptr == 0 )
+ LOG_ERROR_MESSAGE("No sampler is assigned to texture variable \"", res.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"");
+
+ #ifdef _DEBUG
+ {
+ auto ShdrVisibleHeapCPUDescriptorHandle = m_pResourceCache->GetShaderVisibleTableCPUDescriptorHandle<Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER>(SamInfo.RootIndex, SamInfo.OffsetFromTableStart + ArrInd);
+ if (m_pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
+ {
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space");
+ }
+ else if (m_pResourceCache->DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
+ {
+ if(SamInfo.Attribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC)
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call");
+ else
+ VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space");
+ }
+ else
+ {
+ UNEXPECTED("Unknown content type");
+ }
+ }
+ #endif
+ }
+ }
+ }
+
+ for(Uint32 s=0; s < m_NumSamplers[VarType]; ++s)
+ {
+ const auto &sam = GetSampler(VarType, s);
+ VERIFY(sam.Attribs.GetVariableType() == VarType, "Unexpected sampler variable type");
+
+ for(Uint32 ArrInd = 0; ArrInd < sam.Attribs.BindCount; ++ArrInd)
+ {
+ const auto &CachedSampler = m_pResourceCache->GetRootTable(sam.RootIndex).GetResource(sam.OffsetFromTableStart + ArrInd, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType());
+ if( CachedSampler.pObject )
+ VERIFY(CachedSampler.Type == CachedResourceType::Sampler, "Incorrect cached sampler type");
+ else
+ VERIFY(CachedSampler.Type == CachedResourceType::Unknown, "Unexpected cached sampler type");
+ if( !CachedSampler.pObject || CachedSampler.CPUDescriptorHandle.ptr == 0 )
+ LOG_ERROR_MESSAGE( "No sampler is bound to sampler variable \"", sam.Attribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"" );
+ }
+ }
+ }
+}
+#endif
+
+const Char* ShaderResourceLayoutVk::GetShaderName()const
+{
+ RefCntAutoPtr<IShader> pShader(&m_Owner, IID_Shader);
+ if (pShader)
+ {
+ return pShader->GetDesc().Name;
+ }
+ else
+ {
+ RefCntAutoPtr<IShaderResourceBinding> pSRB(&m_Owner, IID_ShaderResourceBinding);
+ if(pSRB)
+ {
+ auto *pPSO = pSRB->GetPipelineState();
+ auto *pPSOVk = ValidatedCast<PipelineStateVkImpl>(pPSO);
+ auto *ppShaders = pPSOVk->GetShaders();
+ auto NumShaders = pPSOVk->GetNumShaders();
+ for (Uint32 s = 0; s < NumShaders; ++s)
+ {
+ const auto &ShaderDesc = ppShaders[s]->GetDesc();
+ if(ShaderDesc.ShaderType == m_pResources->GetShaderType())
+ return ShaderDesc.Name;
+ }
+ UNEXPECTED("Shader not found");
+ }
+ else
+ {
+ UNEXPECTED("Owner is expected to be a shader or a shader resource binding");
+ }
+ }
+ return "";
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourcesVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourcesVk.cpp
new file mode 100644
index 00000000..82548231
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourcesVk.cpp
@@ -0,0 +1,93 @@
+/* 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 "ShaderResourcesVk.h"
+//#include "ShaderD3DBase.h"
+#include "ShaderBase.h"
+//#include "D3DShaderResourceLoader.h"
+
+
+namespace Diligent
+{
+
+#if 0
+ShaderResourcesVk::ShaderResourcesVk(ID3DBlob *pShaderBytecode, const ShaderDesc &ShdrDesc) :
+ ShaderResources(GetRawAllocator(), ShdrDesc.ShaderType)
+{
+ Uint32 CurrCB = 0, CurrTexSRV = 0, CurrTexUAV = 0, CurrBufSRV = 0, CurrBufUAV = 0, CurrSampler = 0;
+ LoadD3DShaderResources<Vk_SHADER_DESC, Vk_SHADER_INPUT_BIND_DESC, IVkShaderReflection>(
+ pShaderBytecode,
+
+ [&](Uint32 NumCBs, Uint32 NumTexSRVs, Uint32 NumTexUAVs, Uint32 NumBufSRVs, Uint32 NumBufUAVs, Uint32 NumSamplers)
+ {
+ Initialize(GetRawAllocator(), NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers);
+ },
+
+ [&](D3DShaderResourceAttribs&& CBAttribs)
+ {
+ new (&GetCB(CurrCB++)) D3DShaderResourceAttribs(std::move(CBAttribs));
+ },
+
+ [&](D3DShaderResourceAttribs &&TexUAV)
+ {
+ new (&GetTexUAV(CurrTexUAV++)) D3DShaderResourceAttribs( std::move(TexUAV) );
+ },
+
+ [&](D3DShaderResourceAttribs &&BuffUAV)
+ {
+ new (&GetBufUAV(CurrBufUAV++)) D3DShaderResourceAttribs( std::move(BuffUAV) );
+ },
+
+ [&](D3DShaderResourceAttribs &&BuffSRV)
+ {
+ new (&GetBufSRV(CurrBufSRV++)) D3DShaderResourceAttribs( std::move(BuffSRV) );
+ },
+
+ [&](D3DShaderResourceAttribs &&SamplerAttribs)
+ {
+ new (&GetSampler(CurrSampler++)) D3DShaderResourceAttribs( std::move(SamplerAttribs) );
+ },
+
+ [&](D3DShaderResourceAttribs &&TexAttribs)
+ {
+ VERIFY(CurrSampler == GetNumSamplers(), "All samplers must be initialized before texture SRVs" );
+
+ auto SamplerId = FindAssignedSamplerId(TexAttribs);
+ new (&GetTexSRV(CurrTexSRV++)) D3DShaderResourceAttribs( std::move(TexAttribs), SamplerId);
+ },
+
+ ShdrDesc,
+ D3DSamplerSuffix);
+
+ VERIFY(CurrCB == GetNumCBs(), "Not all CBs are initialized, which will result in a crash when ~D3DShaderResourceAttribs() is called");
+ VERIFY(CurrTexSRV == GetNumTexSRV(), "Not all Tex SRVs are initialized, which will result in a crash when ~D3DShaderResourceAttribs() is called" );
+ VERIFY(CurrTexUAV == GetNumTexUAV(), "Not all Tex UAVs are initialized, which will result in a crash when ~D3DShaderResourceAttribs() is called" );
+ VERIFY(CurrBufSRV == GetNumBufSRV(), "Not all Buf SRVs are initialized, which will result in a crash when ~D3DShaderResourceAttribs() is called" );
+ VERIFY(CurrBufUAV == GetNumBufUAV(), "Not all Buf UAVs are initialized, which will result in a crash when ~D3DShaderResourceAttribs() is called" );
+ VERIFY(CurrSampler == GetNumSamplers(), "Not all Samplers are initialized, which will result in a crash when ~D3DShaderResourceAttribs() is called" );
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
new file mode 100644
index 00000000..0b96448c
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
@@ -0,0 +1,89 @@
+/* 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 "ShaderVkImpl.h"
+#include "RenderDeviceVkImpl.h"
+#include "DataBlobImpl.h"
+//#include "D3DShaderResourceLoader.h"
+
+using namespace Diligent;
+
+namespace Diligent
+{
+
+
+ShaderVkImpl::ShaderVkImpl(IReferenceCounters *pRefCounters, RenderDeviceVkImpl *pRenderDeviceVk, const ShaderCreationAttribs &ShaderCreationAttribs) :
+ TShaderBase(pRefCounters, pRenderDeviceVk, ShaderCreationAttribs.Desc)/*,
+ ShaderD3DBase(ShaderCreationAttribs),
+ m_StaticResLayout(*this, GetRawAllocator()),
+ m_DummyShaderVar(*this),
+ m_ConstResCache(ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)*/
+{
+/*
+ // Load shader resources
+ auto &Allocator = GetRawAllocator();
+ auto *pRawMem = ALLOCATE(Allocator, "Allocator for ShaderResources", sizeof(ShaderResourcesVk));
+ auto *pResources = new (pRawMem) ShaderResourcesVk(m_pShaderByteCode, m_Desc);
+ m_pShaderResources.reset(pResources, STDDeleterRawMem<ShaderResourcesVk>(Allocator));
+
+ // Clone only static resources that will be set directly in the shader
+ // http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources
+ SHADER_VARIABLE_TYPE VarTypes[] = {SHADER_VARIABLE_TYPE_STATIC};
+ m_StaticResLayout.Initialize(pRenderDeviceVk->GetVkDevice(), m_pShaderResources, GetRawAllocator(), VarTypes, _countof(VarTypes), &m_ConstResCache, nullptr);
+*/
+}
+
+ShaderVkImpl::~ShaderVkImpl()
+{
+}
+
+void ShaderVkImpl::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags)
+{
+#if 0
+ m_StaticResLayout.BindResources(pResourceMapping, Flags, &m_ConstResCache);
+#endif
+}
+
+IShaderVariable* ShaderVkImpl::GetShaderVariable(const Char* Name)
+{
+#if 0
+ auto *pVar = m_StaticResLayout.GetShaderVariable(Name);
+ if(pVar == nullptr)
+ pVar = &m_DummyShaderVar;
+ return pVar;
+#endif
+ return nullptr;
+}
+
+#if 0
+#ifdef VERIFY_SHADER_BINDINGS
+void ShaderVkImpl::DbgVerifyStaticResourceBindings()
+{
+ m_StaticResLayout.dbgVerifyBindings();
+}
+#endif
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
new file mode 100644
index 00000000..c2f57992
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
@@ -0,0 +1,275 @@
+/* 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 "SwapChainVkImpl.h"
+#include "RenderDeviceVkImpl.h"
+#include "DeviceContextVkImpl.h"
+//#include "DXGITypeConversions.h"
+#include "TextureVkImpl.h"
+#include "EngineMemory.h"
+
+namespace Diligent
+{
+
+SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters *pRefCounters,
+ const SwapChainDesc& SCDesc,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ DeviceContextVkImpl* pDeviceContextVk,
+ void* pNativeWndHandle) :
+ TSwapChainBase(pRefCounters, pRenderDeviceVk, pDeviceContextVk, SCDesc)/*,
+ m_pBackBufferRTV(STD_ALLOCATOR_RAW_MEM(RefCntAutoPtr<ITextureView>, GetRawAllocator(), "Allocator for vector<RefCntAutoPtr<ITextureView>>"))*/
+{
+#if 0
+#if PLATFORM_WIN32
+ auto hWnd = reinterpret_cast<HWND>(pNativeWndHandle);
+
+ if( m_SwapChainDesc.Width == 0 || m_SwapChainDesc.Height == 0 )
+ {
+ RECT rc;
+ GetClientRect( hWnd, &rc );
+ m_SwapChainDesc.Width = rc.right - rc.left;
+ m_SwapChainDesc.Height = rc.bottom - rc.top;
+ }
+#endif
+
+ auto DXGIColorBuffFmt = TexFormatToDXGI_Format(m_SwapChainDesc.ColorBufferFormat);
+
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
+ swapChainDesc.Width = m_SwapChainDesc.Width;
+ swapChainDesc.Height = m_SwapChainDesc.Height;
+ // Flip model swapchains (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL and DXGI_SWAP_EFFECT_FLIP_DISCARD) only support the following Formats:
+ // - DXGI_FORMAT_R16G16B16A16_FLOAT
+ // - DXGI_FORMAT_B8G8R8A8_UNORM
+ // - DXGI_FORMAT_R8G8B8A8_UNORM
+ // - DXGI_FORMAT_R10G10B10A2_UNORM
+ // If RGBA8_UNORM_SRGB swap chain is required, we will create RGBA8_UNORM swap chain, but
+ // create RGBA8_UNORM_SRGB render target view
+ swapChainDesc.Format = DXGIColorBuffFmt == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGIColorBuffFmt;
+ swapChainDesc.Stereo = FALSE;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.BufferCount = m_SwapChainDesc.BufferCount;
+ swapChainDesc.Scaling = DXGI_SCALING_NONE;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; // Not used
+ swapChainDesc.Flags = 0;
+
+ CComPtr<IDXGISwapChain1> pSwapChain1;
+ CComPtr<IDXGIFactory4> factory;
+ HRESULT hr = CreateDXGIFactory1(__uuidof(factory), reinterpret_cast<void**>(static_cast<IDXGIFactory4**>(&factory)) );
+ CHECK_D3D_RESULT_THROW(hr, "Failed to create DXGI factory")
+
+ auto *pVkCmdQueue = pRenderDeviceVk->GetCmdQueue()->GetVkCommandQueue();
+#if PLATFORM_WIN32
+ hr = factory->CreateSwapChainForHwnd(pVkCmdQueue, hWnd, &swapChainDesc, nullptr, nullptr, &pSwapChain1);
+ CHECK_D3D_RESULT_THROW( hr, "Failed to create Swap Chain" );
+
+ // This sample does not support fullscreen transitions.
+ hr = factory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER);
+
+#elif PLATFORM_UNIVERSAL_WINDOWS
+
+ hr = factory->CreateSwapChainForCoreWindow(
+ pVkCmdQueue,
+ reinterpret_cast<IUnknown*>(pNativeWndHandle),
+ &swapChainDesc,
+ nullptr,
+ &pSwapChain1);
+ CHECK_D3D_RESULT_THROW( hr, "Failed to create DXGI swap chain" );
+
+ // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
+ // ensures that the application will only render after each VSync, minimizing power consumption.
+ //pDXGIDevice->SetMaximumFrameLatency( 1 );
+
+#endif
+
+ pSwapChain1->QueryInterface(__uuidof(m_pSwapChain), reinterpret_cast<void**>( static_cast<IDXGISwapChain3**>(&m_pSwapChain) ));
+
+ InitBuffersAndViews();
+#endif
+}
+
+SwapChainVkImpl::~SwapChainVkImpl()
+{
+
+}
+
+#if 0
+void SwapChainVkImpl::InitBuffersAndViews()
+{
+ m_pBackBufferRTV.resize(m_SwapChainDesc.BufferCount);
+ for(Uint32 backbuff = 0; backbuff < m_SwapChainDesc.BufferCount; ++backbuff)
+ {
+ CComPtr<IVkResource> pBackBuffer;
+ auto hr = m_pSwapChain->GetBuffer(backbuff, __uuidof(pBackBuffer), reinterpret_cast<void**>( static_cast<IVkResource**>(&pBackBuffer) ));
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to get back buffer ", backbuff," from the swap chain");
+
+ hr = pBackBuffer->SetName(L"Main back buffer");
+ VERIFY_EXPR(SUCCEEDED(hr));
+
+ TextureDesc BackBufferDesc;
+ BackBufferDesc.Format = m_SwapChainDesc.ColorBufferFormat;
+ String Name = "Main back buffer ";
+ Name += std::to_string(backbuff);
+ BackBufferDesc.Name = Name.c_str();
+
+ RefCntAutoPtr<TextureVkImpl> pBackBufferTex;
+ ValidatedCast<RenderDeviceVkImpl>(m_pRenderDevice.RawPtr())->CreateTexture(BackBufferDesc, pBackBuffer, &pBackBufferTex);
+ TextureViewDesc RTVDesc;
+ RTVDesc.ViewType = TEXTURE_VIEW_RENDER_TARGET;
+ RefCntAutoPtr<ITextureView> pRTV;
+ pBackBufferTex->CreateView(RTVDesc, &pRTV);
+ m_pBackBufferRTV[backbuff] = RefCntAutoPtr<ITextureViewVk>(pRTV, IID_TextureViewVk);
+ }
+
+ TextureDesc DepthBufferDesc;
+ DepthBufferDesc.Type = RESOURCE_DIM_TEX_2D;
+ DepthBufferDesc.Width = m_SwapChainDesc.Width;
+ DepthBufferDesc.Height = m_SwapChainDesc.Height;
+ DepthBufferDesc.Format = m_SwapChainDesc.DepthBufferFormat;
+ DepthBufferDesc.SampleCount = m_SwapChainDesc.SamplesCount;
+ DepthBufferDesc.Usage = USAGE_DEFAULT;
+ DepthBufferDesc.BindFlags = BIND_DEPTH_STENCIL;
+
+ DepthBufferDesc.ClearValue.Format = DepthBufferDesc.Format;
+ DepthBufferDesc.ClearValue.DepthStencil.Depth = m_SwapChainDesc.DefaultDepthValue;
+ DepthBufferDesc.ClearValue.DepthStencil.Stencil = m_SwapChainDesc.DefaultStencilValue;
+ DepthBufferDesc.Name = "Main depth buffer";
+ RefCntAutoPtr<ITexture> pDepthBufferTex;
+ m_pRenderDevice->CreateTexture(DepthBufferDesc, TextureData(), static_cast<ITexture**>(&pDepthBufferTex) );
+ auto pDSV = pDepthBufferTex->GetDefaultView(TEXTURE_VIEW_DEPTH_STENCIL);
+ m_pDepthBufferDSV = RefCntAutoPtr<ITextureViewVk>(pDSV, IID_TextureViewVk);
+}
+#endif
+
+IMPLEMENT_QUERY_INTERFACE( SwapChainVkImpl, IID_SwapChainVk, TSwapChainBase )
+
+
+void SwapChainVkImpl::Present()
+{
+#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 )
+ {
+ LOG_ERROR_MESSAGE( "Immediate context has been released" );
+ return;
+ }
+
+ auto *pImmediateCtx = pDeviceContext.RawPtr();
+ auto *pImmediateCtxVk = ValidatedCast<DeviceContextVkImpl>( pImmediateCtx );
+
+ auto *pCmdCtx = pImmediateCtxVk->RequestCmdContext();
+ auto *pBackBuffer = ValidatedCast<TextureVkImpl>( GetCurrentBackBufferRTV()->GetTexture() );
+ pCmdCtx->TransitionResource( pBackBuffer, Vk_RESOURCE_STATE_PRESENT);
+
+ pImmediateCtxVk->Flush();
+
+ auto *pDeviceVk = ValidatedCast<RenderDeviceVkImpl>( pImmediateCtxVk->GetDevice() );
+
+ auto hr = m_pSwapChain->Present( SyncInterval, 0 );
+ VERIFY(SUCCEEDED(hr), "Present failed");
+
+ pDeviceVk->FinishFrame();
+
+#if 0
+#if PLATFORM_UNIVERSAL_WINDOWS
+ // A successful Present call for DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL SwapChains unbinds
+ // backbuffer 0 from all GPU writeable bind points.
+ // We need to rebind all render targets to make sure that
+ // the back buffer is not unbound
+ pImmediateCtxVk->CommitRenderTargets();
+#endif
+#endif
+#endif
+}
+
+void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight )
+{
+ if( TSwapChainBase::Resize(NewWidth, NewHeight) )
+ {
+#if 0
+ auto pDeviceContext = m_wpDeviceContext.Lock();
+ VERIFY( pDeviceContext, "Immediate context has been released" );
+ if( pDeviceContext )
+ {
+ RenderDeviceVkImpl *pDeviceVk = ValidatedCast<RenderDeviceVkImpl>(m_pRenderDevice.RawPtr());
+ pDeviceContext->Flush();
+
+ try
+ {
+ auto *pImmediateCtxVk = ValidatedCast<DeviceContextVkImpl>(pDeviceContext.RawPtr());
+ bool bIsDefaultFBBound = pImmediateCtxVk->IsDefaultFBBound();
+
+ // All references to the swap chain must be released before it can be resized
+ m_pBackBufferRTV.clear();
+ m_pDepthBufferDSV.Release();
+
+ // This will release references to Vk swap chain buffers hold by
+ // m_pBackBufferRTV[]
+ pDeviceVk->IdleGPU(true);
+
+ DXGI_SWAP_CHAIN_DESC SCDes;
+ memset( &SCDes, 0, sizeof( SCDes ) );
+ m_pSwapChain->GetDesc( &SCDes );
+ CHECK_D3D_RESULT_THROW( m_pSwapChain->ResizeBuffers(SCDes.BufferCount, m_SwapChainDesc.Width,
+ m_SwapChainDesc.Height, SCDes.BufferDesc.Format,
+ SCDes.Flags),
+ "Failed to resize the DXGI swap chain" );
+
+
+ InitBuffersAndViews();
+
+ if( bIsDefaultFBBound )
+ {
+ // Set default render target and viewport
+ pDeviceContext->SetRenderTargets( 0, nullptr, nullptr );
+ pDeviceContext->SetViewports( 1, nullptr, 0, 0 );
+ }
+ }
+ catch( const std::runtime_error & )
+ {
+ LOG_ERROR( "Failed to resize the swap chain" );
+ }
+ }
+#endif
+ }
+}
+
+#if 0
+ITextureViewVk *SwapChainVkImpl::GetCurrentBackBufferRTV()
+{
+ auto CurrentBackBufferIndex = m_pSwapChain->GetCurrentBackBufferIndex();
+ VERIFY_EXPR(CurrentBackBufferIndex >= 0 && CurrentBackBufferIndex < m_SwapChainDesc.BufferCount);
+ return m_pBackBufferRTV[CurrentBackBufferIndex];
+}
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp
new file mode 100644
index 00000000..6a58538f
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp
@@ -0,0 +1,61 @@
+/* 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 "TextureViewVkImpl.h"
+#include "DeviceContextVkImpl.h"
+
+namespace Diligent
+{
+
+TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters *pRefCounters,
+ IRenderDevice *pDevice,
+ const TextureViewDesc& ViewDesc,
+ ITexture *pTexture,
+ DescriptorHeapAllocation &&HandleAlloc,
+ bool bIsDefaultView ) :
+ TTextureViewBase( pRefCounters, pDevice, ViewDesc, pTexture, bIsDefaultView ),
+ m_Descriptor(std::move(HandleAlloc))
+{
+}
+//
+//IVkView* TextureViewVkImpl::GetVkView()
+//{
+// return m_pVkView;
+//}
+
+IMPLEMENT_QUERY_INTERFACE( TextureViewVkImpl, IID_TextureViewVk, TTextureViewBase )
+
+void TextureViewVkImpl::GenerateMips( IDeviceContext *pContext )
+{
+ VERIFY( m_Desc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, "GenerateMips() is allowed for shader resource views only, ", GetTexViewTypeLiteralName(m_Desc.ViewType), " is not allowed." );
+ if( m_Desc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE )
+ {
+ LOG_ERROR("GenerateMips() is allowed for shader resource views only, ", GetTexViewTypeLiteralName(m_Desc.ViewType), " is not allowed.");
+ return;
+ }
+ auto *pDeviceCtxVk = ValidatedCast<DeviceContextVkImpl>( pContext );
+ pDeviceCtxVk->GenerateMips(this);
+}
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
new file mode 100644
index 00000000..1b452377
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
@@ -0,0 +1,546 @@
+/* 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 "TextureVkImpl.h"
+#include "RenderDeviceVkImpl.h"
+#include "DeviceContextVkImpl.h"
+#include "VulkanTypeConversions.h"
+#include "TextureViewVkImpl.h"
+//#include "DXGITypeConversions.h"
+#include "EngineMemory.h"
+#include "StringTools.h"
+
+using namespace Diligent;
+
+namespace Diligent
+{
+
+#if 0
+DXGI_FORMAT GetClearFormat(DXGI_FORMAT Fmt, Vk_RESOURCE_FLAGS Flags)
+{
+ if( Flags & Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL )
+ {
+ switch (Fmt)
+ {
+ case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_D32_FLOAT;
+ case DXGI_FORMAT_R16_TYPELESS: return DXGI_FORMAT_D16_UNORM;
+ case DXGI_FORMAT_R24G8_TYPELESS: return DXGI_FORMAT_D24_UNORM_S8_UINT;
+ case DXGI_FORMAT_R32G8X24_TYPELESS: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
+ }
+ }
+ else if (Flags & Vk_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
+ {
+
+ }
+ return Fmt;
+}
+#endif
+
+TextureVkImpl :: TextureVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &TexViewObjAllocator,
+ RenderDeviceVkImpl *pRenderDeviceVk,
+ const TextureDesc& TexDesc,
+ const TextureData &InitData /*= TextureData()*/) :
+ TTextureBase(pRefCounters, TexViewObjAllocator, pRenderDeviceVk, TexDesc)
+{
+ 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;
+ else
+ {
+ LOG_ERROR_AND_THROW("Unknown texture type");
+ }
+
+
+ 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;
+ HeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN;
+ HeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN;
+ HeapProps.CreationNodeMask = 1;
+ HeapProps.VisibleNodeMask = 1;
+
+ auto *pVkDevice = pRenderDeviceVk->GetVkDevice();
+ Vk_CLEAR_VALUE ClearValue;
+ Vk_CLEAR_VALUE *pClearValue = nullptr;
+ if( Desc.Flags & (Vk_RESOURCE_FLAG_ALLOW_RENDER_TARGET | Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) )
+ {
+ if(m_Desc.ClearValue.Format != TEX_FORMAT_UNKNOWN)
+ ClearValue.Format = TexFormatToDXGI_Format(m_Desc.ClearValue.Format);
+ else
+ ClearValue.Format = GetClearFormat(Format, Desc.Flags);
+
+ if (Desc.Flags & Vk_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
+ {
+ for(int i=0; i < 4; ++i)
+ ClearValue.Color[i] = m_Desc.ClearValue.Color[i];
+ }
+ else if(Desc.Flags & Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
+ {
+ ClearValue.DepthStencil.Depth = m_Desc.ClearValue.DepthStencil.Depth;
+ ClearValue.DepthStencil.Stencil = m_Desc.ClearValue.DepthStencil.Stencil;
+ }
+ pClearValue = &ClearValue;
+ }
+
+ bool bInitializeTexture = (InitData.pSubResources != nullptr && InitData.NumSubresources > 0);
+ if(bInitializeTexture)
+ m_UsageState = Vk_RESOURCE_STATE_COPY_DEST;
+
+ 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");
+
+ if( *m_Desc.Name != 0)
+ m_pVkResource->SetName(WidenString(m_Desc.Name).c_str());
+
+ if(bInitializeTexture)
+ {
+ Uint32 ExpectedNumSubresources = static_cast<Uint32>(Desc.MipLevels * (Desc.Dimension == Vk_RESOURCE_DIMENSION_TEXTURE3D ? 1 : Desc.DepthOrArraySize) );
+ if( InitData.NumSubresources != ExpectedNumSubresources )
+ LOG_ERROR_AND_THROW("Incorrect number of subresources in init data. ", ExpectedNumSubresources, " expected, while ", InitData.NumSubresources, " provided");
+
+ UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_pVkResource, 0, InitData.NumSubresources);
+
+ Vk_HEAP_PROPERTIES UploadHeapProps;
+ UploadHeapProps.Type = Vk_HEAP_TYPE_UPLOAD;
+ UploadHeapProps.CPUPageProperty = Vk_CPU_PAGE_PROPERTY_UNKNOWN;
+ UploadHeapProps.MemoryPoolPreference = Vk_MEMORY_POOL_UNKNOWN;
+ UploadHeapProps.CreationNodeMask = 1;
+ UploadHeapProps.VisibleNodeMask = 1;
+
+ Vk_RESOURCE_DESC BufferDesc;
+ BufferDesc.Dimension = Vk_RESOURCE_DIMENSION_BUFFER;
+ BufferDesc.Alignment = 0;
+ BufferDesc.Width = uploadBufferSize;
+ BufferDesc.Height = 1;
+ BufferDesc.DepthOrArraySize = 1;
+ BufferDesc.MipLevels = 1;
+ BufferDesc.Format = DXGI_FORMAT_UNKNOWN;
+ BufferDesc.SampleDesc.Count = 1;
+ BufferDesc.SampleDesc.Quality = 0;
+ BufferDesc.Layout = Vk_TEXTURE_LAYOUT_ROW_MAJOR;
+ BufferDesc.Flags = Vk_RESOURCE_FLAG_NONE;
+
+ CComPtr<IVkResource> UploadBuffer;
+ hr = pVkDevice->CreateCommittedResource( &UploadHeapProps, Vk_HEAP_FLAG_NONE,
+ &BufferDesc, Vk_RESOURCE_STATE_GENERIC_READ,
+ nullptr, __uuidof(UploadBuffer), reinterpret_cast<void**>(static_cast<IVkResource**>(&UploadBuffer)));
+ if(FAILED(hr))
+ LOG_ERROR_AND_THROW("Failed to create committed resource in an upload heap");
+
+ auto *pInitContext = pRenderDeviceVk->AllocateCommandContext();
+ // copy data to the intermediate upload heap and then schedule a copy from the upload heap to the default texture
+ VERIFY_EXPR(m_UsageState == Vk_RESOURCE_STATE_COPY_DEST);
+ std::vector<Vk_SUBRESOURCE_DATA, STDAllocatorRawMem<Vk_SUBRESOURCE_DATA> > VkSubResData(InitData.NumSubresources, Vk_SUBRESOURCE_DATA(), STD_ALLOCATOR_RAW_MEM(Vk_SUBRESOURCE_DATA, GetRawAllocator(), "Allocator for vector<Vk_SUBRESOURCE_DATA>") );
+ for(size_t subres=0; subres < VkSubResData.size(); ++subres)
+ {
+ VkSubResData[subres].pData = InitData.pSubResources[subres].pData;
+ VkSubResData[subres].RowPitch = InitData.pSubResources[subres].Stride;
+ VkSubResData[subres].SlicePitch = InitData.pSubResources[subres].DepthStride;
+ }
+ auto UploadedSize = UpdateSubresources(pInitContext->GetCommandList(), m_pVkResource, UploadBuffer, 0, 0, InitData.NumSubresources, VkSubResData.data());
+ VERIFY(UploadedSize == uploadBufferSize, "Incorrect uploaded data size (", UploadedSize, "). ", uploadBufferSize, " is expected");
+
+ // Command list fence should only be signaled when submitting cmd list
+ // from the immediate context, otherwise the basic requirement will be violated
+ // as in the scenario below
+ // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/
+ //
+ // Signaled Fence | Immediate Context | InitContext |
+ // | | |
+ // N | Draw(ResourceX) | |
+ // | Release(ResourceX) | |
+ // | - (ResourceX, N) -> Release Queue | |
+ // | | CopyResource() |
+ // N+1 | | CloseAndExecuteCommandContext() |
+ // | | |
+ // N+2 | CloseAndExecuteCommandContext() | |
+ // | - Cmd list is submitted with number | |
+ // | N+1, but resource it references | |
+ // | was added to the delete queue | |
+ // | with value N | |
+ pRenderDeviceVk->CloseAndExecuteCommandContext(pInitContext, false);
+
+ // We MUST NOT call TransitionResource() from here, because
+ // it will call AddRef() and potentially Release(), while
+ // the object is not constructed yet
+ // 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);
+ }
+
+ if(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)
+ {
+ if (m_Desc.Type != RESOURCE_DIM_TEX_2D && m_Desc.Type != RESOURCE_DIM_TEX_2D_ARRAY)
+ {
+ LOG_ERROR_AND_THROW("Mipmap generation is only supported for 2D textures and texture arrays");
+ }
+
+ m_MipUAVs = pRenderDeviceVk->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_Desc.MipLevels);
+ for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel)
+ {
+ TextureViewDesc UAVDesc;
+ // Always create texture array UAV
+ UAVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
+ UAVDesc.ViewType = TEXTURE_VIEW_UNORDERED_ACCESS;
+ UAVDesc.FirstArraySlice = 0;
+ UAVDesc.NumArraySlices = m_Desc.ArraySize;
+ UAVDesc.MostDetailedMip = MipLevel;
+ if (m_Desc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB)
+ UAVDesc.Format = TEX_FORMAT_RGBA8_UNORM;
+ CreateUAV( UAVDesc, m_MipUAVs.GetCpuHandle(MipLevel) );
+ }
+
+ {
+ m_TexArraySRV = pRenderDeviceVk->AllocateDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
+ TextureViewDesc TexArraySRVDesc;
+ // Create texture array SRV
+ TexArraySRVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
+ TexArraySRVDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE;
+ TexArraySRVDesc.FirstArraySlice = 0;
+ TexArraySRVDesc.NumArraySlices = m_Desc.ArraySize;
+ TexArraySRVDesc.MostDetailedMip = 0;
+ TexArraySRVDesc.NumMipLevels = m_Desc.MipLevels;
+ CreateSRV( TexArraySRVDesc, m_TexArraySRV.GetCpuHandle() );
+ }
+ }
+#endif
+}
+
+static TextureDesc InitTexDescFromVkResource(void *pTexture, const TextureDesc& SrcTexDesc)
+{
+ //auto ResourceDesc = pTexture->GetDesc();
+
+ TextureDesc TexDesc = SrcTexDesc;
+#if 0
+ if (TexDesc.Format == TEX_FORMAT_UNKNOWN)
+ TexDesc.Format = DXGI_FormatToTexFormat(ResourceDesc.Format);
+ auto RefDXGIFormat = TexFormatToDXGI_Format(TexDesc.Format);
+ if( RefDXGIFormat != TexDesc.Format)
+ LOG_ERROR_AND_THROW("Incorrect texture format (", GetTextureFormatAttribs(TexDesc.Format).Name, ")");
+
+ TexDesc.Width = static_cast<Uint32>( ResourceDesc.Width );
+ TexDesc.Height = Uint32{ ResourceDesc.Height };
+ TexDesc.ArraySize = Uint32{ ResourceDesc.DepthOrArraySize };
+ TexDesc.MipLevels = Uint32{ ResourceDesc.MipLevels };
+ switch(ResourceDesc.Dimension)
+ {
+ case Vk_RESOURCE_DIMENSION_TEXTURE1D: TexDesc.Type = TexDesc.ArraySize == 1 ? RESOURCE_DIM_TEX_1D : RESOURCE_DIM_TEX_1D_ARRAY; break;
+ case Vk_RESOURCE_DIMENSION_TEXTURE2D: TexDesc.Type = TexDesc.ArraySize == 1 ? RESOURCE_DIM_TEX_2D : RESOURCE_DIM_TEX_2D_ARRAY; break;
+ case Vk_RESOURCE_DIMENSION_TEXTURE3D: TexDesc.Type = RESOURCE_DIM_TEX_3D; break;
+ }
+
+ TexDesc.SampleCount = ResourceDesc.SampleDesc.Count;
+
+ TexDesc.Usage = USAGE_DEFAULT;
+ TexDesc.BindFlags = 0;
+ if( (ResourceDesc.Flags & Vk_RESOURCE_FLAG_ALLOW_RENDER_TARGET) != 0 )
+ TexDesc.BindFlags |= BIND_RENDER_TARGET;
+ if( (ResourceDesc.Flags & Vk_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) != 0 )
+ TexDesc.BindFlags |= BIND_DEPTH_STENCIL;
+ if( (ResourceDesc.Flags & Vk_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) != 0 )
+ TexDesc.BindFlags |= BIND_UNORDERED_ACCESS;
+ if ((ResourceDesc.Flags & Vk_RESOURCE_FLAG_DENY_SHADER_RESOURCE) == 0)
+ {
+ auto FormatAttribs = GetTextureFormatAttribs(TexDesc.Format);
+ if (FormatAttribs.ComponentType != COMPONENT_TYPE_DEPTH &&
+ FormatAttribs.ComponentType != COMPONENT_TYPE_DEPTH_STENCIL)
+ {
+ TexDesc.BindFlags |= BIND_SHADER_RESOURCE;
+ }
+ }
+#endif
+ return TexDesc;
+}
+
+
+TextureVkImpl::TextureVkImpl(IReferenceCounters *pRefCounters,
+ FixedBlockMemoryAllocator &TexViewObjAllocator,
+ RenderDeviceVkImpl *pDeviceVk,
+ const TextureDesc& TexDesc,
+ void *pTexture) :
+ TTextureBase(pRefCounters, TexViewObjAllocator, pDeviceVk, InitTexDescFromVkResource(pTexture, TexDesc))
+{
+#if 0
+ m_pVkResource = pTexture;
+#endif
+}
+IMPLEMENT_QUERY_INTERFACE( TextureVkImpl, IID_TextureVk, TTextureBase )
+
+void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )
+{
+ VERIFY( ppView != nullptr, "View pointer address is null" );
+ if( !ppView )return;
+ VERIFY( *ppView == nullptr, "Overwriting reference to existing object may cause memory leaks" );
+
+ *ppView = nullptr;
+#if 0
+ try
+ {
+ auto *pDeviceVkImpl = ValidatedCast<RenderDeviceVkImpl>(GetDevice());
+ auto &TexViewAllocator = pDeviceVkImpl->GetTexViewObjAllocator();
+ VERIFY( &TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization" );
+
+ auto UpdatedViewDesc = ViewDesc;
+ CorrectTextureViewDesc( UpdatedViewDesc );
+
+ DescriptorHeapAllocation ViewHandleAlloc;
+ 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() );
+ }
+ 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() );
+ }
+ 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() );
+ }
+ 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() );
+ }
+ break;
+
+ default: UNEXPECTED( "Unknown view type" ); break;
+ }
+
+ auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr)
+ (GetDevice(), UpdatedViewDesc, this, std::move(ViewHandleAlloc), bIsDefaultView );
+ VERIFY( pViewVk->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type" );
+
+ if( bIsDefaultView )
+ *ppView = pViewVk;
+ else
+ pViewVk->QueryInterface(IID_TextureView, reinterpret_cast<IObject**>(ppView) );
+ }
+ catch( const std::runtime_error & )
+ {
+ 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 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 )
+{
+ TTextureBase::UpdateData( pContext, MipLevel, Slice, DstBox, SubresData );
+ if (SubresData.pSrcBuffer == nullptr)
+ {
+ LOG_ERROR("Vk does not allow updating texture subresource from CPU memory");
+ return;
+ }
+
+ VERIFY( m_Desc.Usage == USAGE_DEFAULT, "Only default usage resiurces can be updated with UpdateData()" );
+
+ auto *pCtxVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+#if 0
+ auto DstSubResIndex = VkCalcSubresource(MipLevel, Slice, 0, m_Desc.MipLevels, m_Desc.ArraySize);
+
+ pCtxVk->CopyTextureRegion(SubresData.pSrcBuffer, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, DstBox);
+#endif
+}
+
+void TextureVkImpl :: CopyData(IDeviceContext *pContext,
+ ITexture *pSrcTexture,
+ Uint32 SrcMipLevel,
+ Uint32 SrcSlice,
+ const Box *pSrcBox,
+ Uint32 DstMipLevel,
+ Uint32 DstSlice,
+ Uint32 DstX,
+ Uint32 DstY,
+ Uint32 DstZ)
+{
+ TTextureBase::CopyData( pContext, pSrcTexture, SrcMipLevel, SrcSlice, pSrcBox,
+ DstMipLevel, DstSlice, DstX, DstY, DstZ );
+
+ auto *pCtxVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ auto *pSrcTexVk = ValidatedCast<TextureVkImpl>( pSrcTexture );
+
+#if 0
+ Vk_BOX VkSrcBox, *pVkSrcBox = nullptr;
+ if( pSrcBox )
+ {
+ VkSrcBox.left = pSrcBox->MinX;
+ VkSrcBox.right = pSrcBox->MaxX;
+ VkSrcBox.top = pSrcBox->MinY;
+ VkSrcBox.bottom = pSrcBox->MaxY;
+ VkSrcBox.front = pSrcBox->MinZ;
+ VkSrcBox.back = pSrcBox->MaxZ;
+ pVkSrcBox = &VkSrcBox;
+ }
+
+ auto DstSubResIndex = VkCalcSubresource(DstMipLevel, DstSlice, 0, m_Desc.MipLevels, m_Desc.ArraySize);
+ auto SrcSubResIndex = VkCalcSubresource(SrcMipLevel, SrcSlice, 0, pSrcTexVk->m_Desc.MipLevels, pSrcTexVk->m_Desc.ArraySize);
+ pCtxVk->CopyTextureRegion(pSrcTexVk, SrcSubResIndex, pVkSrcBox, this, DstSubResIndex, DstX, DstY, DstZ);
+#endif
+}
+
+void TextureVkImpl :: Map(IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags, MappedTextureSubresource &MappedData)
+{
+ TTextureBase::Map( pContext, Subresource, MapType, MapFlags, MappedData );
+ LOG_ERROR_ONCE("TextureVkImpl::Map() is not implemented");
+
+ static char TmpDummyBuffer[1024*1024*64];
+ MappedData.pData = TmpDummyBuffer;
+}
+
+void TextureVkImpl::Unmap( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags )
+{
+ TTextureBase::Unmap( pContext, Subresource, MapType, MapFlags );
+ LOG_ERROR_ONCE("TextureVkImpl::Unmap() is not implemented");
+}
+
+#if 0
+void TextureVkImpl::CreateSRV( TextureViewDesc &SRVDesc, Vk_CPU_DESCRIPTOR_HANDLE SRVHandle )
+{
+ VERIFY( SRVDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE, "Incorrect view type: shader resource is expected" );
+
+ if( SRVDesc.Format == TEX_FORMAT_UNKNOWN )
+ {
+ SRVDesc.Format = m_Desc.Format;
+ }
+ Vk_SHADER_RESOURCE_VIEW_DESC Vk_SRVDesc;
+ TextureViewDesc_to_Vk_SRV_DESC(SRVDesc, Vk_SRVDesc, m_Desc.SampleCount);
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateShaderResourceView(m_pVkResource, &Vk_SRVDesc, SRVHandle);
+}
+
+void TextureVkImpl::CreateRTV( TextureViewDesc &RTVDesc, Vk_CPU_DESCRIPTOR_HANDLE RTVHandle )
+{
+ VERIFY( RTVDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET, "Incorrect view type: render target is expected" );
+
+ if( RTVDesc.Format == TEX_FORMAT_UNKNOWN )
+ {
+ RTVDesc.Format = m_Desc.Format;
+ }
+
+ Vk_RENDER_TARGET_VIEW_DESC Vk_RTVDesc;
+ TextureViewDesc_to_Vk_RTV_DESC(RTVDesc, Vk_RTVDesc, m_Desc.SampleCount);
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateRenderTargetView( m_pVkResource, &Vk_RTVDesc, RTVHandle );
+}
+
+void TextureVkImpl::CreateDSV( TextureViewDesc &DSVDesc, Vk_CPU_DESCRIPTOR_HANDLE DSVHandle )
+{
+ VERIFY( DSVDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL, "Incorrect view type: depth stencil is expected" );
+
+ if( DSVDesc.Format == TEX_FORMAT_UNKNOWN )
+ {
+ DSVDesc.Format = m_Desc.Format;
+ }
+
+ Vk_DEPTH_STENCIL_VIEW_DESC Vk_DSVDesc;
+ TextureViewDesc_to_Vk_DSV_DESC(DSVDesc, Vk_DSVDesc, m_Desc.SampleCount);
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateDepthStencilView( m_pVkResource, &Vk_DSVDesc, DSVHandle );
+}
+
+void TextureVkImpl::CreateUAV( TextureViewDesc &UAVDesc, Vk_CPU_DESCRIPTOR_HANDLE UAVHandle )
+{
+ VERIFY( UAVDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, "Incorrect view type: unordered access is expected" );
+
+ if( UAVDesc.Format == TEX_FORMAT_UNKNOWN )
+ {
+ UAVDesc.Format = m_Desc.Format;
+ }
+
+ Vk_UNORDERED_ACCESS_VIEW_DESC Vk_UAVDesc;
+ TextureViewDesc_to_Vk_UAV_DESC(UAVDesc, Vk_UAVDesc);
+
+ auto *pDeviceVk = static_cast<RenderDeviceVkImpl*>(GetDevice())->GetVkDevice();
+ pDeviceVk->CreateUnorderedAccessView( m_pVkResource, nullptr, &Vk_UAVDesc, UAVHandle );
+}
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanResourceBase.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanResourceBase.cpp
new file mode 100644
index 00000000..67cf4f1f
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanResourceBase.cpp
@@ -0,0 +1,30 @@
+/* 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 "VulkanResourceBase.h"
+
+namespace Diligent
+{
+
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
new file mode 100644
index 00000000..77c22c26
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
@@ -0,0 +1,302 @@
+/* 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 "VulkanTypeConversions.h"
+//#include "DXGITypeConversions.h"
+
+#include "VulkanTypeDefinitions.h"
+//#include "VulkanTypeConversionImpl.h"
+//#include "D3DViewDescConversionImpl.h"
+
+namespace Diligent
+{
+
+#if 0
+D3D12_COMPARISON_FUNC ComparisonFuncToD3D12ComparisonFunc(COMPARISON_FUNCTION Func)
+{
+ return ComparisonFuncToD3DComparisonFunc<D3D12_COMPARISON_FUNC>(Func);
+}
+
+D3D12_FILTER FilterTypeToD3D12Filter(FILTER_TYPE MinFilter, FILTER_TYPE MagFilter, FILTER_TYPE MipFilter)
+{
+ return FilterTypeToD3DFilter<D3D12_FILTER>(MinFilter, MagFilter, MipFilter);
+}
+
+D3D12_TEXTURE_ADDRESS_MODE TexAddressModeToD3D12AddressMode(TEXTURE_ADDRESS_MODE Mode)
+{
+ return TexAddressModeToD3DAddressMode<D3D12_TEXTURE_ADDRESS_MODE>(Mode);
+}
+
+void DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(const DepthStencilStateDesc &DepthStencilDesc, D3D12_DEPTH_STENCIL_DESC &d3d12DSSDesc)
+{
+ DepthStencilStateDesc_To_D3D_DEPTH_STENCIL_DESC<D3D12_DEPTH_STENCIL_DESC, D3D12_DEPTH_STENCILOP_DESC, D3D12_STENCIL_OP, D3D12_COMPARISON_FUNC>(DepthStencilDesc, d3d12DSSDesc);
+}
+
+void RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(const RasterizerStateDesc &RasterizerDesc, D3D12_RASTERIZER_DESC &d3d12RSDesc)
+{
+ RasterizerStateDesc_To_D3D_RASTERIZER_DESC<D3D12_RASTERIZER_DESC, D3D12_FILL_MODE, D3D12_CULL_MODE>(RasterizerDesc, d3d12RSDesc);
+
+ // The sample count that is forced while UAV rendering or rasterizing.
+ // Valid values are 0, 1, 2, 4, 8, and optionally 16. 0 indicates that
+ // the sample count is not forced.
+ d3d12RSDesc.ForcedSampleCount = 0;
+
+ d3d12RSDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+}
+
+
+
+D3D12_LOGIC_OP LogicOperationToD3D12LogicOp( LOGIC_OPERATION lo )
+{
+ // Note that this code is safe for multithreaded environments since
+ // bIsInit is set to true only AFTER the entire map is initialized.
+ static bool bIsInit = false;
+ static D3D12_LOGIC_OP D3D12LogicOp[LOGIC_OP_NUM_OPERATIONS] = {};
+ if( !bIsInit )
+ {
+ // In a multithreaded environment, several threads can potentially enter
+ // this block. This is not a problem since they will just initialize the
+ // memory with the same values more than once
+ D3D12LogicOp[ D3D12_LOGIC_OP_CLEAR ] = D3D12_LOGIC_OP_CLEAR;
+ D3D12LogicOp[ D3D12_LOGIC_OP_SET ] = D3D12_LOGIC_OP_SET;
+ D3D12LogicOp[ D3D12_LOGIC_OP_COPY ] = D3D12_LOGIC_OP_COPY;
+ D3D12LogicOp[ D3D12_LOGIC_OP_COPY_INVERTED ] = D3D12_LOGIC_OP_COPY_INVERTED;
+ D3D12LogicOp[ D3D12_LOGIC_OP_NOOP ] = D3D12_LOGIC_OP_NOOP;
+ D3D12LogicOp[ D3D12_LOGIC_OP_INVERT ] = D3D12_LOGIC_OP_INVERT;
+ D3D12LogicOp[ D3D12_LOGIC_OP_AND ] = D3D12_LOGIC_OP_AND;
+ D3D12LogicOp[ D3D12_LOGIC_OP_NAND ] = D3D12_LOGIC_OP_NAND;
+ D3D12LogicOp[ D3D12_LOGIC_OP_OR ] = D3D12_LOGIC_OP_OR;
+ D3D12LogicOp[ D3D12_LOGIC_OP_NOR ] = D3D12_LOGIC_OP_NOR;
+ D3D12LogicOp[ D3D12_LOGIC_OP_XOR ] = D3D12_LOGIC_OP_XOR;
+ D3D12LogicOp[ D3D12_LOGIC_OP_EQUIV ] = D3D12_LOGIC_OP_EQUIV;
+ D3D12LogicOp[ D3D12_LOGIC_OP_AND_REVERSE ] = D3D12_LOGIC_OP_AND_REVERSE;
+ D3D12LogicOp[ D3D12_LOGIC_OP_AND_INVERTED ] = D3D12_LOGIC_OP_AND_INVERTED;
+ D3D12LogicOp[ D3D12_LOGIC_OP_OR_REVERSE ] = D3D12_LOGIC_OP_OR_REVERSE;
+ D3D12LogicOp[ D3D12_LOGIC_OP_OR_INVERTED ] = D3D12_LOGIC_OP_OR_INVERTED;
+
+ bIsInit = true;
+ }
+ if( lo >= LOGIC_OP_CLEAR && lo < LOGIC_OP_NUM_OPERATIONS )
+ {
+ auto d3dlo = D3D12LogicOp[lo];
+ return d3dlo;
+ }
+ else
+ {
+ UNEXPECTED("Incorrect blend factor (", lo, ")" );
+ return static_cast<D3D12_LOGIC_OP>( 0 );
+ }
+}
+
+
+void BlendStateDesc_To_D3D12_BLEND_DESC(const BlendStateDesc &BSDesc, D3D12_BLEND_DESC &d3d12BlendDesc)
+{
+ BlendStateDescToD3DBlendDesc<D3D12_BLEND_DESC, D3D12_BLEND, D3D12_BLEND_OP>(BSDesc, d3d12BlendDesc);
+
+ for( int i = 0; i < 8; ++i )
+ {
+ const auto& SrcRTDesc = BSDesc.RenderTargets[i];
+ auto &DstRTDesc = d3d12BlendDesc.RenderTarget[i];
+
+ // The following members only present in D3D_RENDER_TARGET_BLEND_DESC
+ DstRTDesc.LogicOpEnable = SrcRTDesc.LogicOperationEnable ? TRUE : FALSE;
+ DstRTDesc.LogicOp = LogicOperationToD3D12LogicOp(SrcRTDesc.LogicOp);
+ }
+}
+
+void LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(const std::vector<LayoutElement, STDAllocatorRawMem<LayoutElement>> &LayoutElements,
+ std::vector<D3D12_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D12_INPUT_ELEMENT_DESC> > &d3d12InputElements)
+{
+ LayoutElements_To_D3D_INPUT_ELEMENT_DESCs<D3D12_INPUT_ELEMENT_DESC>(LayoutElements, d3d12InputElements);
+}
+
+D3D12_PRIMITIVE_TOPOLOGY TopologyToD3D12Topology(PRIMITIVE_TOPOLOGY Topology)
+{
+ return TopologyToD3DTopology<D3D12_PRIMITIVE_TOPOLOGY>(Topology);
+}
+
+
+
+void TextureViewDesc_to_D3D12_SRV_DESC(const TextureViewDesc& SRVDesc, D3D12_SHADER_RESOURCE_VIEW_DESC &D3D12SRVDesc, Uint32 SampleCount)
+{
+ TextureViewDesc_to_D3D_SRV_DESC(SRVDesc, D3D12SRVDesc, SampleCount);
+ D3D12SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ switch (SRVDesc.TextureDim)
+ {
+ case RESOURCE_DIM_TEX_1D:
+ D3D12SRVDesc.Texture1D.ResourceMinLODClamp = 0;
+ break;
+
+ case RESOURCE_DIM_TEX_1D_ARRAY:
+ D3D12SRVDesc.Texture1DArray.ResourceMinLODClamp = 0;
+ break;
+
+ case RESOURCE_DIM_TEX_2D:
+ if( SampleCount > 1 )
+ {
+ }
+ else
+ {
+ D3D12SRVDesc.Texture2D.PlaneSlice = 0;
+ D3D12SRVDesc.Texture2D.ResourceMinLODClamp = 0;
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_2D_ARRAY:
+ if( SampleCount > 1 )
+ {
+ }
+ else
+ {
+ D3D12SRVDesc.Texture2DArray.PlaneSlice = 0;
+ D3D12SRVDesc.Texture2DArray.ResourceMinLODClamp = 0;
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_3D:
+ D3D12SRVDesc.Texture3D.ResourceMinLODClamp = 0;
+ break;
+
+ case RESOURCE_DIM_TEX_CUBE:
+ D3D12SRVDesc.TextureCube.ResourceMinLODClamp = 0;
+ break;
+
+ case RESOURCE_DIM_TEX_CUBE_ARRAY:
+ D3D12SRVDesc.TextureCubeArray.ResourceMinLODClamp = 0;
+ break;
+
+ default:
+ UNEXPECTED( "Unexpected view type" );
+ }
+}
+
+void TextureViewDesc_to_D3D12_RTV_DESC(const TextureViewDesc& RTVDesc, D3D12_RENDER_TARGET_VIEW_DESC &D3D12RTVDesc, Uint32 SampleCount)
+{
+ TextureViewDesc_to_D3D_RTV_DESC(RTVDesc, D3D12RTVDesc, SampleCount);
+ switch (RTVDesc.TextureDim)
+ {
+ case RESOURCE_DIM_TEX_1D:
+ break;
+
+ case RESOURCE_DIM_TEX_1D_ARRAY:
+ break;
+
+ case RESOURCE_DIM_TEX_2D:
+ if( SampleCount > 1 )
+ {
+ }
+ else
+ {
+ D3D12RTVDesc.Texture2D.PlaneSlice = 0;
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_2D_ARRAY:
+ if( SampleCount > 1 )
+ {
+ }
+ else
+ {
+ D3D12RTVDesc.Texture2DArray.PlaneSlice = 0;
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_3D:
+ break;
+
+ default:
+ UNEXPECTED( "Unexpected view type" );
+ }
+}
+
+void TextureViewDesc_to_D3D12_DSV_DESC(const TextureViewDesc& DSVDesc, D3D12_DEPTH_STENCIL_VIEW_DESC &D3D12DSVDesc, Uint32 SampleCount)
+{
+ TextureViewDesc_to_D3D_DSV_DESC(DSVDesc, D3D12DSVDesc, SampleCount);
+ D3D12DSVDesc.Flags = D3D12_DSV_FLAG_NONE;
+}
+
+void TextureViewDesc_to_D3D12_UAV_DESC(const TextureViewDesc& UAVDesc, D3D12_UNORDERED_ACCESS_VIEW_DESC &D3D12UAVDesc)
+{
+ TextureViewDesc_to_D3D_UAV_DESC(UAVDesc, D3D12UAVDesc);
+ switch (UAVDesc.TextureDim)
+ {
+ case RESOURCE_DIM_TEX_1D:
+ break;
+
+ case RESOURCE_DIM_TEX_1D_ARRAY:
+ break;
+
+ case RESOURCE_DIM_TEX_2D:
+ D3D12UAVDesc.Texture2D.PlaneSlice = 0;
+ break;
+
+ case RESOURCE_DIM_TEX_2D_ARRAY:
+ D3D12UAVDesc.Texture2DArray.PlaneSlice = 0;
+ break;
+
+ case RESOURCE_DIM_TEX_3D:
+ break;
+
+ default:
+ UNEXPECTED( "Unexpected view type" );
+ }
+}
+
+
+void BufferViewDesc_to_D3D12_SRV_DESC(const BufferDesc &BuffDesc, const BufferViewDesc& SRVDesc, D3D12_SHADER_RESOURCE_VIEW_DESC &D3D12SRVDesc)
+{
+ BufferViewDesc_to_D3D_SRV_DESC(BuffDesc, SRVDesc, D3D12SRVDesc);
+ D3D12SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ D3D12SRVDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
+ VERIFY_EXPR(BuffDesc.BindFlags & BIND_SHADER_RESOURCE);
+ if (BuffDesc.Mode == BUFFER_MODE_STRUCTURED)
+ D3D12SRVDesc.Buffer.StructureByteStride = BuffDesc.ElementByteStride;
+}
+
+void BufferViewDesc_to_D3D12_UAV_DESC(const BufferDesc &BuffDesc, const BufferViewDesc& UAVDesc, D3D12_UNORDERED_ACCESS_VIEW_DESC &D3D12UAVDesc)
+{
+ BufferViewDesc_to_D3D_UAV_DESC(BuffDesc, UAVDesc, D3D12UAVDesc);
+ D3D12UAVDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
+ VERIFY_EXPR(BuffDesc.BindFlags & BIND_UNORDERED_ACCESS);
+ if (BuffDesc.Mode == BUFFER_MODE_STRUCTURED)
+ D3D12UAVDesc.Buffer.StructureByteStride = BuffDesc.ElementByteStride;
+}
+
+D3D12_STATIC_BORDER_COLOR BorderColorToD3D12StaticBorderColor(const Float32 BorderColor[])
+{
+ D3D12_STATIC_BORDER_COLOR StaticBorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
+ if(BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 0)
+ StaticBorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
+ else if(BorderColor[0] == 0 && BorderColor[1] == 0 && BorderColor[2] == 0 && BorderColor[3] == 1)
+ StaticBorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
+ else if(BorderColor[0] == 1 && BorderColor[1] == 1 && BorderColor[2] == 1 && BorderColor[3] == 0)
+ StaticBorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
+ else
+ {
+ LOG_ERROR_MESSAGE("Static samplers only allow transparent black (0,0,0,1), opaque black (0,0,0,0) or opaque white (1,1,1,0) as border colors.");
+ }
+ return StaticBorderColor;
+}
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtils.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtils.cpp
new file mode 100644
index 00000000..562cbe81
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtils.cpp
@@ -0,0 +1,47 @@
+/* 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 "VulkanUtils.h"
+
+namespace Diligent
+{
+#if 0
+ const Char* GetD3D12DescriptorHeapTypeLiteralName(D3D12_DESCRIPTOR_HEAP_TYPE Type)
+ {
+ static bool bIsInitialized = false;
+ static const Char* HeapTypeNames[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
+ if (!bIsInitialized)
+ {
+ HeapTypeNames[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] = "D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV";
+ HeapTypeNames[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER] = "D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER";
+ HeapTypeNames[D3D12_DESCRIPTOR_HEAP_TYPE_RTV] = "D3D12_DESCRIPTOR_HEAP_TYPE_RTV";
+ HeapTypeNames[D3D12_DESCRIPTOR_HEAP_TYPE_DSV] = "D3D12_DESCRIPTOR_HEAP_TYPE_DSV";
+
+ bIsInitialized = true;
+ }
+ VERIFY_EXPR(Type >= 0 && Type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES);
+ return HeapTypeNames[Type];
+ }
+#endif
+}
diff --git a/Graphics/GraphicsEngineVulkan/src/pch.cpp b/Graphics/GraphicsEngineVulkan/src/pch.cpp
new file mode 100644
index 00000000..3eef26a8
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/pch.cpp
@@ -0,0 +1,24 @@
+/* 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"