From cc038e873634fef5ca4c861e375bf8a39ef372ae Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sun, 24 Nov 2019 15:34:48 -0800 Subject: clang-formatted cpp files of GraphiceEngineVulkan project --- .../include/CommandPoolManager.h | 31 +- .../GraphicsEngineVulkan/src/BufferViewVkImpl.cpp | 20 +- Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp | 218 +- .../src/CommandPoolManager.cpp | 38 +- .../src/CommandQueueVkImpl.cpp | 52 +- .../src/DescriptorPoolManager.cpp | 66 +- .../src/DeviceContextVkImpl.cpp | 3713 ++++++++++---------- .../GraphicsEngineVulkan/src/EngineFactoryVk.cpp | 220 +- Graphics/GraphicsEngineVulkan/src/FenceVkImpl.cpp | 31 +- .../GraphicsEngineVulkan/src/FramebufferCache.cpp | 48 +- .../src/GenerateMipsVkHelper.cpp | 727 ++-- .../GraphicsEngineVulkan/src/PipelineLayout.cpp | 206 +- .../src/PipelineStateVkImpl.cpp | 286 +- .../src/RenderDeviceVkImpl.cpp | 274 +- .../GraphicsEngineVulkan/src/RenderPassCache.cpp | 25 +- .../GraphicsEngineVulkan/src/SamplerVkImpl.cpp | 48 +- .../src/ShaderResourceBindingVkImpl.cpp | 42 +- .../src/ShaderResourceCacheVk.cpp | 149 +- .../src/ShaderResourceLayoutVk.cpp | 437 +-- .../GraphicsEngineVulkan/src/ShaderVariableVk.cpp | 89 +- Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp | 44 +- .../GraphicsEngineVulkan/src/SwapChainVkImpl.cpp | 270 +- .../GraphicsEngineVulkan/src/TextureViewVkImpl.cpp | 22 +- .../GraphicsEngineVulkan/src/TextureVkImpl.cpp | 349 +- .../GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp | 151 +- .../src/VulkanTypeConversions.cpp | 356 +- .../GraphicsEngineVulkan/src/VulkanUploadHeap.cpp | 57 +- .../src/VulkanUtilities/VulkanCommandBuffer.cpp | 203 +- .../VulkanUtilities/VulkanCommandBufferPool.cpp | 152 +- .../src/VulkanUtilities/VulkanDebug.cpp | 1034 +++--- .../src/VulkanUtilities/VulkanFencePool.cpp | 68 +- .../src/VulkanUtilities/VulkanInstance.cpp | 388 +- .../src/VulkanUtilities/VulkanLogicalDevice.cpp | 887 ++--- .../src/VulkanUtilities/VulkanMemoryManager.cpp | 79 +- .../src/VulkanUtilities/VulkanPhysicalDevice.cpp | 277 +- 35 files changed, 5704 insertions(+), 5353 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h b/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h index c28d1838..525d1d60 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h @@ -37,11 +37,11 @@ class RenderDeviceVkImpl; class CommandPoolManager { public: - CommandPoolManager(RenderDeviceVkImpl& DeviceVkImpl, + CommandPoolManager(RenderDeviceVkImpl& DeviceVkImpl, std::string Name, - uint32_t queueFamilyIndex, - VkCommandPoolCreateFlags flags)noexcept; - + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags) noexcept; + // clang-format off CommandPoolManager (const CommandPoolManager&) = delete; CommandPoolManager ( CommandPoolManager&&) = delete; @@ -52,31 +52,34 @@ public: ~CommandPoolManager(); // Allocates Vulkan command pool. - VulkanUtilities::CommandPoolWrapper AllocateCommandPool(const char *DebugName = nullptr); - + VulkanUtilities::CommandPoolWrapper AllocateCommandPool(const char* DebugName = nullptr); + void SafeReleaseCommandPool(VulkanUtilities::CommandPoolWrapper&& CmdPool, Uint32 CmdQueueIndex, Uint64 FenceValue); void DestroyPools(); #ifdef DEVELOPMENT - int32_t GetAllocatedPoolCount()const{return m_AllocatedPoolCounter;} + int32_t GetAllocatedPoolCount() const + { + return m_AllocatedPoolCounter; + } #endif private: // Returns command pool to the list of available pools. The GPU must have finished using the pool void FreeCommandPool(VulkanUtilities::CommandPoolWrapper&& CmdPool); - RenderDeviceVkImpl& m_DeviceVkImpl; - const std::string m_Name; - const uint32_t m_QueueFamilyIndex; - const VkCommandPoolCreateFlags m_CmdPoolFlags; + RenderDeviceVkImpl& m_DeviceVkImpl; + const std::string m_Name; + const uint32_t m_QueueFamilyIndex; + const VkCommandPoolCreateFlags m_CmdPoolFlags; - std::mutex m_Mutex; - std::deque< VulkanUtilities::CommandPoolWrapper, STDAllocatorRawMem > m_CmdPools; + std::mutex m_Mutex; + std::deque> m_CmdPools; #ifdef DEVELOPMENT std::atomic_int32_t m_AllocatedPoolCounter; #endif }; -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp index eb9b4001..74cd8ab7 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferViewVkImpl.cpp @@ -29,12 +29,13 @@ namespace Diligent { -BufferViewVkImpl::BufferViewVkImpl( IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDevice, - const BufferViewDesc& ViewDesc, - IBuffer* pBuffer, - VulkanUtilities::BufferViewWrapper&& BuffView, - bool bIsDefaultView ) : +BufferViewVkImpl::BufferViewVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDevice, + const BufferViewDesc& ViewDesc, + IBuffer* pBuffer, + VulkanUtilities::BufferViewWrapper&& BuffView, + bool bIsDefaultView) : + // clang-format off TBufferViewBase { pRefCounters, @@ -44,6 +45,7 @@ BufferViewVkImpl::BufferViewVkImpl( IReferenceCounters* pRefCou bIsDefaultView }, m_BuffView{std::move(BuffView)} +// clang-format on { } @@ -52,9 +54,9 @@ BufferViewVkImpl::~BufferViewVkImpl() m_pDevice->SafeReleaseDeviceObject(std::move(m_BuffView), m_pBuffer->GetDesc().CommandQueueMask); } -IMPLEMENT_QUERY_INTERFACE( BufferViewVkImpl, IID_BufferViewVk, TBufferViewBase ) +IMPLEMENT_QUERY_INTERFACE(BufferViewVkImpl, IID_BufferViewVk, TBufferViewBase) -const BufferVkImpl* BufferViewVkImpl::GetBufferVk()const +const BufferVkImpl* BufferViewVkImpl::GetBufferVk() const { return ValidatedCast(m_pBuffer); } @@ -64,4 +66,4 @@ BufferVkImpl* BufferViewVkImpl::GetBufferVk() return ValidatedCast(m_pBuffer); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp index 8f96a003..3a878440 100644 --- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp @@ -36,11 +36,12 @@ namespace Diligent { -BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, - FixedBlockMemoryAllocator& BuffViewObjMemAllocator, - RenderDeviceVkImpl* pRenderDeviceVk, - const BufferDesc& BuffDesc, - const BufferData* pBuffData /*= nullptr*/) : +BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, + FixedBlockMemoryAllocator& BuffViewObjMemAllocator, + RenderDeviceVkImpl* pRenderDeviceVk, + const BufferDesc& BuffDesc, + const BufferData* pBuffData /*= nullptr*/) : + // clang-format off TBufferBase { pRefCounters, @@ -50,38 +51,39 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, false }, m_DynamicAllocations{STD_ALLOCATOR_RAW_MEM(VulkanDynamicAllocation, GetRawAllocator(), "Allocator for vector")} +// clang-format on { -#define LOG_BUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Buffer \"", BuffDesc.Name ? BuffDesc.Name : "", "\": ", ##__VA_ARGS__); +#define LOG_BUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Buffer \"", BuffDesc.Name ? BuffDesc.Name : "", "\": ", ##__VA_ARGS__) - if( m_Desc.Usage == USAGE_STATIC && (pBuffData == nullptr || pBuffData->pData == nullptr) ) - LOG_BUFFER_ERROR_AND_THROW("Static buffer must be initialized with data at creation time") + if (m_Desc.Usage == USAGE_STATIC && (pBuffData == nullptr || pBuffData->pData == nullptr)) + LOG_BUFFER_ERROR_AND_THROW("Static buffer must be initialized with data at creation time"); - if( m_Desc.Usage == USAGE_DYNAMIC && pBuffData != nullptr && pBuffData->pData != nullptr ) - LOG_BUFFER_ERROR_AND_THROW("Dynamic buffer must be initialized via Map()") + if (m_Desc.Usage == USAGE_DYNAMIC && pBuffData != nullptr && pBuffData->pData != nullptr) + LOG_BUFFER_ERROR_AND_THROW("Dynamic buffer must be initialized via Map()"); if (m_Desc.Usage == USAGE_STAGING) { 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") + 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 (pBuffData != nullptr && pBuffData->pData != nullptr) - LOG_BUFFER_ERROR_AND_THROW("CPU-writable staging buffers must be updated via map") + LOG_BUFFER_ERROR_AND_THROW("CPU-writable staging buffers must be updated via map"); } } const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); - const auto& DeviceLimits = pRenderDeviceVk->GetPhysicalDevice().GetProperties().limits; - m_DynamicOffsetAlignment = std::max(Uint32{4}, static_cast(DeviceLimits.optimalBufferCopyOffsetAlignment)); + const auto& DeviceLimits = pRenderDeviceVk->GetPhysicalDevice().GetProperties().limits; + m_DynamicOffsetAlignment = std::max(Uint32{4}, static_cast(DeviceLimits.optimalBufferCopyOffsetAlignment)); VkBufferCreateInfo VkBuffCI = {}; - VkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - VkBuffCI.pNext = nullptr; - VkBuffCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT - VkBuffCI.size = m_Desc.uiSizeInBytes; + VkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + VkBuffCI.pNext = nullptr; + VkBuffCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT + VkBuffCI.size = m_Desc.uiSizeInBytes; VkBuffCI.usage = - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command VK_BUFFER_USAGE_TRANSFER_DST_BIT; // The buffer can be used as the destination of a transfer command if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) { @@ -89,15 +91,15 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, // HLSL formatted buffers are mapped to GLSL storage buffers: // // RWBuffer RWBuff - // + // // | // V - // + // // layout(std140, binding = 3) buffer RWBuff // { // uvec4 data[]; // }g_RWBuff; - // + // // So we have to set both VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT and VK_BUFFER_USAGE_STORAGE_BUFFER_BIT bits VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; @@ -110,7 +112,7 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, if (m_Desc.BindFlags & BIND_SHADER_RESOURCE) { // VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - // HLSL buffer SRVs are mapped to storge buffers in GLSL, so we need to set both + // HLSL buffer SRVs are mapped to storge buffers in GLSL, so we need to set both // VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT and VK_BUFFER_USAGE_STORAGE_BUFFER_BIT flags VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; @@ -128,16 +130,16 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; // Each element of pDynamicOffsets parameter of vkCmdBindDescriptorSets function which corresponds to a descriptor - // binding with type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC must be a multiple of + // binding with type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC must be a multiple of // VkPhysicalDeviceLimits::minUniformBufferOffsetAlignment (13.2.5) m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast(DeviceLimits.minUniformBufferOffsetAlignment)); } - if(m_Desc.Usage == USAGE_DYNAMIC) + if (m_Desc.Usage == USAGE_DYNAMIC) { auto CtxCount = 1 + pRenderDeviceVk->GetNumDeferredContexts(); m_DynamicAllocations.reserve(CtxCount); - for(Uint32 ctx=0; ctx < CtxCount; ++ctx) + for (Uint32 ctx = 0; ctx < CtxCount; ++ctx) m_DynamicAllocations.emplace_back(); } @@ -146,32 +148,33 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, // 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 constexpr RESOURCE_STATE State = static_cast( - RESOURCE_STATE_VERTEX_BUFFER | - RESOURCE_STATE_INDEX_BUFFER | - RESOURCE_STATE_CONSTANT_BUFFER | - RESOURCE_STATE_SHADER_RESOURCE | - RESOURCE_STATE_COPY_SOURCE | - RESOURCE_STATE_INDIRECT_ARGUMENT); + RESOURCE_STATE_VERTEX_BUFFER | + RESOURCE_STATE_INDEX_BUFFER | + RESOURCE_STATE_CONSTANT_BUFFER | + RESOURCE_STATE_SHADER_RESOURCE | + RESOURCE_STATE_COPY_SOURCE | + RESOURCE_STATE_INDIRECT_ARGUMENT); SetState(State); #ifdef _DEBUG { - VkAccessFlags AccessFlags = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_TRANSFER_READ_BIT; + VkAccessFlags AccessFlags = + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_TRANSFER_READ_BIT; VERIFY_EXPR(ResourceStateFlagsToVkAccessFlags(State) == AccessFlags); } #endif } else { - VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // sharing mode of the buffer when it will be accessed by multiple queue families. - VkBuffCI.queueFamilyIndexCount = 0; // number of entries in the pQueueFamilyIndices array - VkBuffCI.pQueueFamilyIndices = nullptr; // list of queue families that will access this buffer - // (ignored if sharingMode is not VK_SHARING_MODE_CONCURRENT). + VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // sharing mode of the buffer when it will be accessed by multiple queue families. + VkBuffCI.queueFamilyIndexCount = 0; // number of entries in the pQueueFamilyIndices array + VkBuffCI.pQueueFamilyIndices = nullptr; // list of queue families that will access this buffer + // (ignored if sharingMode is not VK_SHARING_MODE_CONCURRENT). m_VulkanBuffer = LogicalDevice.CreateBuffer(VkBuffCI, m_Desc.Name); @@ -183,21 +186,21 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, else BufferMemoryFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - VERIFY( IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); + VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs, BufferMemoryFlags); auto AlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment); VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (AlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small"); auto Memory = m_MemoryAllocation.Page->GetVkMemory(); - auto err = LogicalDevice.BindBufferMemory(m_VulkanBuffer, Memory, AlignedOffset); + auto err = LogicalDevice.BindBufferMemory(m_VulkanBuffer, Memory, AlignedOffset); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory"); - bool bInitializeBuffer = (pBuffData != nullptr && pBuffData->pData != nullptr && pBuffData->DataSize > 0); - RESOURCE_STATE InitialState = RESOURCE_STATE_UNDEFINED; - if( bInitializeBuffer ) + bool bInitializeBuffer = (pBuffData != nullptr && pBuffData->pData != nullptr && pBuffData->DataSize > 0); + RESOURCE_STATE InitialState = RESOURCE_STATE_UNDEFINED; + if (bInitializeBuffer) { VkBufferCreateInfo VkStaginBuffCI = VkBuffCI; - VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; std::string StagingBufferName = "Upload buffer for '"; StagingBufferName += m_Desc.Name; @@ -205,13 +208,13 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, VulkanUtilities::BufferWrapper StagingBuffer = LogicalDevice.CreateBuffer(VkStaginBuffCI, StagingBufferName.c_str()); VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(StagingBuffer); - VERIFY( IsPowerOfTwo(StagingBufferMemReqs.alignment), "Alignment is not power of 2!"); + VERIFY(IsPowerOfTwo(StagingBufferMemReqs.alignment), "Alignment is not power of 2!"); - // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges + // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible // to the host (10.2) auto StagingMemoryAllocation = pRenderDeviceVk->AllocateMemory(StagingBufferMemReqs, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - auto StagingBufferMemory = StagingMemoryAllocation.Page->GetVkMemory(); + auto StagingBufferMemory = StagingMemoryAllocation.Page->GetVkMemory(); auto AlignedStagingMemOffset = Align(VkDeviceSize{StagingMemoryAllocation.UnalignedOffset}, StagingBufferMemReqs.alignment); VERIFY_EXPR(StagingMemoryAllocation.Size >= StagingBufferMemReqs.size + (AlignedStagingMemOffset - StagingMemoryAllocation.UnalignedOffset)); @@ -224,12 +227,12 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, CHECK_VK_ERROR_AND_THROW(err, "Failed to bind staging bufer memory"); VulkanUtilities::CommandPoolWrapper CmdPool; - VkCommandBuffer vkCmdBuff; + VkCommandBuffer vkCmdBuff; pRenderDeviceVk->AllocateTransientCmdPool(CmdPool, vkCmdBuff, "Transient command pool to copy staging data to a device buffer"); auto EnabledGraphicsShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages(); VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledGraphicsShaderStages); - InitialState = RESOURCE_STATE_COPY_DEST; + InitialState = RESOURCE_STATE_COPY_DEST; VkAccessFlags AccessFlags = ResourceStateFlagsToVkAccessFlags(InitialState); VERIFY_EXPR(AccessFlags == VK_ACCESS_TRANSFER_WRITE_BIT); VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, AccessFlags, EnabledGraphicsShaderStages); @@ -237,17 +240,17 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, // Copy commands MUST be recorded outside of a render pass instance. This is OK here // as copy will be the only command in the cmd buffer VkBufferCopy BuffCopy = {}; - BuffCopy.srcOffset = 0; - BuffCopy.dstOffset = 0; - BuffCopy.size = VkBuffCI.size; + BuffCopy.srcOffset = 0; + BuffCopy.dstOffset = 0; + BuffCopy.size = VkBuffCI.size; vkCmdCopyBuffer(vkCmdBuff, StagingBuffer, m_VulkanBuffer, 1, &BuffCopy); Uint32 QueueIndex = 0; - pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool)); + pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool)); // After command buffer is submitted, safe-release staging resources. This strategy - // is little overconservative as the resources will only be released after the + // is little overconservative as the resources will only be released after the // first command buffer submitted through the immediate context is complete // Next Cmd Buff| Next Fence | This Thread | Immediate Context @@ -257,20 +260,20 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, // | | ExecuteAndDisposeTransientCmdBuff(vkCmdBuff) | // | | - SubmittedCmdBuffNumber = N | // | | - SubmittedFenceValue = F | - // N+1 - - | - F+1 - | | + // N+1 - - | - F+1 - | | // | | Release(StagingBuffer) | // | | - {N+1, StagingBuffer} -> Stale Objects | // | | | // | | | - // | | | ExecuteCommandBuffer() + // | | | ExecuteCommandBuffer() // | | | - SubmittedCmdBuffNumber = N+1 // | | | - SubmittedFenceValue = F+1 - // N+2 - - | - F+2 - | - - - - - - - - - - - - | - // | | | - DiscardStaleVkObjects(N+1, F+1) - // | | | - {F+1, StagingBuffer} -> Release Queue - // | | | + // N+2 - - | - F+2 - | - - - - - - - - - - - - | + // | | | - DiscardStaleVkObjects(N+1, F+1) + // | | | - {F+1, StagingBuffer} -> Release Queue + // | | | - pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingBuffer), Uint64{1} << Uint64{QueueIndex}); + pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingBuffer), Uint64{1} << Uint64{QueueIndex}); pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingMemoryAllocation), Uint64{1} << Uint64{QueueIndex}); } @@ -281,59 +284,67 @@ BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, } -BufferVkImpl :: BufferVkImpl(IReferenceCounters* pRefCounters, - FixedBlockMemoryAllocator& BuffViewObjMemAllocator, - RenderDeviceVkImpl* pRenderDeviceVk, - const BufferDesc& BuffDesc, - RESOURCE_STATE InitialState, - VkBuffer vkBuffer) : - TBufferBase(pRefCounters, BuffViewObjMemAllocator, pRenderDeviceVk, BuffDesc, false), - m_DynamicAllocations(STD_ALLOCATOR_RAW_MEM(VulkanDynamicAllocation, GetRawAllocator(), "Allocator for vector")), - m_VulkanBuffer(vkBuffer) +BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters, + FixedBlockMemoryAllocator& BuffViewObjMemAllocator, + RenderDeviceVkImpl* pRenderDeviceVk, + const BufferDesc& BuffDesc, + RESOURCE_STATE InitialState, + VkBuffer vkBuffer) : + // clang-format off + TBufferBase + { + pRefCounters, + BuffViewObjMemAllocator, + pRenderDeviceVk, + BuffDesc, + false + }, + m_DynamicAllocations{STD_ALLOCATOR_RAW_MEM(VulkanDynamicAllocation, GetRawAllocator(), "Allocator for vector")}, + m_VulkanBuffer{vkBuffer} +// clang-format on { SetState(InitialState); } -BufferVkImpl :: ~BufferVkImpl() +BufferVkImpl::~BufferVkImpl() { // Vk object can only be destroyed when it is no longer used by the GPU - if(m_VulkanBuffer != VK_NULL_HANDLE) + if (m_VulkanBuffer != VK_NULL_HANDLE) m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanBuffer), m_Desc.CommandQueueMask); - if(m_MemoryAllocation.Page != nullptr) + if (m_MemoryAllocation.Page != nullptr) m_pDevice->SafeReleaseDeviceObject(std::move(m_MemoryAllocation), m_Desc.CommandQueueMask); } -IMPLEMENT_QUERY_INTERFACE( BufferVkImpl, IID_BufferVk, TBufferBase ) +IMPLEMENT_QUERY_INTERFACE(BufferVkImpl, IID_BufferVk, TBufferBase) -void BufferVkImpl::CreateViewInternal( const BufferViewDesc& OrigViewDesc, IBufferView** ppView, bool bIsDefaultView ) +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" ); + VERIFY(ppView != nullptr, "Null pointer provided"); + if (!ppView) return; + VERIFY(*ppView == nullptr, "Overwriting reference to existing object may cause memory leaks"); *ppView = nullptr; try { auto& BuffViewAllocator = m_pDevice->GetBuffViewObjAllocator(); - VERIFY( &BuffViewAllocator == &m_dbgBuffViewAllocator, "Buff view allocator does not match allocator provided at buffer initialization" ); + 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 || ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE ) + if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS || ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE) { auto View = CreateView(ViewDesc); - *ppView = NEW_RC_OBJ(BuffViewAllocator, "BufferViewVkImpl instance", BufferViewVkImpl, bIsDefaultView ? this : nullptr) - (GetDevice(), ViewDesc, this, std::move(View), bIsDefaultView ); + *ppView = NEW_RC_OBJ(BuffViewAllocator, "BufferViewVkImpl instance", BufferViewVkImpl, bIsDefaultView ? this : nullptr)(GetDevice(), ViewDesc, this, std::move(View), bIsDefaultView); } - if( !bIsDefaultView && *ppView ) + if (!bIsDefaultView && *ppView) (*ppView)->AddRef(); } - catch( const std::runtime_error & ) + 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, "\"" ); + const auto* ViewTypeName = GetBufferViewTypeLiteralName(OrigViewDesc.ViewType); + LOG_ERROR("Failed to create view \"", OrigViewDesc.Name ? OrigViewDesc.Name : "", "\" (", ViewTypeName, ") for buffer \"", m_Desc.Name, "\""); } } @@ -342,13 +353,14 @@ VulkanUtilities::BufferViewWrapper BufferVkImpl::CreateView(struct BufferViewDes { VulkanUtilities::BufferViewWrapper BuffView; CorrectBufferViewDesc(ViewDesc); - if( (ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE || ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS) && + if ((ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE || ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS) && (m_Desc.Mode == BUFFER_MODE_FORMATTED || m_Desc.Mode == BUFFER_MODE_RAW)) { VkBufferViewCreateInfo ViewCI = {}; - ViewCI.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; - ViewCI.pNext = nullptr; - ViewCI.flags = 0; // reserved for future use + + ViewCI.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + ViewCI.pNext = nullptr; + ViewCI.flags = 0; // reserved for future use ViewCI.buffer = m_VulkanBuffer; if (m_Desc.Mode == BUFFER_MODE_RAW && ViewDesc.Format.ValueType == VT_UNDEFINED) { @@ -360,15 +372,15 @@ VulkanUtilities::BufferViewWrapper BufferVkImpl::CreateView(struct BufferViewDes ViewCI.format = TypeToVkFormat(ViewDesc.Format.ValueType, ViewDesc.Format.NumComponents, ViewDesc.Format.IsNormalized); } ViewCI.offset = ViewDesc.ByteOffset; // offset in bytes from the base address of the buffer - ViewCI.range = ViewDesc.ByteWidth; // size in bytes of the buffer view + ViewCI.range = ViewDesc.ByteWidth; // size in bytes of the buffer view const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); - BuffView = LogicalDevice.CreateBufferView(ViewCI, ViewDesc.Name); + BuffView = LogicalDevice.CreateBufferView(ViewCI, ViewDesc.Name); } return BuffView; } -VkBuffer BufferVkImpl::GetVkBuffer()const +VkBuffer BufferVkImpl::GetVkBuffer() const { if (m_VulkanBuffer != VK_NULL_HANDLE) return m_VulkanBuffer; @@ -384,20 +396,20 @@ void BufferVkImpl::SetAccessFlags(VkAccessFlags AccessFlags) SetState(VkAccessFlagsToResourceStates(AccessFlags)); } -VkAccessFlags BufferVkImpl::GetAccessFlags()const +VkAccessFlags BufferVkImpl::GetAccessFlags() const { return ResourceStateFlagsToVkAccessFlags(GetState()); } #ifdef DEVELOPMENT -void BufferVkImpl::DvpVerifyDynamicAllocation(DeviceContextVkImpl* pCtx)const +void BufferVkImpl::DvpVerifyDynamicAllocation(DeviceContextVkImpl* pCtx) const { - auto ContextId = pCtx->GetContextId(); - const auto& DynAlloc = m_DynamicAllocations[ContextId]; - auto CurrentFrame = pCtx->GetContextFrameNumber(); + auto ContextId = pCtx->GetContextId(); + const auto& DynAlloc = m_DynamicAllocations[ContextId]; + auto CurrentFrame = pCtx->GetContextFrameNumber(); DEV_CHECK_ERR(DynAlloc.pDynamicMemMgr != nullptr, "Dynamic buffer '", m_Desc.Name, "' has not been mapped before its first use. Context Id: ", ContextId, ". Note: memory for dynamic buffers is allocated when a buffer is mapped."); DEV_CHECK_ERR(DynAlloc.dvpFrameNumber == CurrentFrame, "Dynamic allocation of dynamic buffer '", m_Desc.Name, "' in frame ", CurrentFrame, " is out-of-date. Note: contents of all dynamic resources is discarded at the end of every frame. A buffer must be mapped before its first use in any frame."); } #endif -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp index 30186949..fbe0caab 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp @@ -28,15 +28,17 @@ namespace Diligent { -CommandPoolManager::CommandPoolManager(RenderDeviceVkImpl& DeviceVkImpl, +CommandPoolManager::CommandPoolManager(RenderDeviceVkImpl& DeviceVkImpl, std::string Name, - uint32_t queueFamilyIndex, - VkCommandPoolCreateFlags flags)noexcept: + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags) noexcept : + // clang-format off m_DeviceVkImpl {DeviceVkImpl }, m_Name {std::move(Name) }, m_QueueFamilyIndex{queueFamilyIndex }, m_CmdPoolFlags {flags }, m_CmdPools {STD_ALLOCATOR_RAW_MEM(VulkanUtilities::CommandPoolWrapper, GetRawAllocator(), "Allocator for deque")} +// clang-format on { #ifdef DEVELOPMENT m_AllocatedPoolCounter = 0; @@ -45,23 +47,25 @@ CommandPoolManager::CommandPoolManager(RenderDeviceVkImpl& DeviceVkImpl, VulkanUtilities::CommandPoolWrapper CommandPoolManager::AllocateCommandPool(const char* DebugName) { - std::lock_guard LockGuard(m_Mutex); + std::lock_guard LockGuard{m_Mutex}; VulkanUtilities::CommandPoolWrapper CmdPool; - if(!m_CmdPools.empty()) + if (!m_CmdPools.empty()) { CmdPool = std::move(m_CmdPools.front()); m_CmdPools.pop_front(); } auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); - if(CmdPool == VK_NULL_HANDLE) + if (CmdPool == VK_NULL_HANDLE) { VkCommandPoolCreateInfo CmdPoolCI = {}; + CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; CmdPoolCI.pNext = nullptr; CmdPoolCI.queueFamilyIndex = m_QueueFamilyIndex; CmdPoolCI.flags = m_CmdPoolFlags; + CmdPool = LogicalDevice.CreateCommandPool(CmdPoolCI); DEV_CHECK_ERR(CmdPool != VK_NULL_HANDLE, "Failed to create Vulkan command pool"); } @@ -80,37 +84,41 @@ void CommandPoolManager::SafeReleaseCommandPool(VulkanUtilities::CommandPoolWrap { public: CommandPoolDeleter(CommandPoolManager& _CmdPoolMgr, VulkanUtilities::CommandPoolWrapper&& _Pool) : - CmdPoolMgr(&_CmdPoolMgr), - Pool (std::move(_Pool)) + // clang-format off + CmdPoolMgr{&_CmdPoolMgr }, + Pool {std::move(_Pool)} + // clang-format on { VERIFY_EXPR(Pool != VK_NULL_HANDLE); } + // clang-format off CommandPoolDeleter (const CommandPoolDeleter&) = delete; CommandPoolDeleter& operator = (const CommandPoolDeleter&) = delete; CommandPoolDeleter& operator = ( CommandPoolDeleter&&) = delete; CommandPoolDeleter(CommandPoolDeleter&& rhs) : - CmdPoolMgr(rhs.CmdPoolMgr), - Pool (std::move(rhs.Pool)) + CmdPoolMgr{rhs.CmdPoolMgr }, + Pool {std::move(rhs.Pool)} { rhs.CmdPoolMgr = nullptr; } - + // clang-format on ~CommandPoolDeleter() { - if (CmdPoolMgr!=nullptr) + if (CmdPoolMgr != nullptr) { CmdPoolMgr->FreeCommandPool(std::move(Pool)); } } + private: CommandPoolManager* CmdPoolMgr; VulkanUtilities::CommandPoolWrapper Pool; }; - // Discard command pool directly to the release queue since we know exactly which queue it was submitted to + // Discard command pool directly to the release queue since we know exactly which queue it was submitted to // as well as the associated FenceValue m_DeviceVkImpl.GetReleaseQueue(CmdQueueIndex).DiscardResource(CommandPoolDeleter{*this, std::move(CmdPool)}, FenceValue); } @@ -128,7 +136,7 @@ void CommandPoolManager::DestroyPools() { std::lock_guard LockGuard(m_Mutex); DEV_CHECK_ERR(m_AllocatedPoolCounter == 0, m_AllocatedPoolCounter, " pool(s) have not been freed. This will cause a crash if the references to these pools are still in release queues when CommandPoolManager::FreeCommandPool() is called for destroyed CommandPoolManager object."); - LOG_INFO_MESSAGE(m_Name, " allocated descriptor pool count: ", m_CmdPools.size() ); + LOG_INFO_MESSAGE(m_Name, " allocated descriptor pool count: ", m_CmdPools.size()); m_CmdPools.clear(); } @@ -137,4 +145,4 @@ CommandPoolManager::~CommandPoolManager() DEV_CHECK_ERR(m_CmdPools.empty() && m_AllocatedPoolCounter == 0, "Command pools have not been destroyed"); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp index 79c03886..cb378edd 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandQueueVkImpl.cpp @@ -28,25 +28,27 @@ namespace Diligent { -CommandQueueVkImpl::CommandQueueVkImpl(IReferenceCounters* pRefCounters, +CommandQueueVkImpl::CommandQueueVkImpl(IReferenceCounters* pRefCounters, std::shared_ptr LogicalDevice, uint32_t QueueFamilyIndex) : + // clang-format off TBase{pRefCounters}, m_LogicalDevice {LogicalDevice}, m_VkQueue {LogicalDevice->GetQueue(QueueFamilyIndex, 0)}, m_QueueFamilyIndex {QueueFamilyIndex}, m_NextFenceValue {1} +// clang-format on { } CommandQueueVkImpl::~CommandQueueVkImpl() { // Queues are created along with the logical device during vkCreateDevice. - // All queues associated with the logical device are destroyed when vkDestroyDevice + // All queues associated with the logical device are destroyed when vkDestroyDevice // is called on that device. } -IMPLEMENT_QUERY_INTERFACE( CommandQueueVkImpl, IID_CommandQueueVk, TBase ) +IMPLEMENT_QUERY_INTERFACE(CommandQueueVkImpl, IID_CommandQueueVk, TBase) Uint64 CommandQueueVkImpl::Submit(const VkSubmitInfo& SubmitInfo) @@ -58,13 +60,16 @@ Uint64 CommandQueueVkImpl::Submit(const VkSubmitInfo& SubmitInfo) Atomics::AtomicIncrement(m_NextFenceValue); auto vkFence = m_pFence->GetVkFence(); - uint32_t SubmitCount = - (SubmitInfo.waitSemaphoreCount != 0 || - SubmitInfo.commandBufferCount != 0 || - SubmitInfo.signalSemaphoreCount != 0) ? - 1 : 0; + + uint32_t SubmitCount = + (SubmitInfo.waitSemaphoreCount != 0 || + SubmitInfo.commandBufferCount != 0 || + SubmitInfo.signalSemaphoreCount != 0) ? + 1 : + 0; auto err = vkQueueSubmit(m_VkQueue, SubmitCount, &SubmitInfo, vkFence); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); (void)err; + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); + (void)err; // We must atomically place the (value, fence) pair into the deque m_pFence->AddPendingFence(std::move(vkFence), FenceValue); @@ -75,18 +80,19 @@ Uint64 CommandQueueVkImpl::Submit(const VkSubmitInfo& SubmitInfo) Uint64 CommandQueueVkImpl::Submit(VkCommandBuffer cmdBuffer) { VkSubmitInfo SubmitInfo = {}; - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; SubmitInfo.commandBufferCount = cmdBuffer != VK_NULL_HANDLE ? 1 : 0; - SubmitInfo.pCommandBuffers = &cmdBuffer; - SubmitInfo.waitSemaphoreCount = 0; // the number of semaphores upon which to wait before executing the command buffers - SubmitInfo.pWaitSemaphores = nullptr; // a pointer to an array of semaphores upon which to wait before the command - // buffers begin execution - SubmitInfo.pWaitDstStageMask = nullptr; // a pointer to an array of pipeline stages at which each corresponding - // semaphore wait will occur - SubmitInfo.signalSemaphoreCount = 0; // the number of semaphores to be signaled once the commands specified in - // pCommandBuffers have completed execution - SubmitInfo.pSignalSemaphores = nullptr; // a pointer to an array of semaphores which will be signaled when the - // command buffers for this batch have completed execution + SubmitInfo.pCommandBuffers = &cmdBuffer; + SubmitInfo.waitSemaphoreCount = 0; // the number of semaphores upon which to wait before executing the command buffers + SubmitInfo.pWaitSemaphores = nullptr; // a pointer to an array of semaphores upon which to wait before the command + // buffers begin execution + SubmitInfo.pWaitDstStageMask = nullptr; // a pointer to an array of pipeline stages at which each corresponding + // semaphore wait will occur + SubmitInfo.signalSemaphoreCount = 0; // the number of semaphores to be signaled once the commands specified in + // pCommandBuffers have completed execution + SubmitInfo.pSignalSemaphores = nullptr; // a pointer to an array of semaphores which will be signaled when the + // command buffers for this batch have completed execution return Submit(SubmitInfo); } @@ -115,8 +121,10 @@ Uint64 CommandQueueVkImpl::GetCompletedFenceValue() void CommandQueueVkImpl::SignalFence(VkFence vkFence) { std::lock_guard Lock{m_QueueMutex}; + auto err = vkQueueSubmit(m_VkQueue, 0, nullptr, vkFence); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); (void)err; + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to submit command buffer to the command queue"); + (void)err; } VkResult CommandQueueVkImpl::Present(const VkPresentInfoKHR& PresentInfo) @@ -125,4 +133,4 @@ VkResult CommandQueueVkImpl::Present(const VkPresentInfoKHR& PresentInfo) return vkQueuePresentKHR(m_VkQueue, &PresentInfo); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp index c094e384..b2bf3680 100644 --- a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp @@ -39,13 +39,14 @@ void DescriptorSetAllocation::Release() } } -VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPool(const char* DebugName)const +VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPool(const char* DebugName) const { VkDescriptorPoolCreateInfo PoolCI = {}; + PoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; PoolCI.pNext = nullptr; - // VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT specifies that descriptor sets can - // return their individual allocations to the pool, i.e. all of vkAllocateDescriptorSets, + // VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT specifies that descriptor sets can + // return their individual allocations to the pool, i.e. all of vkAllocateDescriptorSets, // vkFreeDescriptorSets, and vkResetDescriptorPool are allowed. (13.2.3) PoolCI.flags = m_AllowFreeing ? VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT : 0; PoolCI.maxSets = m_MaxSets; @@ -71,7 +72,7 @@ VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::GetPool(const char else { auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); - auto Pool = std::move(m_Pools.front()); + auto Pool = std::move(m_Pools.front()); VulkanUtilities::SetDescriptorPoolName(LogicalDevice.GetVkDevice(), Pool, DebugName); m_Pools.pop_front(); return Pool; @@ -83,26 +84,28 @@ void DescriptorPoolManager::DisposePool(VulkanUtilities::DescriptorPoolWrapper&& class DescriptorPoolDeleter { public: + // clang-format off DescriptorPoolDeleter(DescriptorPoolManager& _PoolMgr, VulkanUtilities::DescriptorPoolWrapper&& _Pool) noexcept : - PoolMgr (&_PoolMgr), - Pool (std::move(_Pool)) + PoolMgr {&_PoolMgr }, + Pool {std::move(_Pool)} {} - DescriptorPoolDeleter (const DescriptorPoolDeleter&) = delete; - DescriptorPoolDeleter& operator = (const DescriptorPoolDeleter&) = delete; - DescriptorPoolDeleter& operator = ( DescriptorPoolDeleter&&)= delete; + DescriptorPoolDeleter (const DescriptorPoolDeleter&) = delete; + DescriptorPoolDeleter& operator= (const DescriptorPoolDeleter&) = delete; + DescriptorPoolDeleter& operator= ( DescriptorPoolDeleter&&)= delete; DescriptorPoolDeleter(DescriptorPoolDeleter&& rhs)noexcept : - PoolMgr (rhs.PoolMgr), - Pool (std::move(rhs.Pool)) + PoolMgr {rhs.PoolMgr }, + Pool {std::move(rhs.Pool)} { rhs.PoolMgr = nullptr; } + // clang-format on ~DescriptorPoolDeleter() { - if (PoolMgr!=nullptr) + if (PoolMgr != nullptr) { PoolMgr->FreePool(std::move(Pool)); } @@ -133,12 +136,13 @@ static VkDescriptorSet AllocateDescriptorSet(const VulkanUtilities::VulkanLogica const char* DebugName) { VkDescriptorSetAllocateInfo DescrSetAllocInfo = {}; + DescrSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; DescrSetAllocInfo.pNext = nullptr; DescrSetAllocInfo.descriptorPool = Pool; DescrSetAllocInfo.descriptorSetCount = 1; DescrSetAllocInfo.pSetLayouts = &SetLayout; - // Descriptor pools are externally synchronized, meaning that the application must not allocate + // Descriptor pools are externally synchronized, meaning that the application must not allocate // and/or free descriptor sets from the same pool in multiple threads simultaneously (13.2.3) return LogicalDevice.AllocateVkDescriptorSet(DescrSetAllocInfo, DebugName); } @@ -151,16 +155,16 @@ DescriptorSetAllocator::~DescriptorSetAllocator() DescriptorSetAllocation DescriptorSetAllocator::Allocate(Uint64 CommandQueueMask, VkDescriptorSetLayout SetLayout, const char* DebugName) { - // Descriptor pools are externally synchronized, meaning that the application must not allocate + // Descriptor pools are externally synchronized, meaning that the application must not allocate // and/or free descriptor sets from the same pool in multiple threads simultaneously (13.2.3) std::lock_guard Lock{m_Mutex}; const auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); // Try all pools starting from the frontmost - for(auto it = m_Pools.begin(); it != m_Pools.end(); ++it) + for (auto it = m_Pools.begin(); it != m_Pools.end(); ++it) { auto& Pool = *it; - auto Set = AllocateDescriptorSet(LogicalDevice, Pool, SetLayout, DebugName); + auto Set = AllocateDescriptorSet(LogicalDevice, Pool, SetLayout, DebugName); if (Set != VK_NULL_HANDLE) { // Move the pool to the front @@ -181,14 +185,14 @@ DescriptorSetAllocation DescriptorSetAllocator::Allocate(Uint64 CommandQueueMask m_Pools.emplace_front(CreateDescriptorPool("Descriptor pool")); auto& NewPool = m_Pools.front(); - auto Set = AllocateDescriptorSet(LogicalDevice, NewPool, SetLayout, DebugName); + auto Set = AllocateDescriptorSet(LogicalDevice, NewPool, SetLayout, DebugName); DEV_CHECK_ERR(Set != VK_NULL_HANDLE, "Failed to allocate descriptor set"); #ifdef DEVELOPMENT ++m_AllocatedSetCounter; #endif - return {Set, NewPool, CommandQueueMask, *this }; + return {Set, NewPool, CommandQueueMask, *this}; } void DescriptorSetAllocator::FreeDescriptorSet(VkDescriptorSet Set, VkDescriptorPool Pool, Uint64 QueueMask) @@ -196,12 +200,13 @@ void DescriptorSetAllocator::FreeDescriptorSet(VkDescriptorSet Set, VkDescriptor class DescriptorSetDeleter { public: + // clang-format off DescriptorSetDeleter(DescriptorSetAllocator& _Allocator, VkDescriptorSet _Set, VkDescriptorPool _Pool) : - Allocator (&_Allocator), - Set (_Set), - Pool (_Pool) + Allocator {&_Allocator}, + Set {_Set }, + Pool {_Pool } {} DescriptorSetDeleter (const DescriptorSetDeleter&) = delete; @@ -209,18 +214,19 @@ void DescriptorSetAllocator::FreeDescriptorSet(VkDescriptorSet Set, VkDescriptor DescriptorSetDeleter& operator = ( DescriptorSetDeleter&&)= delete; DescriptorSetDeleter(DescriptorSetDeleter&& rhs)noexcept : - Allocator (rhs.Allocator), - Set (rhs.Set), - Pool (rhs.Pool) + Allocator {rhs.Allocator}, + Set {rhs.Set }, + Pool {rhs.Pool } { rhs.Allocator = nullptr; rhs.Set = nullptr; rhs.Pool = nullptr; } + // clang-format on ~DescriptorSetDeleter() { - if (Allocator!=nullptr) + if (Allocator != nullptr) { std::lock_guard Lock{Allocator->m_Mutex}; Allocator->m_DeviceVkImpl.GetLogicalDevice().FreeDescriptorSet(Pool, Set); @@ -241,8 +247,8 @@ void DescriptorSetAllocator::FreeDescriptorSet(VkDescriptorSet Set, VkDescriptor VkDescriptorSet DynamicDescriptorSetAllocator::Allocate(VkDescriptorSetLayout SetLayout, const char* DebugName) { - VkDescriptorSet set = VK_NULL_HANDLE; - const auto& LogicalDevice = m_GlobalPoolMgr.GetDeviceVkImpl().GetLogicalDevice(); + VkDescriptorSet set = VK_NULL_HANDLE; + const auto& LogicalDevice = m_GlobalPoolMgr.GetDeviceVkImpl().GetLogicalDevice(); if (!m_AllocatedPools.empty()) { set = AllocateDescriptorSet(LogicalDevice, m_AllocatedPools.back(), SetLayout, DebugName); @@ -253,13 +259,13 @@ VkDescriptorSet DynamicDescriptorSetAllocator::Allocate(VkDescriptorSetLayout Se m_AllocatedPools.emplace_back(m_GlobalPoolMgr.GetPool("Dynamic Descriptor Pool")); set = AllocateDescriptorSet(LogicalDevice, m_AllocatedPools.back(), SetLayout, DebugName); } - + return set; } void DynamicDescriptorSetAllocator::ReleasePools(Uint64 QueueMask) { - for(auto& Pool : m_AllocatedPools) + for (auto& Pool : m_AllocatedPools) { m_GlobalPoolMgr.DisposePool(std::move(Pool), QueueMask); } @@ -273,4 +279,4 @@ DynamicDescriptorSetAllocator::~DynamicDescriptorSetAllocator() LOG_INFO_MESSAGE(m_Name, " peak descriptor pool count: ", m_PeakPoolCount); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 7231ac5e..86a4bce1 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -36,2272 +36,2293 @@ namespace Diligent { - static std::string GetContextObjectName(const char* Object, bool bIsDeferred, Uint32 ContextId) - { - std::stringstream ss; - ss << Object; - if (bIsDeferred) - ss << " of deferred context #" << ContextId; - else - ss << " of immediate context"; - return ss.str(); - } - - DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDeviceVkImpl, - bool bIsDeferred, - const EngineVkCreateInfo& EngineCI, - Uint32 ContextId, - Uint32 CommandQueueId, - std::shared_ptr GenerateMipsHelper) : - TDeviceContextBase - { - pRefCounters, - pDeviceVkImpl, - ContextId, - CommandQueueId, - bIsDeferred ? std::numeric_limits::max() : EngineCI.NumCommandsToFlushCmdBuffer, - bIsDeferred - }, - m_CommandBuffer { pDeviceVkImpl->GetLogicalDevice().GetEnabledGraphicsShaderStages() }, - m_CmdListAllocator { GetRawAllocator(), sizeof(CommandListVkImpl), 64 }, - // Command pools must be thread safe because command buffers are returned into pools by release queues - // potentially running in another thread - m_CmdPool - { - pDeviceVkImpl->GetLogicalDevice().GetSharedPtr(), - pDeviceVkImpl->GetCommandQueue(CommandQueueId).GetQueueFamilyIndex(), - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT - }, - // Upload heap must always be thread-safe as Finish() may be called from another thread - m_UploadHeap - { - *pDeviceVkImpl, - GetContextObjectName("Upload heap", bIsDeferred, ContextId), - EngineCI.UploadHeapPageSize - }, - m_DynamicHeap - { - pDeviceVkImpl->GetDynamicMemoryManager(), - GetContextObjectName("Dynamic heap", bIsDeferred, ContextId), - EngineCI.DynamicHeapPageSize - }, - m_DynamicDescrSetAllocator - { - pDeviceVkImpl->GetDynamicDescriptorPool(), - GetContextObjectName("Dynamic descriptor set allocator", bIsDeferred, ContextId), - }, - m_GenerateMipsHelper{std::move(GenerateMipsHelper)} - { - m_GenerateMipsHelper->CreateSRB(&m_GenerateMipsSRB); - BufferDesc DummyVBDesc; - DummyVBDesc.Name = "Dummy vertex buffer"; - DummyVBDesc.BindFlags = BIND_VERTEX_BUFFER; - DummyVBDesc.Usage = USAGE_DEFAULT; - DummyVBDesc.uiSizeInBytes = 32; - RefCntAutoPtr pDummyVB; - m_pDevice->CreateBuffer(DummyVBDesc, nullptr, &pDummyVB); - m_DummyVB = pDummyVB.RawPtr(); - } +static std::string GetContextObjectName(const char* Object, bool bIsDeferred, Uint32 ContextId) +{ + std::stringstream ss; + ss << Object; + if (bIsDeferred) + ss << " of deferred context #" << ContextId; + else + ss << " of immediate context"; + return ss.str(); +} + +DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVkImpl, + bool bIsDeferred, + const EngineVkCreateInfo& EngineCI, + Uint32 ContextId, + Uint32 CommandQueueId, + std::shared_ptr GenerateMipsHelper) : + // clang-format off + TDeviceContextBase + { + pRefCounters, + pDeviceVkImpl, + ContextId, + CommandQueueId, + bIsDeferred ? std::numeric_limits::max() : EngineCI.NumCommandsToFlushCmdBuffer, + bIsDeferred + }, + m_CommandBuffer { pDeviceVkImpl->GetLogicalDevice().GetEnabledGraphicsShaderStages() }, + m_CmdListAllocator { GetRawAllocator(), sizeof(CommandListVkImpl), 64 }, + // Command pools must be thread safe because command buffers are returned into pools by release queues + // potentially running in another thread + m_CmdPool + { + pDeviceVkImpl->GetLogicalDevice().GetSharedPtr(), + pDeviceVkImpl->GetCommandQueue(CommandQueueId).GetQueueFamilyIndex(), + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT + }, + // Upload heap must always be thread-safe as Finish() may be called from another thread + m_UploadHeap + { + *pDeviceVkImpl, + GetContextObjectName("Upload heap", bIsDeferred, ContextId), + EngineCI.UploadHeapPageSize + }, + m_DynamicHeap + { + pDeviceVkImpl->GetDynamicMemoryManager(), + GetContextObjectName("Dynamic heap", bIsDeferred, ContextId), + EngineCI.DynamicHeapPageSize + }, + m_DynamicDescrSetAllocator + { + pDeviceVkImpl->GetDynamicDescriptorPool(), + GetContextObjectName("Dynamic descriptor set allocator", bIsDeferred, ContextId), + }, + m_GenerateMipsHelper{std::move(GenerateMipsHelper)} +// clang-format on +{ + m_GenerateMipsHelper->CreateSRB(&m_GenerateMipsSRB); + + BufferDesc DummyVBDesc; + DummyVBDesc.Name = "Dummy vertex buffer"; + DummyVBDesc.BindFlags = BIND_VERTEX_BUFFER; + DummyVBDesc.Usage = USAGE_DEFAULT; + DummyVBDesc.uiSizeInBytes = 32; + RefCntAutoPtr pDummyVB; + m_pDevice->CreateBuffer(DummyVBDesc, nullptr, &pDummyVB); + m_DummyVB = pDummyVB.RawPtr(); +} - DeviceContextVkImpl::~DeviceContextVkImpl() +DeviceContextVkImpl::~DeviceContextVkImpl() +{ + if (m_State.NumCommands != 0) { - if (m_State.NumCommands != 0) + if (m_bIsDeferred) { - if (m_bIsDeferred) - { - LOG_ERROR_MESSAGE("There are outstanding commands in deferred context #", m_ContextId, " being destroyed, which indicates that FinishCommandList() has not been called." - " This may cause synchronization issues."); - } - else - { - LOG_ERROR_MESSAGE("There are outstanding commands in the immediate context being destroyed, which indicates the context has not been Flush()'ed.", - " This may cause synchronization issues."); - } + LOG_ERROR_MESSAGE("There are outstanding commands in deferred context #", m_ContextId, + " being destroyed, which indicates that FinishCommandList() has not been called." + " This may cause synchronization issues."); } - - if (!m_bIsDeferred) + else { - Flush(); + LOG_ERROR_MESSAGE("There are outstanding commands in the immediate context being destroyed, " + "which indicates the context has not been Flush()'ed.", + " This may cause synchronization issues."); } + } + + if (!m_bIsDeferred) + { + Flush(); + } - // For deferred contexts, m_SubmittedBuffersCmdQueueMask is reset to 0 after every call to FinishFrame(). - // In this case there are no resources to release, so there will be no issues. - FinishFrame(); + // For deferred contexts, m_SubmittedBuffersCmdQueueMask is reset to 0 after every call to FinishFrame(). + // In this case there are no resources to release, so there will be no issues. + FinishFrame(); - // There must be no stale resources - DEV_CHECK_ERR(m_UploadHeap.GetStalePagesCount() == 0, "All allocated upload heap pages must have been released at this point"); - DEV_CHECK_ERR(m_DynamicHeap.GetAllocatedMasterBlockCount() == 0, "All allocated dynamic heap master blocks must have been released"); - DEV_CHECK_ERR(m_DynamicDescrSetAllocator.GetAllocatedPoolCount() == 0, "All allocated dynamic descriptor set pools must have been released at this point"); + // There must be no stale resources + // clang-format off + DEV_CHECK_ERR(m_UploadHeap.GetStalePagesCount() == 0, "All allocated upload heap pages must have been released at this point"); + DEV_CHECK_ERR(m_DynamicHeap.GetAllocatedMasterBlockCount() == 0, "All allocated dynamic heap master blocks must have been released"); + DEV_CHECK_ERR(m_DynamicDescrSetAllocator.GetAllocatedPoolCount() == 0, "All allocated dynamic descriptor set pools must have been released at this point"); + // clang-format on - auto VkCmdPool = m_CmdPool.Release(); - m_pDevice->SafeReleaseDeviceObject(std::move(VkCmdPool), ~Uint64{0}); - - m_pDevice->SafeReleaseDeviceObject(std::move(m_GenerateMipsHelper), ~Uint64{0}); - m_pDevice->SafeReleaseDeviceObject(std::move(m_GenerateMipsSRB), ~Uint64{0}); - m_pDevice->SafeReleaseDeviceObject(std::move(m_DummyVB), ~Uint64{0}); + auto VkCmdPool = m_CmdPool.Release(); + m_pDevice->SafeReleaseDeviceObject(std::move(VkCmdPool), ~Uint64{0}); - // The main reason we need to idle the GPU is because we need to make sure that all command buffers are returned to the - // pool. Upload heap, dynamic heap and dynamic descriptor manager return their resources to global managers and - // do not really need to wait for GPU to idle. - m_pDevice->IdleGPU(); - DEV_CHECK_ERR(m_CmdPool.DvpGetBufferCounter() == 0, "All command buffers must have been returned to the pool"); - } + // clang-format off + m_pDevice->SafeReleaseDeviceObject(std::move(m_GenerateMipsHelper), ~Uint64{0}); + m_pDevice->SafeReleaseDeviceObject(std::move(m_GenerateMipsSRB), ~Uint64{0}); + m_pDevice->SafeReleaseDeviceObject(std::move(m_DummyVB), ~Uint64{0}); + // clang-format on + + // The main reason we need to idle the GPU is because we need to make sure that all command buffers are returned to the + // pool. Upload heap, dynamic heap and dynamic descriptor manager return their resources to global managers and + // do not really need to wait for GPU to idle. + m_pDevice->IdleGPU(); + DEV_CHECK_ERR(m_CmdPool.DvpGetBufferCounter() == 0, "All command buffers must have been returned to the pool"); +} - IMPLEMENT_QUERY_INTERFACE( DeviceContextVkImpl, IID_DeviceContextVk, TDeviceContextBase ) +IMPLEMENT_QUERY_INTERFACE(DeviceContextVkImpl, IID_DeviceContextVk, TDeviceContextBase) - void DeviceContextVkImpl::DisposeVkCmdBuffer(Uint32 CmdQueue, VkCommandBuffer vkCmdBuff, Uint64 FenceValue) +void DeviceContextVkImpl::DisposeVkCmdBuffer(Uint32 CmdQueue, VkCommandBuffer vkCmdBuff, Uint64 FenceValue) +{ + VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); + class CmdBufferDeleter { - VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); - class CmdBufferDeleter + public: + // clang-format off + CmdBufferDeleter(VkCommandBuffer _vkCmdBuff, + VulkanUtilities::VulkanCommandBufferPool& _Pool) noexcept : + vkCmdBuff {_vkCmdBuff}, + Pool {&_Pool } { - public: - CmdBufferDeleter(VkCommandBuffer _vkCmdBuff, - VulkanUtilities::VulkanCommandBufferPool& _Pool) noexcept : - vkCmdBuff (_vkCmdBuff), - Pool (&_Pool) - { - VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); - } + VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); + } - CmdBufferDeleter (const CmdBufferDeleter&) = delete; - CmdBufferDeleter& operator = (const CmdBufferDeleter&) = delete; - CmdBufferDeleter& operator = ( CmdBufferDeleter&&) = delete; + CmdBufferDeleter (const CmdBufferDeleter&) = delete; + CmdBufferDeleter& operator = (const CmdBufferDeleter&) = delete; + CmdBufferDeleter& operator = ( CmdBufferDeleter&&) = delete; - CmdBufferDeleter(CmdBufferDeleter&& rhs) noexcept : - vkCmdBuff (rhs.vkCmdBuff), - Pool (rhs.Pool) - { - rhs.vkCmdBuff = VK_NULL_HANDLE; - rhs.Pool = nullptr; - } + CmdBufferDeleter(CmdBufferDeleter&& rhs) noexcept : + vkCmdBuff {rhs.vkCmdBuff}, + Pool {rhs.Pool } + { + rhs.vkCmdBuff = VK_NULL_HANDLE; + rhs.Pool = nullptr; + } + // clang-format on - ~CmdBufferDeleter() + ~CmdBufferDeleter() + { + if (Pool != nullptr) { - if(Pool != nullptr) - { - Pool->FreeCommandBuffer(std::move(vkCmdBuff)); - } + Pool->FreeCommandBuffer(std::move(vkCmdBuff)); } + } - private: - VkCommandBuffer vkCmdBuff; - VulkanUtilities::VulkanCommandBufferPool* Pool; - }; + private: + VkCommandBuffer vkCmdBuff; + VulkanUtilities::VulkanCommandBufferPool* Pool; + }; - auto& ReleaseQueue = m_pDevice->GetReleaseQueue(CmdQueue); - ReleaseQueue.DiscardResource(CmdBufferDeleter{vkCmdBuff, m_CmdPool}, FenceValue); - } + auto& ReleaseQueue = m_pDevice->GetReleaseQueue(CmdQueue); + ReleaseQueue.DiscardResource(CmdBufferDeleter{vkCmdBuff, m_CmdPool}, FenceValue); +} - inline void DeviceContextVkImpl::DisposeCurrentCmdBuffer(Uint32 CmdQueue, Uint64 FenceValue) +inline void DeviceContextVkImpl::DisposeCurrentCmdBuffer(Uint32 CmdQueue, Uint64 FenceValue) +{ + VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Disposing command buffer with unifinished render pass"); + auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); + if (vkCmdBuff != VK_NULL_HANDLE) { - VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Disposing command buffer with unifinished render pass"); - auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); - if (vkCmdBuff != VK_NULL_HANDLE) - { - DisposeVkCmdBuffer(CmdQueue, vkCmdBuff, FenceValue); - m_CommandBuffer.Reset(); - } + DisposeVkCmdBuffer(CmdQueue, vkCmdBuff, FenceValue); + m_CommandBuffer.Reset(); } +} - void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) +void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) +{ + auto* pPipelineStateVk = ValidatedCast(pPipelineState); + if (PipelineStateVkImpl::IsSameObject(m_pPipelineState, pPipelineStateVk)) + return; + + // Never flush deferred context! + if (!m_bIsDeferred && m_State.NumCommands >= m_NumCommandsToFlush) { - auto* pPipelineStateVk = ValidatedCast(pPipelineState); - if (PipelineStateVkImpl::IsSameObject(m_pPipelineState, pPipelineStateVk)) - return; + Flush(); + } - // Never flush deferred context! - if (!m_bIsDeferred && m_State.NumCommands >= m_NumCommandsToFlush) - { - Flush(); - } + const auto& PSODesc = pPipelineStateVk->GetDesc(); - 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 was disabled in previous pipeline + CommitScissor = !OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable; + } - 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 was disabled in previous pipeline - CommitScissor = !OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable; - } + TDeviceContextBase::SetPipelineState(pPipelineStateVk, 0 /*Dummy*/); + EnsureVkCmdBuffer(); - TDeviceContextBase::SetPipelineState( pPipelineStateVk, 0 /*Dummy*/ ); - EnsureVkCmdBuffer(); + if (PSODesc.IsComputePipeline) + { + auto vkPipeline = pPipelineStateVk->GetVkPipeline(); + m_CommandBuffer.BindComputePipeline(vkPipeline); + } + else + { + auto vkPipeline = pPipelineStateVk->GetVkPipeline(); + m_CommandBuffer.BindGraphicsPipeline(vkPipeline); - if (PSODesc.IsComputePipeline) + if (CommitStates) { - auto vkPipeline = pPipelineStateVk->GetVkPipeline(); - m_CommandBuffer.BindComputePipeline(vkPipeline); + m_CommandBuffer.SetStencilReference(m_StencilRef); + m_CommandBuffer.SetBlendConstants(m_BlendFactors); + CommitRenderPassAndFramebuffer(true); + CommitViewports(); } - else - { - auto vkPipeline = pPipelineStateVk->GetVkPipeline(); - m_CommandBuffer.BindGraphicsPipeline(vkPipeline); - - if (CommitStates) - { - m_CommandBuffer.SetStencilReference(m_StencilRef); - m_CommandBuffer.SetBlendConstants(m_BlendFactors); - CommitRenderPassAndFramebuffer(true); - CommitViewports(); - } - if (PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable && (CommitStates || CommitScissor)) - { - CommitScissorRects(); - } + if (PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable && (CommitStates || CommitScissor)) + { + CommitScissorRects(); } - - m_DescrSetBindInfo.Reset(); } - void DeviceContextVkImpl::TransitionShaderResources(IPipelineState *pPipelineState, IShaderResourceBinding *pShaderResourceBinding) - { - VERIFY_EXPR(pPipelineState != nullptr); + m_DescrSetBindInfo.Reset(); +} - auto *pPipelineStateVk = ValidatedCast(pPipelineState); - pPipelineStateVk->CommitAndTransitionShaderResources(pShaderResourceBinding, this, false, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, nullptr); - } +void DeviceContextVkImpl::TransitionShaderResources(IPipelineState* pPipelineState, IShaderResourceBinding* pShaderResourceBinding) +{ + VERIFY_EXPR(pPipelineState != nullptr); - void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding *pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) - { - if (!DeviceContextBase::CommitShaderResources(pShaderResourceBinding, StateTransitionMode, 0 /*Dummy*/)) - return; + auto* pPipelineStateVk = ValidatedCast(pPipelineState); + pPipelineStateVk->CommitAndTransitionShaderResources(pShaderResourceBinding, this, false, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, nullptr); +} - m_pPipelineState->CommitAndTransitionShaderResources(pShaderResourceBinding, this, true, StateTransitionMode, &m_DescrSetBindInfo); - } +void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + if (!DeviceContextBase::CommitShaderResources(pShaderResourceBinding, StateTransitionMode, 0 /*Dummy*/)) + return; + + m_pPipelineState->CommitAndTransitionShaderResources(pShaderResourceBinding, this, true, StateTransitionMode, &m_DescrSetBindInfo); +} - void DeviceContextVkImpl::SetStencilRef(Uint32 StencilRef) +void DeviceContextVkImpl::SetStencilRef(Uint32 StencilRef) +{ + if (TDeviceContextBase::SetStencilRef(StencilRef, 0)) { - if (TDeviceContextBase::SetStencilRef(StencilRef, 0)) - { - EnsureVkCmdBuffer(); - m_CommandBuffer.SetStencilReference(m_StencilRef); - } + EnsureVkCmdBuffer(); + m_CommandBuffer.SetStencilReference(m_StencilRef); } +} - void DeviceContextVkImpl::SetBlendFactors(const float* pBlendFactors) +void DeviceContextVkImpl::SetBlendFactors(const float* pBlendFactors) +{ + if (TDeviceContextBase::SetBlendFactors(pBlendFactors, 0)) { - if (TDeviceContextBase::SetBlendFactors(pBlendFactors, 0)) - { - EnsureVkCmdBuffer(); - m_CommandBuffer.SetBlendConstants(m_BlendFactors); - } + EnsureVkCmdBuffer(); + m_CommandBuffer.SetBlendConstants(m_BlendFactors); } +} - void DeviceContextVkImpl::CommitVkVertexBuffers() - { +void DeviceContextVkImpl::CommitVkVertexBuffers() +{ #ifdef DEVELOPMENT - if (m_NumVertexStreams < m_pPipelineState->GetNumBufferSlotsUsed()) - LOG_ERROR("Currently bound pipeline state '", m_pPipelineState->GetDesc().Name, "' expects ", m_pPipelineState->GetNumBufferSlotsUsed(), " input buffer slots, but only ", m_NumVertexStreams, " is bound"); + if (m_NumVertexStreams < m_pPipelineState->GetNumBufferSlotsUsed()) + LOG_ERROR("Currently bound pipeline state '", m_pPipelineState->GetDesc().Name, "' expects ", m_pPipelineState->GetNumBufferSlotsUsed(), " input buffer slots, but only ", m_NumVertexStreams, " is bound"); #endif - // Do not initialize array with zeros for performance reasons - VkBuffer vkVertexBuffers[MaxBufferSlots];// = {} - VkDeviceSize Offsets[MaxBufferSlots]; - VERIFY( m_NumVertexStreams <= MaxBufferSlots, "Too many buffers are being set" ); - bool DynamicBufferPresent = false; - for ( Uint32 slot = 0; slot < m_NumVertexStreams; ++slot ) + // Do not initialize array with zeros for performance reasons + VkBuffer vkVertexBuffers[MaxBufferSlots]; // = {} + VkDeviceSize Offsets[MaxBufferSlots]; + VERIFY(m_NumVertexStreams <= MaxBufferSlots, "Too many buffers are being set"); + bool DynamicBufferPresent = false; + for (Uint32 slot = 0; slot < m_NumVertexStreams; ++slot) + { + auto& CurrStream = m_VertexStreams[slot]; + if (auto* pBufferVk = CurrStream.pBuffer.RawPtr()) { - auto& CurrStream = m_VertexStreams[slot]; - if (auto* pBufferVk = CurrStream.pBuffer.RawPtr()) + if (pBufferVk->GetDesc().Usage == USAGE_DYNAMIC) { - if (pBufferVk->GetDesc().Usage == USAGE_DYNAMIC) - { - DynamicBufferPresent = true; + DynamicBufferPresent = true; #ifdef DEVELOPMENT - pBufferVk->DvpVerifyDynamicAllocation(this); + pBufferVk->DvpVerifyDynamicAllocation(this); #endif - } + } - // Device context keeps strong references to all vertex buffers. + // Device context keeps strong references to all vertex buffers. - vkVertexBuffers[slot] = pBufferVk->GetVkBuffer(); - Offsets[slot] = CurrStream.Offset + pBufferVk->GetDynamicOffset(m_ContextId, this); - } - else - { - // We can't bind null vertex buffer in Vulkan and have to use a dummy one - vkVertexBuffers[slot] = m_DummyVB->GetVkBuffer(); - Offsets[slot] = 0; - } + vkVertexBuffers[slot] = pBufferVk->GetVkBuffer(); + Offsets[slot] = CurrStream.Offset + pBufferVk->GetDynamicOffset(m_ContextId, this); } + else + { + // We can't bind null vertex buffer in Vulkan and have to use a dummy one + vkVertexBuffers[slot] = m_DummyVB->GetVkBuffer(); + Offsets[slot] = 0; + } + } - //GraphCtx.FlushResourceBarriers(); - if (m_NumVertexStreams > 0) - m_CommandBuffer.BindVertexBuffers( 0, m_NumVertexStreams, vkVertexBuffers, Offsets ); + //GraphCtx.FlushResourceBarriers(); + if (m_NumVertexStreams > 0) + m_CommandBuffer.BindVertexBuffers(0, m_NumVertexStreams, vkVertexBuffers, Offsets); - // GPU offset for a dynamic vertex buffer can change every time a draw command is invoked - m_State.CommittedVBsUpToDate = !DynamicBufferPresent; - } + // GPU offset for a dynamic vertex buffer can change every time a draw command is invoked + m_State.CommittedVBsUpToDate = !DynamicBufferPresent; +} - void DeviceContextVkImpl::DvpLogRenderPass_PSOMismatch() - { - std::stringstream ss; - ss << "Active render pass is incomaptible with PSO '" << m_pPipelineState->GetDesc().Name << "'. " - "This indicates the mismatch between the number and/or format of bound render targets and/or depth stencil buffer " - "and the PSO. Vulkand requires exact match.\n" - " Bound render targets (" << m_NumBoundRenderTargets << "):"; - Uint32 SampleCount = 0; - for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) - { - ss << ' '; - if (auto* pRTV = m_pBoundRenderTargets[rt].RawPtr()) - { - VERIFY_EXPR(SampleCount == 0 || SampleCount == pRTV->GetTexture()->GetDesc().SampleCount); - SampleCount = pRTV->GetTexture()->GetDesc().SampleCount; - ss << GetTextureFormatAttribs(pRTV->GetDesc().Format).Name; - } - else - ss << ""; - } - ss << "; DSV: "; - if (m_pBoundDepthStencil) - { - VERIFY_EXPR(SampleCount == 0 || SampleCount == m_pBoundDepthStencil->GetTexture()->GetDesc().SampleCount); - SampleCount = m_pBoundDepthStencil->GetTexture()->GetDesc().SampleCount; - ss << GetTextureFormatAttribs(m_pBoundDepthStencil->GetDesc().Format).Name; +void DeviceContextVkImpl::DvpLogRenderPass_PSOMismatch() +{ + std::stringstream ss; + ss << "Active render pass is incomaptible with PSO '" << m_pPipelineState->GetDesc().Name + << "'. This indicates the mismatch between the number and/or format of bound render " + "targets and/or depth stencil buffer and the PSO. Vulkand requires exact match.\n" + " Bound render targets (" + << m_NumBoundRenderTargets << "):"; + Uint32 SampleCount = 0; + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) + { + ss << ' '; + if (auto* pRTV = m_pBoundRenderTargets[rt].RawPtr()) + { + VERIFY_EXPR(SampleCount == 0 || SampleCount == pRTV->GetTexture()->GetDesc().SampleCount); + SampleCount = pRTV->GetTexture()->GetDesc().SampleCount; + ss << GetTextureFormatAttribs(pRTV->GetDesc().Format).Name; } else ss << ""; - ss << "; Sample count: " << SampleCount; + } + ss << "; DSV: "; + if (m_pBoundDepthStencil) + { + VERIFY_EXPR(SampleCount == 0 || SampleCount == m_pBoundDepthStencil->GetTexture()->GetDesc().SampleCount); + SampleCount = m_pBoundDepthStencil->GetTexture()->GetDesc().SampleCount; + ss << GetTextureFormatAttribs(m_pBoundDepthStencil->GetDesc().Format).Name; + } + else + ss << ""; + ss << "; Sample count: " << SampleCount; - const auto& GrPipeline = m_pPipelineState->GetDesc().GraphicsPipeline; - ss << "\n PSO: render targets (" << Uint32{GrPipeline.NumRenderTargets} << "): "; - for (Uint32 rt = 0; rt < GrPipeline.NumRenderTargets; ++rt) - ss << ' ' << GetTextureFormatAttribs(GrPipeline.RTVFormats[rt]).Name; - ss << "; DSV: " << GetTextureFormatAttribs(GrPipeline.DSVFormat).Name; - ss << "; Sample count: " << Uint32{GrPipeline.SmplDesc.Count}; + const auto& GrPipeline = m_pPipelineState->GetDesc().GraphicsPipeline; + ss << "\n PSO: render targets (" << Uint32{GrPipeline.NumRenderTargets} << "): "; + for (Uint32 rt = 0; rt < GrPipeline.NumRenderTargets; ++rt) + ss << ' ' << GetTextureFormatAttribs(GrPipeline.RTVFormats[rt]).Name; + ss << "; DSV: " << GetTextureFormatAttribs(GrPipeline.DSVFormat).Name; + ss << "; Sample count: " << Uint32{GrPipeline.SmplDesc.Count}; - LOG_ERROR_MESSAGE(ss.str()); - } + LOG_ERROR_MESSAGE(ss.str()); +} - void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) - { +void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) +{ #ifdef DEVELOPMENT - if ((Flags & DRAW_FLAG_VERIFY_RENDER_TARGETS) != 0) - DvpVerifyRenderTargets(); + if ((Flags & DRAW_FLAG_VERIFY_RENDER_TARGETS) != 0) + DvpVerifyRenderTargets(); #endif - EnsureVkCmdBuffer(); + EnsureVkCmdBuffer(); - if (!m_State.CommittedVBsUpToDate && m_pPipelineState->GetNumBufferSlotsUsed() > 0) - { - CommitVkVertexBuffers(); - } + if (!m_State.CommittedVBsUpToDate && m_pPipelineState->GetNumBufferSlotsUsed() > 0) + { + CommitVkVertexBuffers(); + } #ifdef DEVELOPMENT - if ((Flags & DRAW_FLAG_VERIFY_STATES) != 0) + if ((Flags & DRAW_FLAG_VERIFY_STATES) != 0) + { + for (Uint32 slot = 0; slot < m_NumVertexStreams; ++slot) { - for (Uint32 slot = 0; slot < m_NumVertexStreams; ++slot ) + if (auto* pBufferVk = m_VertexStreams[slot].pBuffer.RawPtr()) { - if (auto* pBufferVk = m_VertexStreams[slot].pBuffer.RawPtr()) - { - DvpVerifyBufferState(*pBufferVk, RESOURCE_STATE_VERTEX_BUFFER, "Using vertex buffers (DeviceContextVkImpl::Draw)"); - } + DvpVerifyBufferState(*pBufferVk, RESOURCE_STATE_VERTEX_BUFFER, "Using vertex buffers (DeviceContextVkImpl::Draw)"); } } + } #endif - if (m_DescrSetBindInfo.DynamicOffsetCount != 0) + if (m_DescrSetBindInfo.DynamicOffsetCount != 0) + { + // First time we must always bind descriptor sets with dynamic offsets. + // If there are no dynamic buffers bound in the resource cache, for all subsequent + // cals we do not need to bind the sets again. + if (!m_DescrSetBindInfo.DynamicDescriptorsBound || + (m_DescrSetBindInfo.DynamicBuffersPresent && (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0)) { - // First time we must always bind descriptor sets with dynamic offsets. - // If there are no dynamic buffers bound in the resource cache, for all subsequent - // cals we do not need to bind the sets again. - if (!m_DescrSetBindInfo.DynamicDescriptorsBound || - (m_DescrSetBindInfo.DynamicBuffersPresent && (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0)) - { - m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo); - } + m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo); } + } #if 0 -#ifdef _DEBUG - else - { - if ( m_pPipelineState->dbgContainsShaderResources() ) - LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called" ); - } -#endif +# ifdef _DEBUG + else + { + if ( m_pPipelineState->dbgContainsShaderResources() ) + LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called" ); + } +# endif #endif #ifdef DEVELOPMENT - if (m_pPipelineState->GetVkRenderPass() != m_RenderPass) - { - DvpLogRenderPass_PSOMismatch(); - } + if (m_pPipelineState->GetVkRenderPass() != m_RenderPass) + { + DvpLogRenderPass_PSOMismatch(); + } #endif - CommitRenderPassAndFramebuffer((Flags & DRAW_FLAG_VERIFY_STATES) != 0); - } + CommitRenderPassAndFramebuffer((Flags & DRAW_FLAG_VERIFY_STATES) != 0); +} - BufferVkImpl* DeviceContextVkImpl::PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode) - { - DEV_CHECK_ERR(pAttribsBuffer, "Indirect draw attribs buffer must not be null"); - auto* pIndirectDrawAttribsVk = ValidatedCast(pAttribsBuffer); +BufferVkImpl* DeviceContextVkImpl::PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode) +{ + DEV_CHECK_ERR(pAttribsBuffer, "Indirect draw attribs buffer must not be null"); + auto* pIndirectDrawAttribsVk = ValidatedCast(pAttribsBuffer); #ifdef DEVELOPMENT - if (pIndirectDrawAttribsVk->GetDesc().Usage == USAGE_DYNAMIC) - pIndirectDrawAttribsVk->DvpVerifyDynamicAllocation(this); + if (pIndirectDrawAttribsVk->GetDesc().Usage == USAGE_DYNAMIC) + pIndirectDrawAttribsVk->DvpVerifyDynamicAllocation(this); #endif - // Buffer memory barries must be executed outside of render pass - TransitionOrVerifyBufferState(*pIndirectDrawAttribsVk, TransitonMode, RESOURCE_STATE_INDIRECT_ARGUMENT, - VK_ACCESS_INDIRECT_COMMAND_READ_BIT, "Indirect draw (DeviceContextVkImpl::Draw)"); - return pIndirectDrawAttribsVk; - } + // Buffer memory barries must be executed outside of render pass + TransitionOrVerifyBufferState(*pIndirectDrawAttribsVk, TransitonMode, RESOURCE_STATE_INDIRECT_ARGUMENT, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT, "Indirect draw (DeviceContextVkImpl::Draw)"); + return pIndirectDrawAttribsVk; +} - void DeviceContextVkImpl::PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE IndexType) - { - PrepareForDraw(Flags); +void DeviceContextVkImpl::PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE IndexType) +{ + PrepareForDraw(Flags); #ifdef DEVELOPMENT - if ((Flags & DRAW_FLAG_VERIFY_STATES) != 0) - { - DvpVerifyBufferState(*m_pIndexBuffer, RESOURCE_STATE_INDEX_BUFFER, "Indexed draw call (DeviceContextVkImpl::Draw)"); - } -#endif - DEV_CHECK_ERR(IndexType == VT_UINT16 || IndexType == VT_UINT32, "Unsupported index format. Only R16_UINT and R32_UINT are allowed."); - VkIndexType vkIndexType = IndexType == VT_UINT16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; - m_CommandBuffer.BindIndexBuffer(m_pIndexBuffer->GetVkBuffer(), m_IndexDataStartOffset + m_pIndexBuffer->GetDynamicOffset(m_ContextId, this), vkIndexType); + if ((Flags & DRAW_FLAG_VERIFY_STATES) != 0) + { + DvpVerifyBufferState(*m_pIndexBuffer, RESOURCE_STATE_INDEX_BUFFER, "Indexed draw call (DeviceContextVkImpl::Draw)"); } +#endif + DEV_CHECK_ERR(IndexType == VT_UINT16 || IndexType == VT_UINT32, "Unsupported index format. Only R16_UINT and R32_UINT are allowed."); + VkIndexType vkIndexType = IndexType == VT_UINT16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; + m_CommandBuffer.BindIndexBuffer(m_pIndexBuffer->GetVkBuffer(), m_IndexDataStartOffset + m_pIndexBuffer->GetDynamicOffset(m_ContextId, this), vkIndexType); +} - void DeviceContextVkImpl::Draw(const DrawAttribs& Attribs) - { - if (!DvpVerifyDrawArguments(Attribs)) - return; +void DeviceContextVkImpl::Draw(const DrawAttribs& Attribs) +{ + if (!DvpVerifyDrawArguments(Attribs)) + return; - PrepareForDraw(Attribs.Flags); + PrepareForDraw(Attribs.Flags); - m_CommandBuffer.Draw(Attribs.NumVertices, Attribs.NumInstances, Attribs.StartVertexLocation, Attribs.FirstInstanceLocation ); - ++m_State.NumCommands; - } + m_CommandBuffer.Draw(Attribs.NumVertices, Attribs.NumInstances, Attribs.StartVertexLocation, Attribs.FirstInstanceLocation); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::DrawIndexed(const DrawIndexedAttribs& Attribs) - { - if (!DvpVerifyDrawIndexedArguments(Attribs)) - return; +void DeviceContextVkImpl::DrawIndexed(const DrawIndexedAttribs& Attribs) +{ + if (!DvpVerifyDrawIndexedArguments(Attribs)) + return; - PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); + PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); - m_CommandBuffer.DrawIndexed(Attribs.NumIndices, Attribs.NumInstances, Attribs.FirstIndexLocation, Attribs.BaseVertex, Attribs.FirstInstanceLocation); - ++m_State.NumCommands; - } + m_CommandBuffer.DrawIndexed(Attribs.NumIndices, Attribs.NumInstances, Attribs.FirstIndexLocation, Attribs.BaseVertex, Attribs.FirstInstanceLocation); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::DrawIndirect(const DrawIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) - { - if (!DvpVerifyDrawIndirectArguments(Attribs, pAttribsBuffer)) - return; +void DeviceContextVkImpl::DrawIndirect(const DrawIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + if (!DvpVerifyDrawIndirectArguments(Attribs, pAttribsBuffer)) + return; - // We must prepare indirect draw attribs buffer first because state transitions must - // be performed outside of render pass, and PrepareForDraw commits render pass - BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); + // We must prepare indirect draw attribs buffer first because state transitions must + // be performed outside of render pass, and PrepareForDraw commits render pass + BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); - PrepareForDraw(Attribs.Flags); + PrepareForDraw(Attribs.Flags); - m_CommandBuffer.DrawIndirect(pIndirectDrawAttribsVk->GetVkBuffer(), pIndirectDrawAttribsVk->GetDynamicOffset(m_ContextId, this) + Attribs.IndirectDrawArgsOffset, 1, 0); - ++m_State.NumCommands; - } + m_CommandBuffer.DrawIndirect(pIndirectDrawAttribsVk->GetVkBuffer(), pIndirectDrawAttribsVk->GetDynamicOffset(m_ContextId, this) + Attribs.IndirectDrawArgsOffset, 1, 0); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) - { - if (!DvpVerifyDrawIndexedIndirectArguments(Attribs, pAttribsBuffer)) - return; +void DeviceContextVkImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + if (!DvpVerifyDrawIndexedIndirectArguments(Attribs, pAttribsBuffer)) + return; - // We must prepare indirect draw attribs buffer first because state transitions must - // be performed outside of render pass, and PrepareForDraw commits render pass - BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); + // We must prepare indirect draw attribs buffer first because state transitions must + // be performed outside of render pass, and PrepareForDraw commits render pass + BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); - PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); + PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); - m_CommandBuffer.DrawIndexedIndirect(pIndirectDrawAttribsVk->GetVkBuffer(), pIndirectDrawAttribsVk->GetDynamicOffset(m_ContextId, this) + Attribs.IndirectDrawArgsOffset, 1, 0); - ++m_State.NumCommands; - } + m_CommandBuffer.DrawIndexedIndirect(pIndirectDrawAttribsVk->GetVkBuffer(), pIndirectDrawAttribsVk->GetDynamicOffset(m_ContextId, this) + Attribs.IndirectDrawArgsOffset, 1, 0); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::PrepareForDispatchCompute() - { - EnsureVkCmdBuffer(); +void DeviceContextVkImpl::PrepareForDispatchCompute() +{ + EnsureVkCmdBuffer(); - // Dispatch commands must be executed outside of render pass - if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) - m_CommandBuffer.EndRenderPass(); + // Dispatch commands must be executed outside of render pass + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + m_CommandBuffer.EndRenderPass(); - if (m_DescrSetBindInfo.DynamicOffsetCount != 0) + if (m_DescrSetBindInfo.DynamicOffsetCount != 0) + { + if (!m_DescrSetBindInfo.DynamicDescriptorsBound || m_DescrSetBindInfo.DynamicBuffersPresent) { - if (!m_DescrSetBindInfo.DynamicDescriptorsBound || m_DescrSetBindInfo.DynamicBuffersPresent) - { - m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo); - } + m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo); } + } #if 0 -#ifdef _DEBUG - else - { - if ( m_pPipelineState->dbgContainsShaderResources() ) - LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called" ); - } -#endif -#endif +# ifdef _DEBUG + else + { + if ( m_pPipelineState->dbgContainsShaderResources() ) + LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called" ); } +# endif +#endif +} - void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) - { - if (!DvpVerifyDispatchArguments(Attribs)) - return; +void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) +{ + if (!DvpVerifyDispatchArguments(Attribs)) + return; - PrepareForDispatchCompute(); - m_CommandBuffer.Dispatch(Attribs.ThreadGroupCountX, Attribs.ThreadGroupCountY, Attribs.ThreadGroupCountZ); - ++m_State.NumCommands; - } + PrepareForDispatchCompute(); + m_CommandBuffer.Dispatch(Attribs.ThreadGroupCountX, Attribs.ThreadGroupCountY, Attribs.ThreadGroupCountZ); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) - { - if (!DvpVerifyDispatchIndirectArguments(Attribs, pAttribsBuffer)) - return; +void DeviceContextVkImpl::DispatchComputeIndirect(const DispatchComputeIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + if (!DvpVerifyDispatchIndirectArguments(Attribs, pAttribsBuffer)) + return; + + PrepareForDispatchCompute(); - PrepareForDispatchCompute(); + auto* pBufferVk = ValidatedCast(pAttribsBuffer); - auto* pBufferVk = ValidatedCast(pAttribsBuffer); - #ifdef DEVELOPMENT - if (pBufferVk->GetDesc().Usage == USAGE_DYNAMIC) - pBufferVk->DvpVerifyDynamicAllocation(this); + if (pBufferVk->GetDesc().Usage == USAGE_DYNAMIC) + pBufferVk->DvpVerifyDynamicAllocation(this); #endif - // Buffer memory barries must be executed outside of render pass - TransitionOrVerifyBufferState(*pBufferVk, Attribs.IndirectAttribsBufferStateTransitionMode, RESOURCE_STATE_INDIRECT_ARGUMENT, - VK_ACCESS_INDIRECT_COMMAND_READ_BIT, "Indirect dispatch (DeviceContextVkImpl::DispatchCompute)"); + // Buffer memory barries must be executed outside of render pass + TransitionOrVerifyBufferState(*pBufferVk, Attribs.IndirectAttribsBufferStateTransitionMode, RESOURCE_STATE_INDIRECT_ARGUMENT, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT, "Indirect dispatch (DeviceContextVkImpl::DispatchCompute)"); - m_CommandBuffer.DispatchIndirect(pBufferVk->GetVkBuffer(), pBufferVk->GetDynamicOffset(m_ContextId, this) + Attribs.DispatchArgsByteOffset); - ++m_State.NumCommands; - } + m_CommandBuffer.DispatchIndirect(pBufferVk->GetVkBuffer(), pBufferVk->GetDynamicOffset(m_ContextId, this) + Attribs.DispatchArgsByteOffset); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::ClearDepthStencil(ITextureView* pView, - CLEAR_DEPTH_STENCIL_FLAGS ClearFlags, - float fDepth, - Uint8 Stencil, - RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +void DeviceContextVkImpl::ClearDepthStencil(ITextureView* pView, + CLEAR_DEPTH_STENCIL_FLAGS ClearFlags, + float fDepth, + Uint8 Stencil, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + ITextureViewVk* pVkDSV = nullptr; + if (pView != nullptr) { - ITextureViewVk* pVkDSV = nullptr; - if ( pView != nullptr ) - { - pVkDSV = ValidatedCast(pView); + pVkDSV = ValidatedCast(pView); #ifdef DEVELOPMENT - const auto& ViewDesc = pVkDSV->GetDesc(); - if ( ViewDesc.ViewType != TEXTURE_VIEW_DEPTH_STENCIL) + const auto& ViewDesc = pVkDSV->GetDesc(); + if (ViewDesc.ViewType != TEXTURE_VIEW_DEPTH_STENCIL) + { + LOG_ERROR("The type (", GetTexViewTypeLiteralName(ViewDesc.ViewType), ") of texture view '", pView->GetDesc().Name, "' is incorrect for ClearDepthStencil operation. Depth-stencil view (TEXTURE_VIEW_DEPTH_STENCIL) must be provided."); + return; + } +#endif + } + else + { + if (m_pSwapChain) + { + pVkDSV = ValidatedCast(m_pSwapChain->GetDepthBufferDSV()); + if (pVkDSV == nullptr) { - LOG_ERROR("The type (", GetTexViewTypeLiteralName(ViewDesc.ViewType), ") of texture view '", pView->GetDesc().Name, "' is incorrect for ClearDepthStencil operation. Depth-stencil view (TEXTURE_VIEW_DEPTH_STENCIL) must be provided." ); + LOG_WARNING_MESSAGE("Depth buffer is not initialized in the swap chain. Clear operation will be ignored."); return; } -#endif } else { - if (m_pSwapChain) - { - pVkDSV = ValidatedCast(m_pSwapChain->GetDepthBufferDSV()); - if (pVkDSV == nullptr) - { - LOG_WARNING_MESSAGE("Depth buffer is not initialized in the swap chain. Clear operation will be ignored."); - return; - } - } - else - { - LOG_ERROR("Failed to clear default depth stencil buffer: swap chain is not initialized in the device context"); - return; - } + LOG_ERROR("Failed to clear default depth stencil buffer: swap chain is not initialized in the device context"); + return; } + } - EnsureVkCmdBuffer(); + EnsureVkCmdBuffer(); - const auto& ViewDesc = pVkDSV->GetDesc(); - VERIFY(ViewDesc.TextureDim != RESOURCE_DIM_TEX_3D, "Depth-stencil view of a 3D texture should've been created as 2D texture array view"); + const auto& ViewDesc = pVkDSV->GetDesc(); + VERIFY(ViewDesc.TextureDim != RESOURCE_DIM_TEX_3D, "Depth-stencil view of a 3D texture should've been created as 2D texture array view"); - if (pVkDSV == m_pBoundDepthStencil) - { - // Render pass may not be currently committed - VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE && m_Framebuffer != VK_NULL_HANDLE); - TransitionRenderTargets(StateTransitionMode); - // No need to verify states again - CommitRenderPassAndFramebuffer(false); - - VkClearAttachment ClearAttachment = {}; - ClearAttachment.aspectMask = 0; - if (ClearFlags & CLEAR_DEPTH_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - if (ClearFlags & CLEAR_STENCIL_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - // colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask - ClearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED; - ClearAttachment.clearValue.depthStencil.depth = fDepth; - ClearAttachment.clearValue.depthStencil.stencil = Stencil; - VkClearRect ClearRect; - // m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level - ClearRect.rect = { {0, 0}, {m_FramebufferWidth, m_FramebufferHeight} }; - // The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of - // the attachment image view (17.2), so baseArrayLayer is 0, not ViewDesc.FirstArraySlice - ClearRect.baseArrayLayer = 0; - ClearRect.layerCount = ViewDesc.NumArraySlices; - // No memory barriers are needed between vkCmdClearAttachments and preceding or - // subsequent draw or attachment clear commands in the same subpass (17.2) - m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect); - } - else - { - // End render pass to clear the buffer with vkCmdClearDepthStencilImage - if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) - m_CommandBuffer.EndRenderPass(); + if (pVkDSV == m_pBoundDepthStencil) + { + // Render pass may not be currently committed + VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE && m_Framebuffer != VK_NULL_HANDLE); + TransitionRenderTargets(StateTransitionMode); + // No need to verify states again + CommitRenderPassAndFramebuffer(false); + + VkClearAttachment ClearAttachment = {}; + ClearAttachment.aspectMask = 0; + if (ClearFlags & CLEAR_DEPTH_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (ClearFlags & CLEAR_STENCIL_FLAG) ClearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + // colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask + ClearAttachment.colorAttachment = VK_ATTACHMENT_UNUSED; + ClearAttachment.clearValue.depthStencil.depth = fDepth; + ClearAttachment.clearValue.depthStencil.stencil = Stencil; + VkClearRect ClearRect; + // m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level + ClearRect.rect = {{0, 0}, {m_FramebufferWidth, m_FramebufferHeight}}; + // The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of + // the attachment image view (17.2), so baseArrayLayer is 0, not ViewDesc.FirstArraySlice + ClearRect.baseArrayLayer = 0; + ClearRect.layerCount = ViewDesc.NumArraySlices; + // No memory barriers are needed between vkCmdClearAttachments and preceding or + // subsequent draw or attachment clear commands in the same subpass (17.2) + m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect); + } + else + { + // End render pass to clear the buffer with vkCmdClearDepthStencilImage + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + m_CommandBuffer.EndRenderPass(); - auto* pTexture = pVkDSV->GetTexture(); - auto* pTextureVk = ValidatedCast(pTexture); - - // Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1) - TransitionOrVerifyTextureState(*pTextureVk, StateTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - "Clearing depth-stencil buffer outside of render pass (DeviceContextVkImpl::ClearDepthStencil)"); - - VkClearDepthStencilValue ClearValue; - ClearValue.depth = fDepth; - ClearValue.stencil = Stencil; - VkImageSubresourceRange Subresource; - Subresource.aspectMask = 0; - if (ClearFlags & CLEAR_DEPTH_FLAG) Subresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - if (ClearFlags & CLEAR_STENCIL_FLAG) Subresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - // We are clearing the image, not image view with vkCmdClearDepthStencilImage - Subresource.baseArrayLayer = ViewDesc.FirstArraySlice; - Subresource.layerCount = ViewDesc.NumArraySlices; - Subresource.baseMipLevel = ViewDesc.MostDetailedMip; - Subresource.levelCount = ViewDesc.NumMipLevels; - - m_CommandBuffer.ClearDepthStencilImage(pTextureVk->GetVkImage(), ClearValue, Subresource); - } + auto* pTexture = pVkDSV->GetTexture(); + auto* pTextureVk = ValidatedCast(pTexture); - ++m_State.NumCommands; + // Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1) + TransitionOrVerifyTextureState(*pTextureVk, StateTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + "Clearing depth-stencil buffer outside of render pass (DeviceContextVkImpl::ClearDepthStencil)"); + + VkClearDepthStencilValue ClearValue; + ClearValue.depth = fDepth; + ClearValue.stencil = Stencil; + VkImageSubresourceRange Subresource; + Subresource.aspectMask = 0; + if (ClearFlags & CLEAR_DEPTH_FLAG) Subresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (ClearFlags & CLEAR_STENCIL_FLAG) Subresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + // We are clearing the image, not image view with vkCmdClearDepthStencilImage + Subresource.baseArrayLayer = ViewDesc.FirstArraySlice; + Subresource.layerCount = ViewDesc.NumArraySlices; + Subresource.baseMipLevel = ViewDesc.MostDetailedMip; + Subresource.levelCount = ViewDesc.NumMipLevels; + + m_CommandBuffer.ClearDepthStencilImage(pTextureVk->GetVkImage(), ClearValue, Subresource); } - VkClearColorValue ClearValueToVkClearValue(const float *RGBA, TEXTURE_FORMAT TexFmt) - { - VkClearColorValue ClearValue; - const auto& FmtAttribs = GetTextureFormatAttribs(TexFmt); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_SINT) - { - for (int i=0; i < 4; ++i) - ClearValue.int32[i] = static_cast(RGBA[i]); - } - else if (FmtAttribs.ComponentType == COMPONENT_TYPE_UINT) - { - for (int i = 0; i < 4; ++i) - ClearValue.uint32[i] = static_cast(RGBA[i]); - } - else - { - for (int i = 0; i < 4; ++i) - ClearValue.float32[i] = RGBA[i]; - } + ++m_State.NumCommands; +} - return ClearValue; +VkClearColorValue ClearValueToVkClearValue(const float* RGBA, TEXTURE_FORMAT TexFmt) +{ + VkClearColorValue ClearValue; + const auto& FmtAttribs = GetTextureFormatAttribs(TexFmt); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_SINT) + { + for (int i = 0; i < 4; ++i) + ClearValue.int32[i] = static_cast(RGBA[i]); + } + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_UINT) + { + for (int i = 0; i < 4; ++i) + ClearValue.uint32[i] = static_cast(RGBA[i]); + } + else + { + for (int i = 0; i < 4; ++i) + ClearValue.float32[i] = RGBA[i]; } - void DeviceContextVkImpl::ClearRenderTarget( ITextureView *pView, const float *RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode ) + return ClearValue; +} + +void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + ITextureViewVk* pVkRTV = nullptr; + if (pView != nullptr) { - ITextureViewVk* pVkRTV = nullptr; - if ( pView != nullptr ) - { #ifdef DEVELOPMENT - const auto& ViewDesc = pView->GetDesc(); - if ( ViewDesc.ViewType != TEXTURE_VIEW_RENDER_TARGET) - { - LOG_ERROR("The type (", GetTexViewTypeLiteralName(ViewDesc.ViewType), ") of texture view '", pView->GetDesc().Name, "' is incorrect for ClearRenderTarget operation. Render target view (TEXTURE_VIEW_RENDER_TARGET) must be provided." ); - return; - } + const auto& ViewDesc = pView->GetDesc(); + if (ViewDesc.ViewType != TEXTURE_VIEW_RENDER_TARGET) + { + LOG_ERROR("The type (", GetTexViewTypeLiteralName(ViewDesc.ViewType), ") of texture view '", pView->GetDesc().Name, "' is incorrect for ClearRenderTarget operation. Render target view (TEXTURE_VIEW_RENDER_TARGET) must be provided."); + return; + } #endif - pVkRTV = ValidatedCast(pView); + pVkRTV = ValidatedCast(pView); + } + else + { + if (m_pSwapChain) + { + pVkRTV = ValidatedCast(m_pSwapChain->GetCurrentBackBufferRTV()); } else { - if (m_pSwapChain) - { - pVkRTV = ValidatedCast(m_pSwapChain->GetCurrentBackBufferRTV()); - } - else - { - LOG_ERROR("Failed to clear default render target: swap chain is not initialized in the device context"); - return; - } + 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; - - EnsureVkCmdBuffer(); + static constexpr float Zero[4] = {0.f, 0.f, 0.f, 0.f}; + if (RGBA == nullptr) + RGBA = Zero; - const auto& ViewDesc = pVkRTV->GetDesc(); - VERIFY(ViewDesc.TextureDim != RESOURCE_DIM_TEX_3D, "Render target view of a 3D texture should've been created as 2D texture array view"); + EnsureVkCmdBuffer(); - // Check if the texture is one of the currently bound render targets - static constexpr const Uint32 InvalidAttachmentIndex = static_cast(-1); - Uint32 attachmentIndex = InvalidAttachmentIndex; - for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) - { - if (m_pBoundRenderTargets[rt] == pVkRTV) - { - attachmentIndex = rt; - break; - } - } - - if (attachmentIndex != InvalidAttachmentIndex) + const auto& ViewDesc = pVkRTV->GetDesc(); + VERIFY(ViewDesc.TextureDim != RESOURCE_DIM_TEX_3D, "Render target view of a 3D texture should've been created as 2D texture array view"); + + // Check if the texture is one of the currently bound render targets + static constexpr const Uint32 InvalidAttachmentIndex = static_cast(-1); + + Uint32 attachmentIndex = InvalidAttachmentIndex; + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) + { + if (m_pBoundRenderTargets[rt] == pVkRTV) { - // Render pass may not be currently committed - VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE && m_Framebuffer != VK_NULL_HANDLE); - TransitionRenderTargets(StateTransitionMode); - // No need to verify states again - CommitRenderPassAndFramebuffer(false); - - VkClearAttachment ClearAttachment = {}; - ClearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask, - // in which case it is an index to the pColorAttachments array in the VkSubpassDescription - // structure of the current subpass which selects the color attachment to clear (17.2) - // It is NOT the render pass attachment index - ClearAttachment.colorAttachment = attachmentIndex; - ClearAttachment.clearValue.color = ClearValueToVkClearValue(RGBA, ViewDesc.Format); - VkClearRect ClearRect; - // m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level - ClearRect.rect = { {0, 0}, {m_FramebufferWidth, m_FramebufferHeight} }; - // The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of - // the attachment image view (17.2), so baseArrayLayer is 0, not ViewDesc.FirstArraySlice - ClearRect.baseArrayLayer = 0; - ClearRect.layerCount = ViewDesc.NumArraySlices; - // No memory barriers are needed between vkCmdClearAttachments and preceding or - // subsequent draw or attachment clear commands in the same subpass (17.2) - m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect); + attachmentIndex = rt; + break; } - else - { - // End current render pass and clear the image with vkCmdClearColorImage - if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) - m_CommandBuffer.EndRenderPass(); + } - auto* pTexture = pVkRTV->GetTexture(); - auto* pTextureVk = ValidatedCast(pTexture); + if (attachmentIndex != InvalidAttachmentIndex) + { + // Render pass may not be currently committed + VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE && m_Framebuffer != VK_NULL_HANDLE); + TransitionRenderTargets(StateTransitionMode); + // No need to verify states again + CommitRenderPassAndFramebuffer(false); + + VkClearAttachment ClearAttachment = {}; + ClearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // colorAttachment is only meaningful if VK_IMAGE_ASPECT_COLOR_BIT is set in aspectMask, + // in which case it is an index to the pColorAttachments array in the VkSubpassDescription + // structure of the current subpass which selects the color attachment to clear (17.2) + // It is NOT the render pass attachment index + ClearAttachment.colorAttachment = attachmentIndex; + ClearAttachment.clearValue.color = ClearValueToVkClearValue(RGBA, ViewDesc.Format); + VkClearRect ClearRect; + // m_FramebufferWidth, m_FramebufferHeight are scaled to the proper mip level + ClearRect.rect = {{0, 0}, {m_FramebufferWidth, m_FramebufferHeight}}; + // The layers [baseArrayLayer, baseArrayLayer + layerCount) count from the base layer of + // the attachment image view (17.2), so baseArrayLayer is 0, not ViewDesc.FirstArraySlice + ClearRect.baseArrayLayer = 0; + ClearRect.layerCount = ViewDesc.NumArraySlices; + // No memory barriers are needed between vkCmdClearAttachments and preceding or + // subsequent draw or attachment clear commands in the same subpass (17.2) + m_CommandBuffer.ClearAttachment(ClearAttachment, ClearRect); + } + else + { + // End current render pass and clear the image with vkCmdClearColorImage + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + m_CommandBuffer.EndRenderPass(); - // Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1) - TransitionOrVerifyTextureState(*pTextureVk, StateTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - "Clearing render target outside of render pass (DeviceContextVkImpl::ClearRenderTarget)"); + auto* pTexture = pVkRTV->GetTexture(); + auto* pTextureVk = ValidatedCast(pTexture); - auto ClearValue = ClearValueToVkClearValue(RGBA, ViewDesc.Format); - VkImageSubresourceRange Subresource; - Subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // We are clearing the image, not image view with vkCmdClearColorImage - Subresource.baseArrayLayer = ViewDesc.FirstArraySlice; - Subresource.layerCount = ViewDesc.NumArraySlices; - Subresource.baseMipLevel = ViewDesc.MostDetailedMip; - Subresource.levelCount = ViewDesc.NumMipLevels; - VERIFY(ViewDesc.NumMipLevels, "RTV must contain single mip level"); + // Image layout must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL (17.1) + TransitionOrVerifyTextureState(*pTextureVk, StateTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + "Clearing render target outside of render pass (DeviceContextVkImpl::ClearRenderTarget)"); - m_CommandBuffer.ClearColorImage(pTextureVk->GetVkImage(), ClearValue, Subresource); - } + auto ClearValue = ClearValueToVkClearValue(RGBA, ViewDesc.Format); + + VkImageSubresourceRange Subresource; + Subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + // We are clearing the image, not image view with vkCmdClearColorImage + Subresource.baseArrayLayer = ViewDesc.FirstArraySlice; + Subresource.layerCount = ViewDesc.NumArraySlices; + Subresource.baseMipLevel = ViewDesc.MostDetailedMip; + Subresource.levelCount = ViewDesc.NumMipLevels; + VERIFY(ViewDesc.NumMipLevels, "RTV must contain single mip level"); - ++m_State.NumCommands; + m_CommandBuffer.ClearColorImage(pTextureVk->GetVkImage(), ClearValue, Subresource); } - void DeviceContextVkImpl::FinishFrame() - { + ++m_State.NumCommands; +} + +void DeviceContextVkImpl::FinishFrame() +{ #ifdef _DEBUG - for(const auto& MappedBuffIt : m_DbgMappedBuffers) + for (const auto& MappedBuffIt : m_DbgMappedBuffers) + { + const auto& BuffDesc = MappedBuffIt.first->GetDesc(); + if (BuffDesc.Usage == USAGE_DYNAMIC) { - const auto& BuffDesc = MappedBuffIt.first->GetDesc(); - if (BuffDesc.Usage == USAGE_DYNAMIC) - { - LOG_WARNING_MESSAGE("Dynamic buffer '", BuffDesc.Name, "' is still mapped when finishing the frame. The contents of the buffer and mapped address will become invalid"); - } + LOG_WARNING_MESSAGE("Dynamic buffer '", BuffDesc.Name, "' is still mapped when finishing the frame. The contents of the buffer and mapped address will become invalid"); } + } #endif - if(GetNumCommandsInCtx() != 0) + if (GetNumCommandsInCtx() != 0) + { + if (m_bIsDeferred) { - if (m_bIsDeferred) - { - LOG_ERROR_MESSAGE("There are outstanding commands in deferred device context #", m_ContextId, - " when finishing the frame. This is an error and may cause unpredicted behaviour." - " Close all deferred contexts and execute them before finishing the frame."); - - } - else - { - 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."); - } + LOG_ERROR_MESSAGE("There are outstanding commands in deferred device context #", m_ContextId, + " when finishing the frame. This is an error and may cause unpredicted behaviour." + " Close all deferred contexts and execute them before finishing the frame."); + } + else + { + 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."); } + } - if (!m_MappedTextures.empty()) - LOG_ERROR_MESSAGE("There are mapped textures in the device context when finishing the frame. All dynamic resources must be used in the same frame in which they are mapped."); + if (!m_MappedTextures.empty()) + LOG_ERROR_MESSAGE("There are mapped textures in the device context when finishing the frame. All dynamic resources must be used in the same frame in which they are mapped."); - VERIFY_EXPR(m_bIsDeferred || m_SubmittedBuffersCmdQueueMask == (Uint64{1}<(m_WaitSemaphores.size()); - VERIFY_EXPR(m_WaitSemaphores.size() == m_WaitDstStageMasks.size()); - SubmitInfo.pWaitSemaphores = SubmitInfo.waitSemaphoreCount != 0 ? m_WaitSemaphores.data() : nullptr; - SubmitInfo.pWaitDstStageMask = SubmitInfo.waitSemaphoreCount != 0 ? m_WaitDstStageMasks.data() : nullptr; - SubmitInfo.signalSemaphoreCount = static_cast(m_SignalSemaphores.size()); - SubmitInfo.pSignalSemaphores = SubmitInfo.signalSemaphoreCount != 0 ? m_SignalSemaphores.data() : nullptr; - - // Submit command buffer even if there are no commands to release stale resources. - //if (SubmitInfo.commandBufferCount != 0 || SubmitInfo.waitSemaphoreCount !=0 || SubmitInfo.signalSemaphoreCount != 0) - auto SubmittedFenceValue = m_pDevice->ExecuteCommandBuffer(m_CommandQueueId, SubmitInfo, this, &m_PendingFences); - - m_WaitSemaphores.clear(); - m_WaitDstStageMasks.clear(); - m_SignalSemaphores.clear(); - m_PendingFences.clear(); - - if (vkCmdBuff != VK_NULL_HANDLE) - { - DisposeCurrentCmdBuffer(m_CommandQueueId, SubmittedFenceValue); - } + VkSubmitInfo SubmitInfo = {}; - m_State = ContextState{}; - m_DescrSetBindInfo.Reset(); - m_CommandBuffer.Reset(); - m_pPipelineState = nullptr; - } + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; - void DeviceContextVkImpl::SetVertexBuffers( Uint32 StartSlot, - Uint32 NumBuffersSet, - IBuffer** ppBuffers, - Uint32* pOffsets, - RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, - SET_VERTEX_BUFFERS_FLAGS Flags ) + auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); + if (vkCmdBuff != VK_NULL_HANDLE) { - TDeviceContextBase::SetVertexBuffers( StartSlot, NumBuffersSet, ppBuffers, pOffsets, StateTransitionMode, Flags ); - for ( Uint32 Buff = 0; Buff < m_NumVertexStreams; ++Buff ) + if (m_State.NumCommands != 0) { - auto& CurrStream = m_VertexStreams[Buff]; - if(auto* pBufferVk = CurrStream.pBuffer.RawPtr()) + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) { - TransitionOrVerifyBufferState(*pBufferVk, StateTransitionMode, RESOURCE_STATE_VERTEX_BUFFER, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, - "Setting vertex buffers (DeviceContextVkImpl::SetVertexBuffers)"); + m_CommandBuffer.EndRenderPass(); } + + m_CommandBuffer.FlushBarriers(); + m_CommandBuffer.EndCommandBuffer(); + + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &vkCmdBuff; } - m_State.CommittedVBsUpToDate = false; } - void DeviceContextVkImpl::InvalidateState() + SubmitInfo.waitSemaphoreCount = static_cast(m_WaitSemaphores.size()); + VERIFY_EXPR(m_WaitSemaphores.size() == m_WaitDstStageMasks.size()); + SubmitInfo.pWaitSemaphores = SubmitInfo.waitSemaphoreCount != 0 ? m_WaitSemaphores.data() : nullptr; + SubmitInfo.pWaitDstStageMask = SubmitInfo.waitSemaphoreCount != 0 ? m_WaitDstStageMasks.data() : nullptr; + SubmitInfo.signalSemaphoreCount = static_cast(m_SignalSemaphores.size()); + SubmitInfo.pSignalSemaphores = SubmitInfo.signalSemaphoreCount != 0 ? m_SignalSemaphores.data() : nullptr; + + // Submit command buffer even if there are no commands to release stale resources. + //if (SubmitInfo.commandBufferCount != 0 || SubmitInfo.waitSemaphoreCount !=0 || SubmitInfo.signalSemaphoreCount != 0) + auto SubmittedFenceValue = m_pDevice->ExecuteCommandBuffer(m_CommandQueueId, SubmitInfo, this, &m_PendingFences); + + m_WaitSemaphores.clear(); + m_WaitDstStageMasks.clear(); + m_SignalSemaphores.clear(); + m_PendingFences.clear(); + + if (vkCmdBuff != VK_NULL_HANDLE) { - if (m_State.NumCommands != 0) - LOG_WARNING_MESSAGE("Invalidating context that has outstanding commands in it. Call Flush() to submit commands for execution"); - - TDeviceContextBase::InvalidateState(); - m_State = ContextState{}; - m_RenderPass = VK_NULL_HANDLE; - m_Framebuffer = VK_NULL_HANDLE; - m_DescrSetBindInfo.Reset(); - VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Invalidating context with unifinished render pass"); - m_CommandBuffer.Reset(); + DisposeCurrentCmdBuffer(m_CommandQueueId, SubmittedFenceValue); } - void DeviceContextVkImpl::SetIndexBuffer( IBuffer *pIndexBuffer, Uint32 ByteOffset, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode ) + m_State = ContextState{}; + m_DescrSetBindInfo.Reset(); + m_CommandBuffer.Reset(); + m_pPipelineState = nullptr; +} + +void DeviceContextVkImpl::SetVertexBuffers(Uint32 StartSlot, + Uint32 NumBuffersSet, + IBuffer** ppBuffers, + Uint32* pOffsets, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, + SET_VERTEX_BUFFERS_FLAGS Flags) +{ + TDeviceContextBase::SetVertexBuffers(StartSlot, NumBuffersSet, ppBuffers, pOffsets, StateTransitionMode, Flags); + for (Uint32 Buff = 0; Buff < m_NumVertexStreams; ++Buff) { - TDeviceContextBase::SetIndexBuffer( pIndexBuffer, ByteOffset, StateTransitionMode ); - if (m_pIndexBuffer) + auto& CurrStream = m_VertexStreams[Buff]; + if (auto* pBufferVk = CurrStream.pBuffer.RawPtr()) { - TransitionOrVerifyBufferState(*m_pIndexBuffer, StateTransitionMode, RESOURCE_STATE_INDEX_BUFFER, VK_ACCESS_INDEX_READ_BIT, "Binding buffer as index buffer (DeviceContextVkImpl::SetIndexBuffer)" ); + TransitionOrVerifyBufferState(*pBufferVk, StateTransitionMode, RESOURCE_STATE_VERTEX_BUFFER, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + "Setting vertex buffers (DeviceContextVkImpl::SetVertexBuffers)"); } - m_State.CommittedIBUpToDate = false; } + m_State.CommittedVBsUpToDate = false; +} +void DeviceContextVkImpl::InvalidateState() +{ + if (m_State.NumCommands != 0) + LOG_WARNING_MESSAGE("Invalidating context that has outstanding commands in it. Call Flush() to submit commands for execution"); + + TDeviceContextBase::InvalidateState(); + m_State = ContextState{}; + m_RenderPass = VK_NULL_HANDLE; + m_Framebuffer = VK_NULL_HANDLE; + m_DescrSetBindInfo.Reset(); + VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Invalidating context with unifinished render pass"); + m_CommandBuffer.Reset(); +} - void DeviceContextVkImpl::CommitViewports() +void DeviceContextVkImpl::SetIndexBuffer(IBuffer* pIndexBuffer, Uint32 ByteOffset, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + TDeviceContextBase::SetIndexBuffer(pIndexBuffer, ByteOffset, StateTransitionMode); + if (m_pIndexBuffer) { - VkViewport VkViewports[MaxViewports]; // Do not waste time initializing array to zero - for ( Uint32 vp = 0; vp < m_NumViewports; ++vp ) - { - VkViewports[vp].x = m_Viewports[vp].TopLeftX; - VkViewports[vp].y = 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; - - // Turn the viewport upside down to be consistent with Direct3D. Note that in both APIs, - // the viewport covers the same texture rows. The difference is that Direct3D invertes - // normalized device Y coordinate when transforming NDC to window coordinates. In Vulkan - // we achieve the same effect by using negative viewport height. Therefore we need to - // invert normalized device Y coordinate when transforming to texture V - // - // - // Image Direct3D Image Vulkan - // row row - // 0 _ (0,0)_______________________(1,0) Tex Height _ (0,1)_______________________(1,1) - // 1 _ | | | VP Top + Hght _ _ _ _| __________ | A - // 2 _ | | | . | | .--> +x| | | - // . | | | . | | | | | | - // . | | | V Coord | | V +y | | | V Coord - // VP Top _ _ _ _| __________ | | VP Top _ _ _ _| |__________| | | - // . | | A +y | | | . | | | - // . | | | | | | . | | | - // . | | '-->+x| | | 2 _ | | | - // . | |__________| | | 1 _ | | | - //Tex Height _ |_______________________| V 0 _ |_______________________| | - // (0,1) (1,1) (0,0) (1,0) - // - // - - VkViewports[vp].y = VkViewports[vp].y + VkViewports[vp].height; - VkViewports[vp].height = -VkViewports[vp].height; - } - EnsureVkCmdBuffer(); - // TODO: reinterpret_cast m_Viewports to VkViewports? - m_CommandBuffer.SetViewports(0, m_NumViewports, VkViewports); + TransitionOrVerifyBufferState(*m_pIndexBuffer, StateTransitionMode, RESOURCE_STATE_INDEX_BUFFER, VK_ACCESS_INDEX_READ_BIT, "Binding buffer as index buffer (DeviceContextVkImpl::SetIndexBuffer)"); } + m_State.CommittedIBUpToDate = false; +} - void DeviceContextVkImpl::SetViewports( Uint32 NumViewports, const Viewport *pViewports, Uint32 RTWidth, Uint32 RTHeight ) - { - TDeviceContextBase::SetViewports( NumViewports, pViewports, RTWidth, RTHeight ); - VERIFY( NumViewports == m_NumViewports, "Unexpected number of viewports" ); - CommitViewports(); - } +void DeviceContextVkImpl::CommitViewports() +{ + VkViewport VkViewports[MaxViewports]; // Do not waste time initializing array to zero + for (Uint32 vp = 0; vp < m_NumViewports; ++vp) + { + VkViewports[vp].x = m_Viewports[vp].TopLeftX; + VkViewports[vp].y = 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; + + // Turn the viewport upside down to be consistent with Direct3D. Note that in both APIs, + // the viewport covers the same texture rows. The difference is that Direct3D invertes + // normalized device Y coordinate when transforming NDC to window coordinates. In Vulkan + // we achieve the same effect by using negative viewport height. Therefore we need to + // invert normalized device Y coordinate when transforming to texture V + // + // + // Image Direct3D Image Vulkan + // row row + // 0 _ (0,0)_______________________(1,0) Tex Height _ (0,1)_______________________(1,1) + // 1 _ | | | VP Top + Hght _ _ _ _| __________ | A + // 2 _ | | | . | | .--> +x| | | + // . | | | . | | | | | | + // . | | | V Coord | | V +y | | | V Coord + // VP Top _ _ _ _| __________ | | VP Top _ _ _ _| |__________| | | + // . | | A +y | | | . | | | + // . | | | | | | . | | | + // . | | '-->+x| | | 2 _ | | | + // . | |__________| | | 1 _ | | | + //Tex Height _ |_______________________| V 0 _ |_______________________| | + // (0,1) (1,1) (0,0) (1,0) + // + // + + VkViewports[vp].y = VkViewports[vp].y + VkViewports[vp].height; + VkViewports[vp].height = -VkViewports[vp].height; + } + EnsureVkCmdBuffer(); + // TODO: reinterpret_cast m_Viewports to VkViewports? + m_CommandBuffer.SetViewports(0, m_NumViewports, VkViewports); +} - void DeviceContextVkImpl::CommitScissorRects() - { - VERIFY(m_pPipelineState && m_pPipelineState->GetDesc().GraphicsPipeline.RasterizerDesc.ScissorEnable, "Scissor test must be enabled in the graphics pipeline"); +void DeviceContextVkImpl::SetViewports(Uint32 NumViewports, const Viewport* pViewports, Uint32 RTWidth, Uint32 RTHeight) +{ + TDeviceContextBase::SetViewports(NumViewports, pViewports, RTWidth, RTHeight); + VERIFY(NumViewports == m_NumViewports, "Unexpected number of viewports"); + + CommitViewports(); +} - if (m_NumScissorRects == 0) - return; // Scissors have not been set in the context yet +void DeviceContextVkImpl::CommitScissorRects() +{ + VERIFY(m_pPipelineState && m_pPipelineState->GetDesc().GraphicsPipeline.RasterizerDesc.ScissorEnable, "Scissor test must be enabled in the graphics pipeline"); - VkRect2D VkScissorRects[MaxViewports]; // Do not waste time initializing array with zeroes - for (Uint32 sr = 0; sr < m_NumScissorRects; ++sr) - { - const auto &SrcRect = m_ScissorRects[sr]; - VkScissorRects[sr].offset = {SrcRect.left, SrcRect.top}; - VkScissorRects[sr].extent = {static_cast(SrcRect.right - SrcRect.left), static_cast(SrcRect.bottom - SrcRect.top)}; - } + if (m_NumScissorRects == 0) + return; // Scissors have not been set in the context yet - EnsureVkCmdBuffer(); - // TODO: reinterpret_cast m_Viewports to m_Viewports? - m_CommandBuffer.SetScissorRects(0, m_NumScissorRects, VkScissorRects); + VkRect2D VkScissorRects[MaxViewports]; // Do not waste time initializing array with zeroes + for (Uint32 sr = 0; sr < m_NumScissorRects; ++sr) + { + const auto& SrcRect = m_ScissorRects[sr]; + VkScissorRects[sr].offset = {SrcRect.left, SrcRect.top}; + VkScissorRects[sr].extent = {static_cast(SrcRect.right - SrcRect.left), static_cast(SrcRect.bottom - SrcRect.top)}; } + EnsureVkCmdBuffer(); + // TODO: reinterpret_cast m_Viewports to m_Viewports? + m_CommandBuffer.SetScissorRects(0, m_NumScissorRects, VkScissorRects); +} - void DeviceContextVkImpl::SetScissorRects( Uint32 NumRects, const Rect *pRects, Uint32 RTWidth, Uint32 RTHeight ) - { - 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 ) +void DeviceContextVkImpl::SetScissorRects(Uint32 NumRects, const Rect* pRects, Uint32 RTWidth, Uint32 RTHeight) +{ + 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) { - const auto &PSODesc = m_pPipelineState->GetDesc(); - if (!PSODesc.IsComputePipeline && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) - { - VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); - CommitScissorRects(); - } + VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); + CommitScissorRects(); } } +} - void DeviceContextVkImpl::TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +void DeviceContextVkImpl::TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + if (m_pBoundDepthStencil) { - if (m_pBoundDepthStencil) - { - auto* pDepthBufferVk = ValidatedCast(m_pBoundDepthStencil->GetTexture()); - TransitionOrVerifyTextureState(*pDepthBufferVk, StateTransitionMode, RESOURCE_STATE_DEPTH_WRITE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - "Binding depth-stencil buffer (DeviceContextVkImpl::TransitionRenderTargets)"); - } + auto* pDepthBufferVk = ValidatedCast(m_pBoundDepthStencil->GetTexture()); + TransitionOrVerifyTextureState(*pDepthBufferVk, StateTransitionMode, RESOURCE_STATE_DEPTH_WRITE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + "Binding depth-stencil buffer (DeviceContextVkImpl::TransitionRenderTargets)"); + } - for (Uint32 rt=0; rt < m_NumBoundRenderTargets; ++rt) + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) + { + if (ITextureView* pRTVVk = m_pBoundRenderTargets[rt].RawPtr()) { - if (ITextureView* pRTVVk = m_pBoundRenderTargets[rt].RawPtr()) - { - auto* pRenderTargetVk = ValidatedCast(pRTVVk->GetTexture()); - TransitionOrVerifyTextureState(*pRenderTargetVk, StateTransitionMode, RESOURCE_STATE_RENDER_TARGET, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - "Binding render targets (DeviceContextVkImpl::TransitionRenderTargets)"); - } + auto* pRenderTargetVk = ValidatedCast(pRTVVk->GetTexture()); + TransitionOrVerifyTextureState(*pRenderTargetVk, StateTransitionMode, RESOURCE_STATE_RENDER_TARGET, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + "Binding render targets (DeviceContextVkImpl::TransitionRenderTargets)"); } } +} - void DeviceContextVkImpl::CommitRenderPassAndFramebuffer(bool VerifyStates) +void DeviceContextVkImpl::CommitRenderPassAndFramebuffer(bool VerifyStates) +{ + const auto& CmdBufferState = m_CommandBuffer.GetState(); + if (CmdBufferState.Framebuffer != m_Framebuffer) { - const auto& CmdBufferState = m_CommandBuffer.GetState(); - if (CmdBufferState.Framebuffer != m_Framebuffer) + if (CmdBufferState.RenderPass != VK_NULL_HANDLE) + m_CommandBuffer.EndRenderPass(); + + if (m_Framebuffer != VK_NULL_HANDLE) { - if (CmdBufferState.RenderPass != VK_NULL_HANDLE) - m_CommandBuffer.EndRenderPass(); - - if (m_Framebuffer != VK_NULL_HANDLE) - { - VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE); + VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE); #ifdef DEVELOPMENT - if (VerifyStates) - { - TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE_VERIFY); - } -#endif - m_CommandBuffer.BeginRenderPass(m_RenderPass, m_Framebuffer, m_FramebufferWidth, m_FramebufferHeight); + if (VerifyStates) + { + TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE_VERIFY); } +#endif + m_CommandBuffer.BeginRenderPass(m_RenderPass, m_Framebuffer, m_FramebufferWidth, m_FramebufferHeight); } } +} - void DeviceContextVkImpl::SetRenderTargets( Uint32 NumRenderTargets, - ITextureView* ppRenderTargets[], - ITextureView* pDepthStencil, - RESOURCE_STATE_TRANSITION_MODE StateTransitionMode ) +void DeviceContextVkImpl::SetRenderTargets(Uint32 NumRenderTargets, + ITextureView* ppRenderTargets[], + ITextureView* pDepthStencil, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + if (TDeviceContextBase::SetRenderTargets(NumRenderTargets, ppRenderTargets, pDepthStencil)) { - if ( TDeviceContextBase::SetRenderTargets( NumRenderTargets, ppRenderTargets, pDepthStencil ) ) + FramebufferCache::FramebufferCacheKey FBKey; + RenderPassCache::RenderPassCacheKey RenderPassKey; + if (m_pBoundDepthStencil) + { + auto* pDepthBuffer = m_pBoundDepthStencil->GetTexture(); + FBKey.DSV = m_pBoundDepthStencil->GetVulkanImageView(); + RenderPassKey.DSVFormat = m_pBoundDepthStencil->GetDesc().Format; + RenderPassKey.SampleCount = static_cast(pDepthBuffer->GetDesc().SampleCount); + } + else + { + FBKey.DSV = VK_NULL_HANDLE; + RenderPassKey.DSVFormat = TEX_FORMAT_UNKNOWN; + } + + FBKey.NumRenderTargets = m_NumBoundRenderTargets; + RenderPassKey.NumRenderTargets = static_cast(m_NumBoundRenderTargets); + + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) { - FramebufferCache::FramebufferCacheKey FBKey; - RenderPassCache::RenderPassCacheKey RenderPassKey; - if (m_pBoundDepthStencil) + if (auto* pRTVVk = m_pBoundRenderTargets[rt].RawPtr()) { - auto* pDepthBuffer = m_pBoundDepthStencil->GetTexture(); - FBKey.DSV = m_pBoundDepthStencil->GetVulkanImageView(); - RenderPassKey.DSVFormat = m_pBoundDepthStencil->GetDesc().Format; - RenderPassKey.SampleCount = static_cast(pDepthBuffer->GetDesc().SampleCount); + auto* pRenderTarget = pRTVVk->GetTexture(); + FBKey.RTVs[rt] = pRTVVk->GetVulkanImageView(); + RenderPassKey.RTVFormats[rt] = pRenderTarget->GetDesc().Format; + if (RenderPassKey.SampleCount == 0) + RenderPassKey.SampleCount = static_cast(pRenderTarget->GetDesc().SampleCount); + else + VERIFY(RenderPassKey.SampleCount == pRenderTarget->GetDesc().SampleCount, "Inconsistent sample count"); } else { - FBKey.DSV = VK_NULL_HANDLE; - RenderPassKey.DSVFormat = TEX_FORMAT_UNKNOWN; + FBKey.RTVs[rt] = VK_NULL_HANDLE; + RenderPassKey.RTVFormats[rt] = TEX_FORMAT_UNKNOWN; } + } - FBKey.NumRenderTargets = m_NumBoundRenderTargets; - RenderPassKey.NumRenderTargets = static_cast(m_NumBoundRenderTargets); - - for (Uint32 rt=0; rt < m_NumBoundRenderTargets; ++rt) - { - if (auto* pRTVVk = m_pBoundRenderTargets[rt].RawPtr()) - { - auto* pRenderTarget = pRTVVk->GetTexture(); - FBKey.RTVs[rt] = pRTVVk->GetVulkanImageView(); - RenderPassKey.RTVFormats[rt] = pRenderTarget->GetDesc().Format; - if (RenderPassKey.SampleCount == 0) - RenderPassKey.SampleCount = static_cast(pRenderTarget->GetDesc().SampleCount); - else - VERIFY(RenderPassKey.SampleCount == pRenderTarget->GetDesc().SampleCount, "Inconsistent sample count"); - } - else - { - FBKey.RTVs[rt] = VK_NULL_HANDLE; - RenderPassKey.RTVFormats[rt] = TEX_FORMAT_UNKNOWN; - } - } + auto& FBCache = m_pDevice->GetFramebufferCache(); + auto& RPCache = m_pDevice->GetRenderPassCache(); - auto& FBCache = m_pDevice->GetFramebufferCache(); - auto& RPCache = m_pDevice->GetRenderPassCache(); + m_RenderPass = RPCache.GetRenderPass(RenderPassKey); + FBKey.Pass = m_RenderPass; + FBKey.CommandQueueMask = ~Uint64{0}; + m_Framebuffer = FBCache.GetFramebuffer(FBKey, m_FramebufferWidth, m_FramebufferHeight, m_FramebufferSlices); - m_RenderPass = RPCache.GetRenderPass(RenderPassKey); - FBKey.Pass = m_RenderPass; - FBKey.CommandQueueMask = ~Uint64{0}; - m_Framebuffer = FBCache.GetFramebuffer(FBKey, m_FramebufferWidth, m_FramebufferHeight, m_FramebufferSlices); + // Set the viewport to match the render target size + SetViewports(1, nullptr, 0, 0); + } - // Set the viewport to match the render target size - SetViewports(1, nullptr, 0, 0); - } + // Layout transitions can only be performed outside of render pass, so defer + // CommitRenderPassAndFramebuffer() until draw call, otherwise we may have to + // to end render pass and begin it again if we need to transition any resource + // (for instance when CommitShaderResources() is called after SetRenderTargets()) + TransitionRenderTargets(StateTransitionMode); +} - // Layout transitions can only be performed outside of render pass, so defer - // CommitRenderPassAndFramebuffer() until draw call, otherwise we may have to - // to end render pass and begin it again if we need to transition any resource - // (for instance when CommitShaderResources() is called after SetRenderTargets()) - TransitionRenderTargets(StateTransitionMode); - } +void DeviceContextVkImpl::ResetRenderTargets() +{ + TDeviceContextBase::ResetRenderTargets(); + m_RenderPass = VK_NULL_HANDLE; + m_Framebuffer = VK_NULL_HANDLE; +} - void DeviceContextVkImpl::ResetRenderTargets() +void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl* pBuffVk, + Uint64 DstOffset, + Uint64 NumBytes, + VkBuffer vkSrcBuffer, + Uint64 SrcOffset, + RESOURCE_STATE_TRANSITION_MODE TransitionMode) +{ +#ifdef DEVELOPMENT + if (DstOffset + NumBytes > pBuffVk->GetDesc().uiSizeInBytes) { - TDeviceContextBase::ResetRenderTargets(); - m_RenderPass = VK_NULL_HANDLE; - m_Framebuffer = VK_NULL_HANDLE; + LOG_ERROR("Update region is out of buffer bounds which will result in an undefined behavior"); } - - void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl* pBuffVk, - Uint64 DstOffset, - Uint64 NumBytes, - VkBuffer vkSrcBuffer, - Uint64 SrcOffset, - RESOURCE_STATE_TRANSITION_MODE TransitionMode) - { -#ifdef DEVELOPMENT - if (DstOffset + NumBytes > pBuffVk->GetDesc().uiSizeInBytes) - { - LOG_ERROR("Update region is out of buffer bounds which will result in an undefined behavior"); - } #endif - EnsureVkCmdBuffer(); - TransitionOrVerifyBufferState(*pBuffVk, TransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, "Updating buffer (DeviceContextVkImpl::UpdateBufferRegion)"); + EnsureVkCmdBuffer(); + TransitionOrVerifyBufferState(*pBuffVk, TransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, "Updating buffer (DeviceContextVkImpl::UpdateBufferRegion)"); - VkBufferCopy CopyRegion; - CopyRegion.srcOffset = SrcOffset; - CopyRegion.dstOffset = DstOffset; - CopyRegion.size = NumBytes; - VERIFY(pBuffVk->m_VulkanBuffer != VK_NULL_HANDLE, "Copy destination buffer must not be suballocated"); - m_CommandBuffer.CopyBuffer(vkSrcBuffer, pBuffVk->GetVkBuffer(), 1, &CopyRegion); - ++m_State.NumCommands; - } + VkBufferCopy CopyRegion; + CopyRegion.srcOffset = SrcOffset; + CopyRegion.dstOffset = DstOffset; + CopyRegion.size = NumBytes; + VERIFY(pBuffVk->m_VulkanBuffer != VK_NULL_HANDLE, "Copy destination buffer must not be suballocated"); + m_CommandBuffer.CopyBuffer(vkSrcBuffer, pBuffVk->GetVkBuffer(), 1, &CopyRegion); + ++m_State.NumCommands; +} - void DeviceContextVkImpl::UpdateBuffer(IBuffer* pBuffer, - Uint32 Offset, - Uint32 Size, - const PVoid pData, - RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) - { - TDeviceContextBase::UpdateBuffer(pBuffer, Offset, Size, pData, StateTransitionMode); +void DeviceContextVkImpl::UpdateBuffer(IBuffer* pBuffer, + Uint32 Offset, + Uint32 Size, + const PVoid pData, + RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) +{ + TDeviceContextBase::UpdateBuffer(pBuffer, Offset, Size, pData, StateTransitionMode); - // 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* pBuffVk = ValidatedCast(pBuffer); + // 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* pBuffVk = ValidatedCast(pBuffer); #ifdef DEVELOPMENT - if (pBuffVk->GetDesc().Usage == USAGE_DYNAMIC) - { - LOG_ERROR("Dynamic buffers must be updated via Map()"); - return; - } + if (pBuffVk->GetDesc().Usage == USAGE_DYNAMIC) + { + LOG_ERROR("Dynamic buffers must be updated via Map()"); + return; + } #endif - constexpr size_t Alignment = 4; - // Source buffer offset must be multiple of 4 (18.4) - auto TmpSpace = m_UploadHeap.Allocate(Size, Alignment); - memcpy(TmpSpace.CPUAddress, pData, Size); - UpdateBufferRegion(pBuffVk, Offset, Size, TmpSpace.vkBuffer, TmpSpace.AlignedOffset, StateTransitionMode); - // The allocation will stay in the upload heap until the end of the frame at which point all upload - // pages will be discarded - } + constexpr size_t Alignment = 4; + // Source buffer offset must be multiple of 4 (18.4) + auto TmpSpace = m_UploadHeap.Allocate(Size, Alignment); + memcpy(TmpSpace.CPUAddress, pData, Size); + UpdateBufferRegion(pBuffVk, Offset, Size, TmpSpace.vkBuffer, TmpSpace.AlignedOffset, StateTransitionMode); + // The allocation will stay in the upload heap until the end of the frame at which point all upload + // pages will be discarded +} - void DeviceContextVkImpl::CopyBuffer(IBuffer* pSrcBuffer, - Uint32 SrcOffset, - RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, - IBuffer* pDstBuffer, - Uint32 DstOffset, - Uint32 Size, - RESOURCE_STATE_TRANSITION_MODE DstBufferTransitionMode) - { - TDeviceContextBase::CopyBuffer(pSrcBuffer, SrcOffset, SrcBufferTransitionMode, pDstBuffer, DstOffset, Size, DstBufferTransitionMode); +void DeviceContextVkImpl::CopyBuffer(IBuffer* pSrcBuffer, + Uint32 SrcOffset, + RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, + IBuffer* pDstBuffer, + Uint32 DstOffset, + Uint32 Size, + RESOURCE_STATE_TRANSITION_MODE DstBufferTransitionMode) +{ + TDeviceContextBase::CopyBuffer(pSrcBuffer, SrcOffset, SrcBufferTransitionMode, pDstBuffer, DstOffset, Size, DstBufferTransitionMode); - auto* pSrcBuffVk = ValidatedCast(pSrcBuffer); - auto* pDstBuffVk = ValidatedCast(pDstBuffer); + auto* pSrcBuffVk = ValidatedCast(pSrcBuffer); + auto* pDstBuffVk = ValidatedCast(pDstBuffer); #ifdef DEVELOPMENT - if (pDstBuffVk->GetDesc().Usage == USAGE_DYNAMIC) - { - LOG_ERROR("Dynamic buffers cannot be copy destinations"); - return; - } + if (pDstBuffVk->GetDesc().Usage == USAGE_DYNAMIC) + { + LOG_ERROR("Dynamic buffers cannot be copy destinations"); + return; + } #endif - EnsureVkCmdBuffer(); - TransitionOrVerifyBufferState(*pSrcBuffVk, SrcBufferTransitionMode, RESOURCE_STATE_COPY_SOURCE, VK_ACCESS_TRANSFER_READ_BIT, "Using buffer as copy source (DeviceContextVkImpl::CopyBuffer)"); - TransitionOrVerifyBufferState(*pDstBuffVk, DstBufferTransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, "Using buffer as copy destination (DeviceContextVkImpl::CopyBuffer)"); + EnsureVkCmdBuffer(); + TransitionOrVerifyBufferState(*pSrcBuffVk, SrcBufferTransitionMode, RESOURCE_STATE_COPY_SOURCE, VK_ACCESS_TRANSFER_READ_BIT, "Using buffer as copy source (DeviceContextVkImpl::CopyBuffer)"); + TransitionOrVerifyBufferState(*pDstBuffVk, DstBufferTransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, "Using buffer as copy destination (DeviceContextVkImpl::CopyBuffer)"); + + VkBufferCopy CopyRegion; + CopyRegion.srcOffset = SrcOffset + pSrcBuffVk->GetDynamicOffset(m_ContextId, this); + CopyRegion.dstOffset = DstOffset; + CopyRegion.size = Size; + VERIFY(pDstBuffVk->m_VulkanBuffer != VK_NULL_HANDLE, "Copy destination buffer must not be suballocated"); + VERIFY_EXPR(pDstBuffVk->GetDynamicOffset(m_ContextId, this) == 0); + m_CommandBuffer.CopyBuffer(pSrcBuffVk->GetVkBuffer(), pDstBuffVk->GetVkBuffer(), 1, &CopyRegion); + ++m_State.NumCommands; +} - VkBufferCopy CopyRegion; - CopyRegion.srcOffset = SrcOffset + pSrcBuffVk->GetDynamicOffset(m_ContextId, this); - CopyRegion.dstOffset = DstOffset; - CopyRegion.size = Size; - VERIFY(pDstBuffVk->m_VulkanBuffer != VK_NULL_HANDLE, "Copy destination buffer must not be suballocated"); - VERIFY_EXPR(pDstBuffVk->GetDynamicOffset(m_ContextId, this) == 0); - m_CommandBuffer.CopyBuffer(pSrcBuffVk->GetVkBuffer(), pDstBuffVk->GetVkBuffer(), 1, &CopyRegion); - ++m_State.NumCommands; - } +void DeviceContextVkImpl::MapBuffer(IBuffer* pBuffer, MAP_TYPE MapType, MAP_FLAGS MapFlags, PVoid& pMappedData) +{ + TDeviceContextBase::MapBuffer(pBuffer, MapType, MapFlags, pMappedData); + auto* pBufferVk = ValidatedCast(pBuffer); + const auto& BuffDesc = pBufferVk->GetDesc(); - void DeviceContextVkImpl::MapBuffer(IBuffer* pBuffer, MAP_TYPE MapType, MAP_FLAGS MapFlags, PVoid& pMappedData) + if (MapType == MAP_READ) { - TDeviceContextBase::MapBuffer(pBuffer, MapType, MapFlags, pMappedData); - auto* pBufferVk = ValidatedCast(pBuffer); - const auto& BuffDesc = pBufferVk->GetDesc(); - - if (MapType == MAP_READ ) + LOG_ERROR("Mapping buffer for reading is not yet imlemented in Vulkan backend"); + UNSUPPORTED("Mapping buffer for reading is not yet imlemented in Vulkan backend"); + } + else if (MapType == MAP_WRITE) + { + if (BuffDesc.Usage == USAGE_STAGING) { - LOG_ERROR("Mapping buffer for reading is not yet imlemented in Vulkan backend"); - UNSUPPORTED("Mapping buffer for reading is not yet imlemented in Vulkan backend"); + LOG_ERROR("Not implemented"); + UNSUPPORTED("Not implemented"); } - else if(MapType == MAP_WRITE) + else if (BuffDesc.Usage == USAGE_DYNAMIC) { - if (BuffDesc.Usage == USAGE_STAGING) + DEV_CHECK_ERR((MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0, "Failed to map buffer '", + BuffDesc.Name, "': Vk buffer must be mapped for writing with MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE flag. Context Id: ", m_ContextId); + + auto& DynAllocation = pBufferVk->m_DynamicAllocations[m_ContextId]; + if ((MapFlags & MAP_FLAG_DISCARD) != 0 || DynAllocation.pDynamicMemMgr == nullptr) { - LOG_ERROR("Not implemented"); - UNSUPPORTED("Not implemented"); + DynAllocation = AllocateDynamicSpace(BuffDesc.uiSizeInBytes, pBufferVk->m_DynamicOffsetAlignment); } - else if (BuffDesc.Usage == USAGE_DYNAMIC) + else { - DEV_CHECK_ERR((MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0, "Failed to map buffer '", - BuffDesc.Name, "': Vk buffer must be mapped for writing with MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE flag. Context Id: ", m_ContextId); - - auto& DynAllocation = pBufferVk->m_DynamicAllocations[m_ContextId]; - if ( (MapFlags & MAP_FLAG_DISCARD) != 0 || DynAllocation.pDynamicMemMgr == nullptr ) - { - DynAllocation = AllocateDynamicSpace(BuffDesc.uiSizeInBytes, pBufferVk->m_DynamicOffsetAlignment); - } - else - { - VERIFY_EXPR(MapFlags & MAP_FLAG_DO_NOT_SYNCHRONIZE); - // Reuse the same allocation - } - - if (DynAllocation.pDynamicMemMgr != nullptr) - { - auto* CPUAddress = DynAllocation.pDynamicMemMgr->GetCPUAddress(); - pMappedData = CPUAddress + DynAllocation.AlignedOffset; - } - else - { - pMappedData = nullptr; - } + VERIFY_EXPR(MapFlags & MAP_FLAG_DO_NOT_SYNCHRONIZE); + // Reuse the same allocation + } + + if (DynAllocation.pDynamicMemMgr != nullptr) + { + auto* CPUAddress = DynAllocation.pDynamicMemMgr->GetCPUAddress(); + pMappedData = CPUAddress + DynAllocation.AlignedOffset; } else { - LOG_ERROR("Only USAGE_DYNAMIC and USAGE_STAGING Vk buffers can be mapped for writing"); + pMappedData = nullptr; } } - 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"); + LOG_ERROR("Only USAGE_DYNAMIC and USAGE_STAGING 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"); + } +} + +void DeviceContextVkImpl::UnmapBuffer(IBuffer* pBuffer, MAP_TYPE MapType) +{ + TDeviceContextBase::UnmapBuffer(pBuffer, MapType); + auto* pBufferVk = ValidatedCast(pBuffer); + const auto& BuffDesc = pBufferVk->GetDesc(); - void DeviceContextVkImpl::UnmapBuffer(IBuffer* pBuffer, MAP_TYPE MapType) + if (MapType == MAP_READ) + { + LOG_ERROR("This map type is not yet supported"); + UNSUPPORTED("This map type is not yet supported"); + } + else if (MapType == MAP_WRITE) { - TDeviceContextBase::UnmapBuffer(pBuffer, MapType); - auto* pBufferVk = ValidatedCast(pBuffer); - const auto& BuffDesc = pBufferVk->GetDesc(); - - if (MapType == MAP_READ ) + if (BuffDesc.Usage == USAGE_STAGING) { LOG_ERROR("This map type is not yet supported"); UNSUPPORTED("This map type is not yet supported"); } - else if(MapType == MAP_WRITE) + else if (BuffDesc.Usage == USAGE_DYNAMIC) { - if (BuffDesc.Usage == USAGE_STAGING) - { - LOG_ERROR("This map type is not yet supported"); - UNSUPPORTED("This map type is not yet supported"); - } - else if (BuffDesc.Usage == USAGE_DYNAMIC) + if (pBufferVk->m_VulkanBuffer != VK_NULL_HANDLE) { - if (pBufferVk->m_VulkanBuffer != VK_NULL_HANDLE) - { - auto& DynAlloc = pBufferVk->m_DynamicAllocations[m_ContextId]; - auto vkSrcBuff = DynAlloc.pDynamicMemMgr->GetVkBuffer(); - UpdateBufferRegion(pBufferVk, 0, BuffDesc.uiSizeInBytes, vkSrcBuff, DynAlloc.AlignedOffset, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - } + auto& DynAlloc = pBufferVk->m_DynamicAllocations[m_ContextId]; + auto vkSrcBuff = DynAlloc.pDynamicMemMgr->GetVkBuffer(); + UpdateBufferRegion(pBufferVk, 0, BuffDesc.uiSizeInBytes, vkSrcBuff, DynAlloc.AlignedOffset, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); } } } +} - void DeviceContextVkImpl::UpdateTexture(ITexture* pTexture, - Uint32 MipLevel, - Uint32 Slice, - const Box& DstBox, - const TextureSubResData& SubresData, - RESOURCE_STATE_TRANSITION_MODE SrcBufferStateTransitionMode, - RESOURCE_STATE_TRANSITION_MODE TextureStateTransitionModee) - { - TDeviceContextBase::UpdateTexture( pTexture, MipLevel, Slice, DstBox, SubresData, SrcBufferStateTransitionMode, TextureStateTransitionModee ); +void DeviceContextVkImpl::UpdateTexture(ITexture* pTexture, + Uint32 MipLevel, + Uint32 Slice, + const Box& DstBox, + const TextureSubResData& SubresData, + RESOURCE_STATE_TRANSITION_MODE SrcBufferStateTransitionMode, + RESOURCE_STATE_TRANSITION_MODE TextureStateTransitionModee) +{ + TDeviceContextBase::UpdateTexture(pTexture, MipLevel, Slice, DstBox, SubresData, SrcBufferStateTransitionMode, TextureStateTransitionModee); - auto* pTexVk = ValidatedCast(pTexture); - // OpenGL backend uses UpdateData() to initialize textures, so we can't check the usage in ValidateUpdateTextureParams() - DEV_CHECK_ERR( pTexVk->GetDesc().Usage == USAGE_DEFAULT, "Only USAGE_DEFAULT textures should be updated with UpdateData()" ); + auto* pTexVk = ValidatedCast(pTexture); + // OpenGL backend uses UpdateData() to initialize textures, so we can't check the usage in ValidateUpdateTextureParams() + DEV_CHECK_ERR(pTexVk->GetDesc().Usage == USAGE_DEFAULT, "Only USAGE_DEFAULT textures should be updated with UpdateData()"); - if (SubresData.pSrcBuffer != nullptr) - { - UNSUPPORTED("Copying buffer to texture is not implemented"); - } - else - { - UpdateTextureRegion(SubresData.pData, SubresData.Stride, SubresData.DepthStride, *pTexVk, - MipLevel, Slice, DstBox, TextureStateTransitionModee); - } + if (SubresData.pSrcBuffer != nullptr) + { + UNSUPPORTED("Copying buffer to texture is not implemented"); } - - void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) + else { - TDeviceContextBase::CopyTexture( CopyAttribs ); + UpdateTextureRegion(SubresData.pData, SubresData.Stride, SubresData.DepthStride, *pTexVk, + MipLevel, Slice, DstBox, TextureStateTransitionModee); + } +} - auto* pSrcTexVk = ValidatedCast( CopyAttribs.pSrcTexture ); - auto* pDstTexVk = ValidatedCast( CopyAttribs.pDstTexture ); - const auto& SrcTexDesc = pSrcTexVk->GetDesc(); - const auto& DstTexDesc = pDstTexVk->GetDesc(); - auto* pSrcBox = CopyAttribs.pSrcBox; - Box FullMipBox; - if (pSrcBox == nullptr) - { - auto MipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); - FullMipBox.MaxX = MipLevelAttribs.LogicalWidth; - FullMipBox.MaxY = MipLevelAttribs.LogicalHeight; - FullMipBox.MaxZ = MipLevelAttribs.Depth; - pSrcBox = &FullMipBox; - } - const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); - const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); - if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) - { - VkImageCopy CopyRegion = {}; - CopyRegion.srcOffset.x = pSrcBox->MinX; - CopyRegion.srcOffset.y = pSrcBox->MinY; - CopyRegion.srcOffset.z = pSrcBox->MinZ; - CopyRegion.extent.width = pSrcBox->MaxX - pSrcBox->MinX; - CopyRegion.extent.height = std::max(pSrcBox->MaxY - pSrcBox->MinY, 1u); - CopyRegion.extent.depth = std::max(pSrcBox->MaxZ - pSrcBox->MinZ, 1u); - - VkImageAspectFlags aspectMask = 0; - if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) - { - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } - else - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - CopyRegion.srcSubresource.baseArrayLayer = CopyAttribs.SrcSlice; - CopyRegion.srcSubresource.layerCount = 1; - CopyRegion.srcSubresource.mipLevel = CopyAttribs.SrcMipLevel; - CopyRegion.srcSubresource.aspectMask = aspectMask; - - CopyRegion.dstSubresource.baseArrayLayer = CopyAttribs.DstSlice; - CopyRegion.dstSubresource.layerCount = 1; - CopyRegion.dstSubresource.mipLevel = CopyAttribs.DstMipLevel; - CopyRegion.dstSubresource.aspectMask = aspectMask; - - CopyRegion.dstOffset.x = CopyAttribs.DstX; - CopyRegion.dstOffset.y = CopyAttribs.DstY; - CopyRegion.dstOffset.z = CopyAttribs.DstZ; - - CopyTextureRegion(pSrcTexVk, CopyAttribs.SrcTextureTransitionMode, pDstTexVk, CopyAttribs.DstTextureTransitionMode, CopyRegion); - } - else if (SrcTexDesc.Usage == USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) - { - DEV_CHECK_ERR((SrcTexDesc.CPUAccessFlags & CPU_ACCESS_WRITE), "Attempting to copy from staging texture that was not created with CPU_ACCESS_WRITE flag"); - DEV_CHECK_ERR(pSrcTexVk->GetState() == RESOURCE_STATE_COPY_SOURCE, "Source staging texture must permanently be in RESOURCE_STATE_COPY_SOURCE state"); - - auto SrcBufferOffset = GetStagingDataOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel); - auto SrcMipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); - // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) - SrcBufferOffset += - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (pSrcBox->MinZ * SrcMipLevelAttribs.StorageHeight + pSrcBox->MinY) / SrcFmtAttribs.BlockHeight * SrcMipLevelAttribs.RowSize + - // For non-compressed formats, BlockWidth is 1. - (pSrcBox->MinX / SrcFmtAttribs.BlockWidth) * SrcFmtAttribs.GetElementSize(); - - Box DstBox; - DstBox.MinX = CopyAttribs.DstX; - DstBox.MinY = CopyAttribs.DstY; - DstBox.MinZ = CopyAttribs.DstZ; - DstBox.MaxX = DstBox.MinX + pSrcBox->MaxX - pSrcBox->MinX; - DstBox.MaxY = DstBox.MinY + pSrcBox->MaxY - pSrcBox->MinY; - DstBox.MaxZ = DstBox.MinZ + pSrcBox->MaxZ - pSrcBox->MinZ; - - CopyBufferToTexture( - pSrcTexVk->GetVkStagingBuffer(), - SrcBufferOffset, - SrcMipLevelAttribs.StorageWidth, - *pDstTexVk, - DstBox, - CopyAttribs.DstMipLevel, - CopyAttribs.DstSlice, - CopyAttribs.DstTextureTransitionMode - ); - } - else if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage == USAGE_STAGING) - { - DEV_CHECK_ERR((DstTexDesc.CPUAccessFlags & CPU_ACCESS_READ), "Attempting to copy to staging texture that was not created with CPU_ACCESS_READ flag"); - DEV_CHECK_ERR(pDstTexVk->GetState() == RESOURCE_STATE_COPY_DEST, "Destination staging texture must permanently be in RESOURCE_STATE_COPY_DEST state"); - - auto DstBufferOffset = GetStagingDataOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel); - auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); - // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) - DstBufferOffset += - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (CopyAttribs.DstZ * DstMipLevelAttribs.StorageHeight + CopyAttribs.DstY) / DstFmtAttribs.BlockHeight * DstMipLevelAttribs.RowSize * - // For non-compressed formats, BlockWidth is 1. - (CopyAttribs.DstX / DstFmtAttribs.BlockWidth) * DstFmtAttribs.GetElementSize(); - - CopyTextureToBuffer( - *pSrcTexVk, - *pSrcBox, - CopyAttribs.SrcMipLevel, - CopyAttribs.SrcSlice, - CopyAttribs.SrcTextureTransitionMode, - pDstTexVk->GetVkStagingBuffer(), - DstBufferOffset, - DstMipLevelAttribs.StorageWidth - ); +void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) +{ + TDeviceContextBase::CopyTexture(CopyAttribs); + + auto* pSrcTexVk = ValidatedCast(CopyAttribs.pSrcTexture); + auto* pDstTexVk = ValidatedCast(CopyAttribs.pDstTexture); + const auto& SrcTexDesc = pSrcTexVk->GetDesc(); + const auto& DstTexDesc = pDstTexVk->GetDesc(); + auto* pSrcBox = CopyAttribs.pSrcBox; + Box FullMipBox; + if (pSrcBox == nullptr) + { + auto MipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); + FullMipBox.MaxX = MipLevelAttribs.LogicalWidth; + FullMipBox.MaxY = MipLevelAttribs.LogicalHeight; + FullMipBox.MaxZ = MipLevelAttribs.Depth; + pSrcBox = &FullMipBox; + } + const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); + const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); + if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) + { + VkImageCopy CopyRegion = {}; + + CopyRegion.srcOffset.x = pSrcBox->MinX; + CopyRegion.srcOffset.y = pSrcBox->MinY; + CopyRegion.srcOffset.z = pSrcBox->MinZ; + CopyRegion.extent.width = pSrcBox->MaxX - pSrcBox->MinX; + CopyRegion.extent.height = std::max(pSrcBox->MaxY - pSrcBox->MinY, 1u); + CopyRegion.extent.depth = std::max(pSrcBox->MaxZ - pSrcBox->MinZ, 1u); + + VkImageAspectFlags aspectMask = 0; + if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; } else - { - UNSUPPORTED("Copying data between staging textures is not supported and is likely not want you really want to do"); - } + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + CopyRegion.srcSubresource.baseArrayLayer = CopyAttribs.SrcSlice; + CopyRegion.srcSubresource.layerCount = 1; + CopyRegion.srcSubresource.mipLevel = CopyAttribs.SrcMipLevel; + CopyRegion.srcSubresource.aspectMask = aspectMask; + + CopyRegion.dstSubresource.baseArrayLayer = CopyAttribs.DstSlice; + CopyRegion.dstSubresource.layerCount = 1; + CopyRegion.dstSubresource.mipLevel = CopyAttribs.DstMipLevel; + CopyRegion.dstSubresource.aspectMask = aspectMask; + + CopyRegion.dstOffset.x = CopyAttribs.DstX; + CopyRegion.dstOffset.y = CopyAttribs.DstY; + CopyRegion.dstOffset.z = CopyAttribs.DstZ; + + CopyTextureRegion(pSrcTexVk, CopyAttribs.SrcTextureTransitionMode, pDstTexVk, CopyAttribs.DstTextureTransitionMode, CopyRegion); + } + else if (SrcTexDesc.Usage == USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) + { + DEV_CHECK_ERR((SrcTexDesc.CPUAccessFlags & CPU_ACCESS_WRITE), "Attempting to copy from staging texture that was not created with CPU_ACCESS_WRITE flag"); + DEV_CHECK_ERR(pSrcTexVk->GetState() == RESOURCE_STATE_COPY_SOURCE, "Source staging texture must permanently be in RESOURCE_STATE_COPY_SOURCE state"); + + auto SrcBufferOffset = GetStagingDataOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel); + auto SrcMipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); + // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) + SrcBufferOffset += + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (pSrcBox->MinZ * SrcMipLevelAttribs.StorageHeight + pSrcBox->MinY) / SrcFmtAttribs.BlockHeight * SrcMipLevelAttribs.RowSize + + // For non-compressed formats, BlockWidth is 1. + (pSrcBox->MinX / SrcFmtAttribs.BlockWidth) * SrcFmtAttribs.GetElementSize(); + + Box DstBox; + DstBox.MinX = CopyAttribs.DstX; + DstBox.MinY = CopyAttribs.DstY; + DstBox.MinZ = CopyAttribs.DstZ; + DstBox.MaxX = DstBox.MinX + pSrcBox->MaxX - pSrcBox->MinX; + DstBox.MaxY = DstBox.MinY + pSrcBox->MaxY - pSrcBox->MinY; + DstBox.MaxZ = DstBox.MinZ + pSrcBox->MaxZ - pSrcBox->MinZ; + + CopyBufferToTexture( + pSrcTexVk->GetVkStagingBuffer(), + SrcBufferOffset, + SrcMipLevelAttribs.StorageWidth, + *pDstTexVk, + DstBox, + CopyAttribs.DstMipLevel, + CopyAttribs.DstSlice, + CopyAttribs.DstTextureTransitionMode); + } + else if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage == USAGE_STAGING) + { + DEV_CHECK_ERR((DstTexDesc.CPUAccessFlags & CPU_ACCESS_READ), "Attempting to copy to staging texture that was not created with CPU_ACCESS_READ flag"); + DEV_CHECK_ERR(pDstTexVk->GetState() == RESOURCE_STATE_COPY_DEST, "Destination staging texture must permanently be in RESOURCE_STATE_COPY_DEST state"); + + auto DstBufferOffset = GetStagingDataOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel); + auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); + // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) + DstBufferOffset += + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (CopyAttribs.DstZ * DstMipLevelAttribs.StorageHeight + CopyAttribs.DstY) / DstFmtAttribs.BlockHeight * DstMipLevelAttribs.RowSize * + // For non-compressed formats, BlockWidth is 1. + (CopyAttribs.DstX / DstFmtAttribs.BlockWidth) * DstFmtAttribs.GetElementSize(); + + CopyTextureToBuffer( + *pSrcTexVk, + *pSrcBox, + CopyAttribs.SrcMipLevel, + CopyAttribs.SrcSlice, + CopyAttribs.SrcTextureTransitionMode, + pDstTexVk->GetVkStagingBuffer(), + DstBufferOffset, + DstMipLevelAttribs.StorageWidth); + } + else + { + UNSUPPORTED("Copying data between staging textures is not supported and is likely not want you really want to do"); } +} - void DeviceContextVkImpl::CopyTextureRegion(TextureVkImpl* pSrcTexture, - RESOURCE_STATE_TRANSITION_MODE SrcTextureTransitionMode, - TextureVkImpl* pDstTexture, - RESOURCE_STATE_TRANSITION_MODE DstTextureTransitionMode, - const VkImageCopy& CopyRegion) - { - EnsureVkCmdBuffer(); - TransitionOrVerifyTextureState(*pSrcTexture, SrcTextureTransitionMode, RESOURCE_STATE_COPY_SOURCE, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - "Using texture as transfer source (DeviceContextVkImpl::CopyTextureRegion)"); - TransitionOrVerifyTextureState(*pDstTexture, DstTextureTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - "Using texture as transfer destination (DeviceContextVkImpl::CopyTextureRegion)"); - - // srcImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL - // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.3) - m_CommandBuffer.CopyImage(pSrcTexture->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, pDstTexture->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &CopyRegion); - ++m_State.NumCommands; - } - - DeviceContextVkImpl::BufferToTextureCopyInfo DeviceContextVkImpl::GetBufferToTextureCopyInfo( - const TextureDesc& TexDesc, - Uint32 MipLevel, - const Box& Region)const - { - BufferToTextureCopyInfo CopyInfo; - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - VERIFY_EXPR(Region.MaxX > Region.MinX && Region.MaxY > Region.MinY && Region.MaxZ > Region.MinZ); - auto UpdateRegionWidth = Region.MaxX - Region.MinX; - auto UpdateRegionHeight = Region.MaxY - Region.MinY; - auto UpdateRegionDepth = Region.MaxZ - Region.MinZ; - if(FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - // Align update region size by the block size. This is only necessary when updating - // coarse mip levels. Otherwise UpdateRegionWidth/Height should be multiples of block size - VERIFY_EXPR( (FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth-1)) == 0 ); - VERIFY_EXPR( (FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0 ); - const auto BlockAlignedRegionWidth = (UpdateRegionWidth + (FmtAttribs.BlockWidth-1)) & ~(FmtAttribs.BlockWidth -1); - const auto BlockAlignedRegionHeight = (UpdateRegionHeight + (FmtAttribs.BlockHeight-1)) & ~(FmtAttribs.BlockHeight-1); - CopyInfo.RowSize = BlockAlignedRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize}; - CopyInfo.RowCount = BlockAlignedRegionHeight / FmtAttribs.BlockHeight; - - // (imageExtent.width + imageOffset.x) must be less than or equal to the image subresource width, and - // (imageExtent.height + imageOffset.y) must be less than or equal to the image subresource height (18.4), - // so we need to clamp UpdateRegionWidth and Height - const Uint32 MipWidth = std::max(TexDesc.Width >> MipLevel, 1u); - const Uint32 MipHeight = std::max(TexDesc.Height >> MipLevel, 1u); - VERIFY_EXPR(MipWidth > Region.MinX); - UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - Region.MinX); - VERIFY_EXPR(MipHeight > Region.MinY); - UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - Region.MinY); - } - else - { - CopyInfo.RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}; - CopyInfo.RowCount = UpdateRegionHeight; - } - - const auto& DeviceLimits = m_pDevice->GetPhysicalDevice().GetProperties().limits; - CopyInfo.Stride = Align(CopyInfo.RowSize, static_cast(DeviceLimits.optimalBufferCopyRowPitchAlignment)); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - // If the calling command's VkImage parameter is a compressed image, - // bufferRowLength must be a multiple of the compressed texel block width - // In texels (not even in compressed blocks!) - CopyInfo.StrideInTexels = CopyInfo.Stride / Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.BlockWidth}; - } - else - { - CopyInfo.StrideInTexels = CopyInfo.Stride / (Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}); - } - CopyInfo.DepthStride = CopyInfo.RowCount * CopyInfo.Stride; - CopyInfo.MemorySize = UpdateRegionDepth * CopyInfo.DepthStride; - CopyInfo.Region = Region; - return CopyInfo; - } +void DeviceContextVkImpl::CopyTextureRegion(TextureVkImpl* pSrcTexture, + RESOURCE_STATE_TRANSITION_MODE SrcTextureTransitionMode, + TextureVkImpl* pDstTexture, + RESOURCE_STATE_TRANSITION_MODE DstTextureTransitionMode, + const VkImageCopy& CopyRegion) +{ + EnsureVkCmdBuffer(); + TransitionOrVerifyTextureState(*pSrcTexture, SrcTextureTransitionMode, RESOURCE_STATE_COPY_SOURCE, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + "Using texture as transfer source (DeviceContextVkImpl::CopyTextureRegion)"); + TransitionOrVerifyTextureState(*pDstTexture, DstTextureTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + "Using texture as transfer destination (DeviceContextVkImpl::CopyTextureRegion)"); + + // srcImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL + // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.3) + m_CommandBuffer.CopyImage(pSrcTexture->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, pDstTexture->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &CopyRegion); + ++m_State.NumCommands; +} +DeviceContextVkImpl::BufferToTextureCopyInfo DeviceContextVkImpl::GetBufferToTextureCopyInfo( + const TextureDesc& TexDesc, + Uint32 MipLevel, + const Box& Region) const +{ + BufferToTextureCopyInfo CopyInfo; + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + VERIFY_EXPR(Region.MaxX > Region.MinX && Region.MaxY > Region.MinY && Region.MaxZ > Region.MinZ); + auto UpdateRegionWidth = Region.MaxX - Region.MinX; + auto UpdateRegionHeight = Region.MaxY - Region.MinY; + auto UpdateRegionDepth = Region.MaxZ - Region.MinZ; + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + // Align update region size by the block size. This is only necessary when updating + // coarse mip levels. Otherwise UpdateRegionWidth/Height should be multiples of block size + VERIFY_EXPR((FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth - 1)) == 0); + VERIFY_EXPR((FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight - 1)) == 0); + const auto BlockAlignedRegionWidth = (UpdateRegionWidth + (FmtAttribs.BlockWidth - 1)) & ~(FmtAttribs.BlockWidth - 1); + const auto BlockAlignedRegionHeight = (UpdateRegionHeight + (FmtAttribs.BlockHeight - 1)) & ~(FmtAttribs.BlockHeight - 1); + CopyInfo.RowSize = BlockAlignedRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize}; + CopyInfo.RowCount = BlockAlignedRegionHeight / FmtAttribs.BlockHeight; + + // (imageExtent.width + imageOffset.x) must be less than or equal to the image subresource width, and + // (imageExtent.height + imageOffset.y) must be less than or equal to the image subresource height (18.4), + // so we need to clamp UpdateRegionWidth and Height + const Uint32 MipWidth = std::max(TexDesc.Width >> MipLevel, 1u); + const Uint32 MipHeight = std::max(TexDesc.Height >> MipLevel, 1u); + VERIFY_EXPR(MipWidth > Region.MinX); + UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - Region.MinX); + VERIFY_EXPR(MipHeight > Region.MinY); + UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - Region.MinY); + } + else + { + CopyInfo.RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}; + CopyInfo.RowCount = UpdateRegionHeight; + } + + const auto& DeviceLimits = m_pDevice->GetPhysicalDevice().GetProperties().limits; + CopyInfo.Stride = Align(CopyInfo.RowSize, static_cast(DeviceLimits.optimalBufferCopyRowPitchAlignment)); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + // If the calling command's VkImage parameter is a compressed image, + // bufferRowLength must be a multiple of the compressed texel block width + // In texels (not even in compressed blocks!) + CopyInfo.StrideInTexels = CopyInfo.Stride / Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.BlockWidth}; + } + else + { + CopyInfo.StrideInTexels = CopyInfo.Stride / (Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}); + } + CopyInfo.DepthStride = CopyInfo.RowCount * CopyInfo.Stride; + CopyInfo.MemorySize = UpdateRegionDepth * CopyInfo.DepthStride; + CopyInfo.Region = Region; + return CopyInfo; +} - void DeviceContextVkImpl::UpdateTextureRegion(const void* pSrcData, - Uint32 SrcStride, - Uint32 SrcDepthStride, - TextureVkImpl& TextureVk, - Uint32 MipLevel, - Uint32 Slice, - const Box& DstBox, - RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode) - { - const auto& TexDesc = TextureVk.GetDesc(); - VERIFY(TexDesc.SampleCount == 1, "Only single-sample textures can be updated with vkCmdCopyBufferToImage()"); - auto CopyInfo = GetBufferToTextureCopyInfo(TexDesc, MipLevel, DstBox); - const auto UpdateRegionDepth = CopyInfo.Region.MaxZ - CopyInfo.Region.MinZ; - // For UpdateTextureRegion(), use UploadHeap, not dynamic heap - const auto& DeviceLimits = m_pDevice->GetPhysicalDevice().GetProperties().limits; - // Source buffer offset must be multiple of 4 (18.4) - auto BufferOffsetAlignment = std::max(DeviceLimits.optimalBufferCopyOffsetAlignment, VkDeviceSize{4}); - // If the calling command's VkImage parameter is a compressed image, bufferOffset must be a multiple of - // the compressed texel block size in bytes (18.4) - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - BufferOffsetAlignment = std::max(BufferOffsetAlignment, VkDeviceSize{FmtAttribs.ComponentSize}); - } - auto Allocation = m_UploadHeap.Allocate(CopyInfo.MemorySize, BufferOffsetAlignment); - // The allocation will stay in the upload heap until the end of the frame at which point all upload - // pages will be discarded - VERIFY( (Allocation.AlignedOffset % BufferOffsetAlignment) == 0, "Allocation offset must be at least 32-bit algined"); +void DeviceContextVkImpl::UpdateTextureRegion(const void* pSrcData, + Uint32 SrcStride, + Uint32 SrcDepthStride, + TextureVkImpl& TextureVk, + Uint32 MipLevel, + Uint32 Slice, + const Box& DstBox, + RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode) +{ + const auto& TexDesc = TextureVk.GetDesc(); + VERIFY(TexDesc.SampleCount == 1, "Only single-sample textures can be updated with vkCmdCopyBufferToImage()"); + auto CopyInfo = GetBufferToTextureCopyInfo(TexDesc, MipLevel, DstBox); + const auto UpdateRegionDepth = CopyInfo.Region.MaxZ - CopyInfo.Region.MinZ; + + // For UpdateTextureRegion(), use UploadHeap, not dynamic heap + const auto& DeviceLimits = m_pDevice->GetPhysicalDevice().GetProperties().limits; + // Source buffer offset must be multiple of 4 (18.4) + auto BufferOffsetAlignment = std::max(DeviceLimits.optimalBufferCopyOffsetAlignment, VkDeviceSize{4}); + // If the calling command's VkImage parameter is a compressed image, bufferOffset must be a multiple of + // the compressed texel block size in bytes (18.4) + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + BufferOffsetAlignment = std::max(BufferOffsetAlignment, VkDeviceSize{FmtAttribs.ComponentSize}); + } + auto Allocation = m_UploadHeap.Allocate(CopyInfo.MemorySize, BufferOffsetAlignment); + // The allocation will stay in the upload heap until the end of the frame at which point all upload + // pages will be discarded + VERIFY((Allocation.AlignedOffset % BufferOffsetAlignment) == 0, "Allocation offset must be at least 32-bit algined"); #ifdef _DEBUG - { - VERIFY(SrcStride >= CopyInfo.RowSize, "Source data stride (", SrcStride, ") is below the image row size (", CopyInfo.RowSize, ")"); - const Uint32 PlaneSize = SrcStride * CopyInfo.RowCount; - VERIFY(UpdateRegionDepth == 1 || SrcDepthStride >= PlaneSize, "Source data depth stride (", SrcDepthStride, ") is below the image plane size (", PlaneSize, ")"); - } -#endif - for(Uint32 DepthSlice = 0; DepthSlice < UpdateRegionDepth; ++DepthSlice) - { - for(Uint32 row = 0; row < CopyInfo.RowCount; ++row) - { - const auto* pSrcPtr = - reinterpret_cast(pSrcData) - + row * SrcStride - + DepthSlice * SrcDepthStride; - auto* pDstPtr = - reinterpret_cast(Allocation.CPUAddress) - + row * CopyInfo.Stride - + DepthSlice * CopyInfo.DepthStride; - - memcpy(pDstPtr, pSrcPtr, CopyInfo.RowSize); - } - } - CopyBufferToTexture(Allocation.vkBuffer, - static_cast(Allocation.AlignedOffset), - CopyInfo.StrideInTexels, - TextureVk, - CopyInfo.Region, - MipLevel, - Slice, - TextureTransitionMode); - } - - void DeviceContextVkImpl::GenerateMips(ITextureView* pTexView) { - TDeviceContextBase::GenerateMips(pTexView); - m_GenerateMipsHelper->GenerateMips(*ValidatedCast(pTexView), *this, *m_GenerateMipsSRB); + VERIFY(SrcStride >= CopyInfo.RowSize, "Source data stride (", SrcStride, ") is below the image row size (", CopyInfo.RowSize, ")"); + const Uint32 PlaneSize = SrcStride * CopyInfo.RowCount; + VERIFY(UpdateRegionDepth == 1 || SrcDepthStride >= PlaneSize, "Source data depth stride (", SrcDepthStride, ") is below the image plane size (", PlaneSize, ")"); } +#endif + for (Uint32 DepthSlice = 0; DepthSlice < UpdateRegionDepth; ++DepthSlice) + { + for (Uint32 row = 0; row < CopyInfo.RowCount; ++row) + { + // clang-format off + const auto* pSrcPtr = + reinterpret_cast(pSrcData) + + row * SrcStride + + DepthSlice * SrcDepthStride; + auto* pDstPtr = + reinterpret_cast(Allocation.CPUAddress) + + row * CopyInfo.Stride + + DepthSlice * CopyInfo.DepthStride; + // clang-format on + + memcpy(pDstPtr, pSrcPtr, CopyInfo.RowSize); + } + } + CopyBufferToTexture(Allocation.vkBuffer, + static_cast(Allocation.AlignedOffset), + CopyInfo.StrideInTexels, + TextureVk, + CopyInfo.Region, + MipLevel, + Slice, + TextureTransitionMode); +} - static VkBufferImageCopy GetBufferImageCopyInfo(Uint32 BufferOffset, - Uint32 BufferRowStrideInTexels, - const TextureDesc& TexDesc, - const Box& Region, - Uint32 MipLevel, - Uint32 ArraySlice) - { - VkBufferImageCopy CopyRegion = {}; - VERIFY( (BufferOffset % 4) == 0, "Source buffer offset must be multiple of 4 (18.4)"); - CopyRegion.bufferOffset = BufferOffset; // must be a multiple of 4 (18.4) +void DeviceContextVkImpl::GenerateMips(ITextureView* pTexView) +{ + TDeviceContextBase::GenerateMips(pTexView); + m_GenerateMipsHelper->GenerateMips(*ValidatedCast(pTexView), *this, *m_GenerateMipsSRB); +} - // bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion of a larger two- or - // three-dimensional image, and control the addressing calculations of data in buffer memory. If either of these - // values is zero, that aspect of the buffer memory is considered to be tightly packed according to the imageExtent (18.4). - CopyRegion.bufferRowLength = BufferRowStrideInTexels; - CopyRegion.bufferImageHeight = 0; +static VkBufferImageCopy GetBufferImageCopyInfo(Uint32 BufferOffset, + Uint32 BufferRowStrideInTexels, + const TextureDesc& TexDesc, + const Box& Region, + Uint32 MipLevel, + Uint32 ArraySlice) +{ + VkBufferImageCopy CopyRegion = {}; + VERIFY((BufferOffset % 4) == 0, "Source buffer offset must be multiple of 4 (18.4)"); + CopyRegion.bufferOffset = BufferOffset; // must be a multiple of 4 (18.4) + + // bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion of a larger two- or + // three-dimensional image, and control the addressing calculations of data in buffer memory. If either of these + // values is zero, that aspect of the buffer memory is considered to be tightly packed according to the imageExtent (18.4). + CopyRegion.bufferRowLength = BufferRowStrideInTexels; + CopyRegion.bufferImageHeight = 0; + + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + // The aspectMask member of imageSubresource must only have a single bit set (18.4) + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + UNSUPPORTED("Updating depth-stencil texture is not currently supported"); + // When copying to or from a depth or stencil aspect, the data in buffer memory uses a layout + // that is a (mostly) tightly packed representation of the depth or stencil data. + // To copy both the depth and stencil aspects of a depth/stencil format, two entries in + // pRegions can be used, where one specifies the depth aspect in imageSubresource, and the + // other specifies the stencil aspect (18.4) + } + else + CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + CopyRegion.imageSubresource.baseArrayLayer = ArraySlice; + CopyRegion.imageSubresource.layerCount = 1; + CopyRegion.imageSubresource.mipLevel = MipLevel; + // - imageOffset.x and (imageExtent.width + imageOffset.x) must both be greater than or equal to 0 and + // less than or equal to the image subresource width (18.4) + // - imageOffset.y and (imageExtent.height + imageOffset.y) must both be greater than or equal to 0 and + // less than or equal to the image subresource height (18.4) + CopyRegion.imageOffset = + VkOffset3D // + { + static_cast(Region.MinX), + static_cast(Region.MinY), + static_cast(Region.MinZ) // + }; + VERIFY(Region.MaxX > Region.MinX && Region.MaxY - Region.MinY && Region.MaxZ > Region.MinZ, + "[", Region.MinX, " .. ", Region.MaxX, ") x [", Region.MinY, " .. ", Region.MaxY, ") x [", Region.MinZ, " .. ", Region.MaxZ, ") is not a vaild region"); + CopyRegion.imageExtent = + VkExtent3D // + { + static_cast(Region.MaxX - Region.MinX), + static_cast(Region.MaxY - Region.MinY), + static_cast(Region.MaxZ - Region.MinZ) // + }; - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - // The aspectMask member of imageSubresource must only have a single bit set (18.4) - if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) - CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) - { - UNSUPPORTED("Updating depth-stencil texture is not currently supported"); - // When copying to or from a depth or stencil aspect, the data in buffer memory uses a layout - // that is a (mostly) tightly packed representation of the depth or stencil data. - // To copy both the depth and stencil aspects of a depth/stencil format, two entries in - // pRegions can be used, where one specifies the depth aspect in imageSubresource, and the - // other specifies the stencil aspect (18.4) - } - else - CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - CopyRegion.imageSubresource.baseArrayLayer = ArraySlice; - CopyRegion.imageSubresource.layerCount = 1; - CopyRegion.imageSubresource.mipLevel = MipLevel; - // - imageOffset.x and (imageExtent.width + imageOffset.x) must both be greater than or equal to 0 and - // less than or equal to the image subresource width (18.4) - // - imageOffset.y and (imageExtent.height + imageOffset.y) must both be greater than or equal to 0 and - // less than or equal to the image subresource height (18.4) - CopyRegion.imageOffset = - VkOffset3D - { - static_cast(Region.MinX), - static_cast(Region.MinY), - static_cast(Region.MinZ) - }; - VERIFY(Region.MaxX > Region.MinX && Region.MaxY - Region.MinY && Region.MaxZ > Region.MinZ, - "[", Region.MinX, " .. ", Region.MaxX, ") x [", Region.MinY, " .. ", Region.MaxY, ") x [", Region.MinZ, " .. ", Region.MaxZ, ") is not a vaild region"); - CopyRegion.imageExtent = - VkExtent3D - { - static_cast(Region.MaxX - Region.MinX), - static_cast(Region.MaxY - Region.MinY), - static_cast(Region.MaxZ - Region.MinZ) - }; + return CopyRegion; +} - return CopyRegion; - } +void DeviceContextVkImpl::CopyBufferToTexture(VkBuffer vkSrcBuffer, + Uint32 SrcBufferOffset, + Uint32 SrcBufferRowStrideInTexels, + TextureVkImpl& DstTextureVk, + const Box& DstRegion, + Uint32 DstMipLevel, + Uint32 DstArraySlice, + RESOURCE_STATE_TRANSITION_MODE DstTextureTransitionMode) +{ + EnsureVkCmdBuffer(); + TransitionOrVerifyTextureState(DstTextureVk, DstTextureTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + "Using texture as copy destination (DeviceContextVkImpl::CopyBufferToTexture)"); + + const auto& TexDesc = DstTextureVk.GetDesc(); + VkBufferImageCopy BuffImgCopy = GetBufferImageCopyInfo(SrcBufferOffset, SrcBufferRowStrideInTexels, TexDesc, DstRegion, DstMipLevel, DstArraySlice); + + m_CommandBuffer.CopyBufferToImage( + vkSrcBuffer, + DstTextureVk.GetVkImage(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) + 1, + &BuffImgCopy); +} - void DeviceContextVkImpl::CopyBufferToTexture(VkBuffer vkSrcBuffer, - Uint32 SrcBufferOffset, - Uint32 SrcBufferRowStrideInTexels, - TextureVkImpl& DstTextureVk, - const Box& DstRegion, - Uint32 DstMipLevel, - Uint32 DstArraySlice, - RESOURCE_STATE_TRANSITION_MODE DstTextureTransitionMode) - { - EnsureVkCmdBuffer(); - TransitionOrVerifyTextureState(DstTextureVk, DstTextureTransitionMode, RESOURCE_STATE_COPY_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - "Using texture as copy destination (DeviceContextVkImpl::CopyBufferToTexture)"); +void DeviceContextVkImpl::CopyTextureToBuffer(TextureVkImpl& SrcTextureVk, + const Box& SrcRegion, + Uint32 SrcMipLevel, + Uint32 SrcArraySlice, + RESOURCE_STATE_TRANSITION_MODE SrcTextureTransitionMode, + VkBuffer vkDstBuffer, + Uint32 DstBufferOffset, + Uint32 DstBufferRowStrideInTexels) +{ + EnsureVkCmdBuffer(); + TransitionOrVerifyTextureState(SrcTextureVk, SrcTextureTransitionMode, RESOURCE_STATE_COPY_SOURCE, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + "Using texture as source destination (DeviceContextVkImpl::CopyTextureToBuffer)"); + + const auto& TexDesc = SrcTextureVk.GetDesc(); + VkBufferImageCopy BuffImgCopy = GetBufferImageCopyInfo(DstBufferOffset, DstBufferRowStrideInTexels, TexDesc, SrcRegion, SrcMipLevel, SrcArraySlice); + + m_CommandBuffer.CopyImageToBuffer( + SrcTextureVk.GetVkImage(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) + vkDstBuffer, + 1, + &BuffImgCopy); +} - const auto& TexDesc = DstTextureVk.GetDesc(); - VkBufferImageCopy BuffImgCopy = GetBufferImageCopyInfo(SrcBufferOffset, SrcBufferRowStrideInTexels, TexDesc, DstRegion, DstMipLevel, DstArraySlice); - m_CommandBuffer.CopyBufferToImage( - vkSrcBuffer, - DstTextureVk.GetVkImage(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) - 1, - &BuffImgCopy); - } +void DeviceContextVkImpl::MapTextureSubresource(ITexture* pTexture, + Uint32 MipLevel, + Uint32 ArraySlice, + MAP_TYPE MapType, + MAP_FLAGS MapFlags, + const Box* pMapRegion, + MappedTextureSubresource& MappedData) +{ + TDeviceContextBase::MapTextureSubresource(pTexture, MipLevel, ArraySlice, MapType, MapFlags, pMapRegion, MappedData); - void DeviceContextVkImpl::CopyTextureToBuffer(TextureVkImpl& SrcTextureVk, - const Box& SrcRegion, - Uint32 SrcMipLevel, - Uint32 SrcArraySlice, - RESOURCE_STATE_TRANSITION_MODE SrcTextureTransitionMode, - VkBuffer vkDstBuffer, - Uint32 DstBufferOffset, - Uint32 DstBufferRowStrideInTexels) - { - EnsureVkCmdBuffer(); - TransitionOrVerifyTextureState(SrcTextureVk, SrcTextureTransitionMode, RESOURCE_STATE_COPY_SOURCE, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - "Using texture as source destination (DeviceContextVkImpl::CopyTextureToBuffer)"); + TextureVkImpl& TextureVk = *ValidatedCast(pTexture); + const auto& TexDesc = TextureVk.GetDesc(); + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - const auto& TexDesc = SrcTextureVk.GetDesc(); - VkBufferImageCopy BuffImgCopy = GetBufferImageCopyInfo(DstBufferOffset, DstBufferRowStrideInTexels, TexDesc, SrcRegion, SrcMipLevel, SrcArraySlice); - - m_CommandBuffer.CopyImageToBuffer( - SrcTextureVk.GetVkImage(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) - vkDstBuffer, - 1, - &BuffImgCopy); + Box FullExtentBox; + if (pMapRegion == nullptr) + { + auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); + FullExtentBox.MaxX = MipLevelAttribs.LogicalWidth; + FullExtentBox.MaxY = MipLevelAttribs.LogicalHeight; + FullExtentBox.MaxZ = MipLevelAttribs.Depth; + pMapRegion = &FullExtentBox; } - - void DeviceContextVkImpl::MapTextureSubresource( ITexture* pTexture, - Uint32 MipLevel, - Uint32 ArraySlice, - MAP_TYPE MapType, - MAP_FLAGS MapFlags, - const Box* pMapRegion, - MappedTextureSubresource& MappedData ) + if (TexDesc.Usage == USAGE_DYNAMIC) { - TDeviceContextBase::MapTextureSubresource(pTexture, MipLevel, ArraySlice, MapType, MapFlags, pMapRegion, MappedData); + if (MapType != MAP_WRITE) + { + LOG_ERROR("Textures can currently only be mapped for writing in Vulkan backend"); + MappedData = MappedTextureSubresource{}; + return; + } - TextureVkImpl& TextureVk = *ValidatedCast(pTexture); - const auto& TexDesc = TextureVk.GetDesc(); - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + if ((MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0) + LOG_INFO_MESSAGE_ONCE("Mapping textures with flags MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE has no effect in Vulkan backend"); - Box FullExtentBox; - if (pMapRegion == nullptr) + auto CopyInfo = GetBufferToTextureCopyInfo(TexDesc, MipLevel, *pMapRegion); + const auto& DeviceLimits = m_pDevice->GetPhysicalDevice().GetProperties().limits; + // Source buffer offset must be multiple of 4 (18.4) + auto Alignment = std::max(DeviceLimits.optimalBufferCopyOffsetAlignment, VkDeviceSize{4}); + // If the calling command's VkImage parameter is a compressed image, bufferOffset must be a multiple of + // the compressed texel block size in bytes (18.4) + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) { - auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); - FullExtentBox.MaxX = MipLevelAttribs.LogicalWidth; - FullExtentBox.MaxY = MipLevelAttribs.LogicalHeight; - FullExtentBox.MaxZ = MipLevelAttribs.Depth; - pMapRegion = &FullExtentBox; + Alignment = std::max(Alignment, VkDeviceSize{FmtAttribs.ComponentSize}); } + auto Allocation = AllocateDynamicSpace(CopyInfo.MemorySize, static_cast(Alignment)); - if (TexDesc.Usage == USAGE_DYNAMIC) + MappedData.pData = reinterpret_cast(Allocation.pDynamicMemMgr->GetCPUAddress()) + Allocation.AlignedOffset; + MappedData.Stride = CopyInfo.Stride; + MappedData.DepthStride = CopyInfo.DepthStride; + + auto it = m_MappedTextures.emplace(MappedTextureKey{&TextureVk, MipLevel, ArraySlice}, MappedTexture{CopyInfo, std::move(Allocation)}); + if (!it.second) + LOG_ERROR_MESSAGE("Mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "' has already been mapped"); + } + else if (TexDesc.Usage == USAGE_STAGING) + { + if ((MapFlags & MAP_FLAG_DO_NOT_SYNCHRONIZE) == 0) { - if (MapType != MAP_WRITE) - { - LOG_ERROR("Textures can currently only be mapped for writing in Vulkan backend"); - MappedData = MappedTextureSubresource{}; - return; - } + LOG_WARNING_MESSAGE_ONCE("Mapping staging textures is never synchronized in Vulkan backend. " + "Application must use fences or other synchronization methods to explicitly synchronize " + "access and map texture with MAP_FLAG_DO_NOT_SYNCHRONIZE flag."); + } - if ((MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0) - LOG_INFO_MESSAGE_ONCE("Mapping textures with flags MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE has no effect in Vulkan backend"); - - auto CopyInfo = GetBufferToTextureCopyInfo(TexDesc, MipLevel, *pMapRegion); - const auto& DeviceLimits = m_pDevice->GetPhysicalDevice().GetProperties().limits; - // Source buffer offset must be multiple of 4 (18.4) - auto Alignment = std::max(DeviceLimits.optimalBufferCopyOffsetAlignment, VkDeviceSize{4}); - // If the calling command's VkImage parameter is a compressed image, bufferOffset must be a multiple of - // the compressed texel block size in bytes (18.4) - if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) - { - Alignment = std::max(Alignment, VkDeviceSize{FmtAttribs.ComponentSize}); - } - auto Allocation = AllocateDynamicSpace(CopyInfo.MemorySize, static_cast(Alignment)); + auto SubresourceOffset = GetStagingDataOffset(TexDesc, ArraySlice, MipLevel); + auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); + // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) + auto MapStartOffset = SubresourceOffset + + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (pMapRegion->MinZ * MipLevelAttribs.StorageHeight + pMapRegion->MinY) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize + + // For non-compressed formats, BlockWidth is 1. + pMapRegion->MinX / FmtAttribs.BlockWidth * FmtAttribs.GetElementSize(); - MappedData.pData = reinterpret_cast(Allocation.pDynamicMemMgr->GetCPUAddress()) + Allocation.AlignedOffset; - MappedData.Stride = CopyInfo.Stride; - MappedData.DepthStride = CopyInfo.DepthStride; + MappedData.pData = TextureVk.GetStagingDataCPUAddress() + MapStartOffset; + MappedData.Stride = MipLevelAttribs.RowSize; + MappedData.DepthStride = MipLevelAttribs.DepthSliceSize; - auto it = m_MappedTextures.emplace(MappedTextureKey{&TextureVk, MipLevel, ArraySlice}, MappedTexture{CopyInfo, std::move(Allocation)}); - if(!it.second) - LOG_ERROR_MESSAGE("Mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "' has already been mapped"); - } - else if (TexDesc.Usage == USAGE_STAGING) + if (MapType == MAP_READ) { - if( (MapFlags & MAP_FLAG_DO_NOT_SYNCHRONIZE) == 0 ) - { - LOG_WARNING_MESSAGE_ONCE("Mapping staging textures is never synchronized in Vulkan backend. " - "Application must use fences or other synchronization methods to explicitly synchronize " - "access and map texture with MAP_FLAG_DO_NOT_SYNCHRONIZE flag."); - } - - auto SubresourceOffset = GetStagingDataOffset(TexDesc, ArraySlice, MipLevel); - auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); - // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) - auto MapStartOffset = SubresourceOffset + - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (pMapRegion->MinZ * MipLevelAttribs.StorageHeight + pMapRegion->MinY) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize + - // For non-compressed formats, BlockWidth is 1. - pMapRegion->MinX / FmtAttribs.BlockWidth * FmtAttribs.GetElementSize(); - - MappedData.pData = TextureVk.GetStagingDataCPUAddress() + MapStartOffset; - MappedData.Stride = MipLevelAttribs.RowSize; - MappedData.DepthStride = MipLevelAttribs.DepthSliceSize; - - if (MapType == MAP_READ) - { - DEV_CHECK_ERR((TexDesc.CPUAccessFlags & CPU_ACCESS_READ), "Texture '", TexDesc.Name, "' was not created with CPU_ACCESS_READ flag and can't be mapped for reading"); - // Reaback memory is not created with HOST_COHERENT flag, so we have to explicitly invalidate the mapped range - // to make device writes visible to CPU reads - VERIFY_EXPR(pMapRegion->MaxZ >= 1 && pMapRegion->MaxY >= 1); - auto BlockAlignedMaxX = Align(pMapRegion->MaxX, Uint32{FmtAttribs.BlockWidth}); - auto BlockAlignedMaxY = Align(pMapRegion->MaxY, Uint32{FmtAttribs.BlockHeight}); - auto MapEndOffset = SubresourceOffset + - ((pMapRegion->MaxZ-1) * MipLevelAttribs.StorageHeight + (BlockAlignedMaxY - FmtAttribs.BlockHeight)) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize + - (BlockAlignedMaxX / FmtAttribs.BlockWidth) * FmtAttribs.GetElementSize(); - TextureVk.InvalidateStagingRange(MapStartOffset, MapEndOffset - MapStartOffset); - } - else if (MapType == MAP_WRITE) - { - DEV_CHECK_ERR((TexDesc.CPUAccessFlags & CPU_ACCESS_WRITE), "Texture '", TexDesc.Name, "' was not created with CPU_ACCESS_WRITE flag and can't be mapped for writing"); - // Nothing needs to be done when mapping texture for writing - } + DEV_CHECK_ERR((TexDesc.CPUAccessFlags & CPU_ACCESS_READ), "Texture '", TexDesc.Name, "' was not created with CPU_ACCESS_READ flag and can't be mapped for reading"); + // Reaback memory is not created with HOST_COHERENT flag, so we have to explicitly invalidate the mapped range + // to make device writes visible to CPU reads + VERIFY_EXPR(pMapRegion->MaxZ >= 1 && pMapRegion->MaxY >= 1); + auto BlockAlignedMaxX = Align(pMapRegion->MaxX, Uint32{FmtAttribs.BlockWidth}); + auto BlockAlignedMaxY = Align(pMapRegion->MaxY, Uint32{FmtAttribs.BlockHeight}); + auto MapEndOffset = SubresourceOffset + + ((pMapRegion->MaxZ - 1) * MipLevelAttribs.StorageHeight + (BlockAlignedMaxY - FmtAttribs.BlockHeight)) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize + + (BlockAlignedMaxX / FmtAttribs.BlockWidth) * FmtAttribs.GetElementSize(); + TextureVk.InvalidateStagingRange(MapStartOffset, MapEndOffset - MapStartOffset); } - else + else if (MapType == MAP_WRITE) { - UNSUPPORTED(GetUsageString(TexDesc.Usage), " textures cannot currently be mapped in Vulkan back-end"); + DEV_CHECK_ERR((TexDesc.CPUAccessFlags & CPU_ACCESS_WRITE), "Texture '", TexDesc.Name, "' was not created with CPU_ACCESS_WRITE flag and can't be mapped for writing"); + // Nothing needs to be done when mapping texture for writing } } - - void DeviceContextVkImpl::UnmapTextureSubresource(ITexture* pTexture, - Uint32 MipLevel, - Uint32 ArraySlice) + else { - TDeviceContextBase::UnmapTextureSubresource( pTexture, MipLevel, ArraySlice); + UNSUPPORTED(GetUsageString(TexDesc.Usage), " textures cannot currently be mapped in Vulkan back-end"); + } +} - TextureVkImpl& TextureVk = *ValidatedCast(pTexture); - const auto& TexDesc = TextureVk.GetDesc(); +void DeviceContextVkImpl::UnmapTextureSubresource(ITexture* pTexture, + Uint32 MipLevel, + Uint32 ArraySlice) +{ + TDeviceContextBase::UnmapTextureSubresource(pTexture, MipLevel, ArraySlice); - if (TexDesc.Usage == USAGE_DYNAMIC) - { - auto UploadSpaceIt = m_MappedTextures.find(MappedTextureKey{&TextureVk, MipLevel, ArraySlice}); - if(UploadSpaceIt != m_MappedTextures.end()) - { - auto& MappedTex = UploadSpaceIt->second; - CopyBufferToTexture(MappedTex.Allocation.pDynamicMemMgr->GetVkBuffer(), - static_cast(MappedTex.Allocation.AlignedOffset), - MappedTex.CopyInfo.StrideInTexels, - TextureVk, - MappedTex.CopyInfo.Region, - MipLevel, - ArraySlice, - RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - m_MappedTextures.erase(UploadSpaceIt); - } - else - { - LOG_ERROR_MESSAGE("Failed to unmap mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "'. The texture has either been unmapped already or has not been mapped"); - } - } - else if (TexDesc.Usage == USAGE_STAGING) + TextureVkImpl& TextureVk = *ValidatedCast(pTexture); + const auto& TexDesc = TextureVk.GetDesc(); + + if (TexDesc.Usage == USAGE_DYNAMIC) + { + auto UploadSpaceIt = m_MappedTextures.find(MappedTextureKey{&TextureVk, MipLevel, ArraySlice}); + if (UploadSpaceIt != m_MappedTextures.end()) { - if (TexDesc.CPUAccessFlags & CPU_ACCESS_READ) - { - // Nothing needs to be done - } - else if (TexDesc.CPUAccessFlags & CPU_ACCESS_WRITE) - { - // Upload textures are currently created with VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, so - // there is no need to explicitly flush the mapped range. - } + auto& MappedTex = UploadSpaceIt->second; + CopyBufferToTexture(MappedTex.Allocation.pDynamicMemMgr->GetVkBuffer(), + static_cast(MappedTex.Allocation.AlignedOffset), + MappedTex.CopyInfo.StrideInTexels, + TextureVk, + MappedTex.CopyInfo.Region, + MipLevel, + ArraySlice, + RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + m_MappedTextures.erase(UploadSpaceIt); } else { - UNSUPPORTED(GetUsageString(TexDesc.Usage), " textures cannot currently be mapped in Vulkan back-end"); + LOG_ERROR_MESSAGE("Failed to unmap mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "'. The texture has either been unmapped already or has not been mapped"); } } - - void DeviceContextVkImpl::FinishCommandList(class ICommandList **ppCommandList) + else if (TexDesc.Usage == USAGE_STAGING) { - if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + if (TexDesc.CPUAccessFlags & CPU_ACCESS_READ) { - m_CommandBuffer.EndRenderPass(); + // Nothing needs to be done + } + else if (TexDesc.CPUAccessFlags & CPU_ACCESS_WRITE) + { + // Upload textures are currently created with VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, so + // there is no need to explicitly flush the mapped range. } + } + else + { + UNSUPPORTED(GetUsageString(TexDesc.Usage), " textures cannot currently be mapped in Vulkan back-end"); + } +} - auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); - auto err = vkEndCommandBuffer(vkCmdBuff); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to end command buffer"); (void)err; +void DeviceContextVkImpl::FinishCommandList(class ICommandList** ppCommandList) +{ + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) + { + m_CommandBuffer.EndRenderPass(); + } - CommandListVkImpl *pCmdListVk( NEW_RC_OBJ(m_CmdListAllocator, "CommandListVkImpl instance", CommandListVkImpl) - (m_pDevice, this, vkCmdBuff) ); - pCmdListVk->QueryInterface( IID_CommandList, reinterpret_cast(ppCommandList) ); + auto vkCmdBuff = m_CommandBuffer.GetVkCmdBuffer(); + auto err = vkEndCommandBuffer(vkCmdBuff); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to end command buffer"); + (void)err; - m_CommandBuffer.Reset(); - m_State = ContextState{}; - m_DescrSetBindInfo.Reset(); - m_pPipelineState = nullptr; + CommandListVkImpl* pCmdListVk(NEW_RC_OBJ(m_CmdListAllocator, "CommandListVkImpl instance", CommandListVkImpl)(m_pDevice, this, vkCmdBuff)); + pCmdListVk->QueryInterface(IID_CommandList, reinterpret_cast(ppCommandList)); - InvalidateState(); - } + m_CommandBuffer.Reset(); + m_State = ContextState{}; + m_DescrSetBindInfo.Reset(); + m_pPipelineState = nullptr; - void DeviceContextVkImpl::ExecuteCommandList(class ICommandList *pCommandList) + InvalidateState(); +} + +void DeviceContextVkImpl::ExecuteCommandList(class ICommandList* pCommandList) +{ + if (m_bIsDeferred) { - if (m_bIsDeferred) - { - LOG_ERROR_MESSAGE("Only immediate context can execute command list"); - return; - } + LOG_ERROR_MESSAGE("Only immediate context can execute command list"); + return; + } - Flush(); + Flush(); - InvalidateState(); + InvalidateState(); - CommandListVkImpl* pCmdListVk = ValidatedCast(pCommandList); - VkCommandBuffer vkCmdBuff = VK_NULL_HANDLE; - RefCntAutoPtr pDeferredCtx; - pCmdListVk->Close(vkCmdBuff, pDeferredCtx); - VERIFY(vkCmdBuff != VK_NULL_HANDLE, "Trying to execute empty command buffer"); - VERIFY_EXPR(pDeferredCtx); - VkSubmitInfo SubmitInfo = {}; - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - SubmitInfo.pNext = nullptr; - SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &vkCmdBuff; - VERIFY_EXPR(m_PendingFences.empty()); - auto pDeferredCtxVkImpl = pDeferredCtx.RawPtr(); - auto SubmittedFenceValue = m_pDevice->ExecuteCommandBuffer(m_CommandQueueId, SubmitInfo, this, nullptr); - // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context - pDeferredCtxVkImpl->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; - // It is OK to dispose command buffer from another thread. We are not going to - // record any commands and only need to add the buffer to the queue - pDeferredCtxVkImpl->DisposeVkCmdBuffer(m_CommandQueueId, vkCmdBuff, SubmittedFenceValue); - } + CommandListVkImpl* pCmdListVk = ValidatedCast(pCommandList); + VkCommandBuffer vkCmdBuff = VK_NULL_HANDLE; - void DeviceContextVkImpl::SignalFence(IFence* pFence, Uint64 Value) - { - VERIFY(!m_bIsDeferred, "Fence can only be signaled from immediate context"); - m_PendingFences.emplace_back( std::make_pair(Value, pFence) ); - } + RefCntAutoPtr pDeferredCtx; + pCmdListVk->Close(vkCmdBuff, pDeferredCtx); + VERIFY(vkCmdBuff != VK_NULL_HANDLE, "Trying to execute empty command buffer"); + VERIFY_EXPR(pDeferredCtx); + VkSubmitInfo SubmitInfo = {}; + + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &vkCmdBuff; + VERIFY_EXPR(m_PendingFences.empty()); + auto pDeferredCtxVkImpl = pDeferredCtx.RawPtr(); + auto SubmittedFenceValue = m_pDevice->ExecuteCommandBuffer(m_CommandQueueId, SubmitInfo, this, nullptr); + // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context + pDeferredCtxVkImpl->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; + // It is OK to dispose command buffer from another thread. We are not going to + // record any commands and only need to add the buffer to the queue + pDeferredCtxVkImpl->DisposeVkCmdBuffer(m_CommandQueueId, vkCmdBuff, SubmittedFenceValue); +} + +void DeviceContextVkImpl::SignalFence(IFence* pFence, Uint64 Value) +{ + VERIFY(!m_bIsDeferred, "Fence can only be signaled from immediate context"); + m_PendingFences.emplace_back(std::make_pair(Value, pFence)); +} - void DeviceContextVkImpl::WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext) +void DeviceContextVkImpl::WaitForFence(IFence* pFence, Uint64 Value, bool FlushContext) +{ + VERIFY(!m_bIsDeferred, "Fence can only be waited from immediate context"); + if (FlushContext) + Flush(); + auto* pFenceVk = ValidatedCast(pFence); + pFenceVk->Wait(Value); +} + +void DeviceContextVkImpl::WaitForIdle() +{ + VERIFY(!m_bIsDeferred, "Only immediate contexts can be idled"); + Flush(); + m_pDevice->IdleCommandQueue(m_CommandQueueId, true); +} + +void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayout NewLayout) +{ + VERIFY_EXPR(pTexture != nullptr); + auto pTextureVk = ValidatedCast(pTexture); + if (!pTextureVk->IsInKnownState()) { - VERIFY(!m_bIsDeferred, "Fence can only be waited from immediate context"); - if (FlushContext) - Flush(); - auto* pFenceVk = ValidatedCast(pFence); - pFenceVk->Wait(Value); + LOG_ERROR_MESSAGE("Failed to transition layout for texture '", pTextureVk->GetDesc().Name, "' because the texture state is unknown"); + return; } - - void DeviceContextVkImpl::WaitForIdle() + auto NewState = VkImageLayoutToResourceState(NewLayout); + if (!pTextureVk->CheckState(NewState)) { - VERIFY(!m_bIsDeferred, "Only immediate contexts can be idled"); - Flush(); - m_pDevice->IdleCommandQueue(m_CommandQueueId, true); + TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, NewState, true); } +} - void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayout NewLayout) +void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& TextureVk, + RESOURCE_STATE OldState, + RESOURCE_STATE NewState, + bool UpdateTextureState, + VkImageSubresourceRange* pSubresRange /* = nullptr*/) +{ + if (OldState == RESOURCE_STATE_UNKNOWN) { - VERIFY_EXPR(pTexture != nullptr); - auto pTextureVk = ValidatedCast(pTexture); - if (!pTextureVk->IsInKnownState()) + if (TextureVk.IsInKnownState()) { - LOG_ERROR_MESSAGE("Failed to transition layout for texture '", pTextureVk->GetDesc().Name, "' because the texture state is unknown"); - return; + OldState = TextureVk.GetState(); } - auto NewState = VkImageLayoutToResourceState(NewLayout); - if (!pTextureVk->CheckState(NewState)) + else { - TransitionTextureState(*pTextureVk, RESOURCE_STATE_UNKNOWN, NewState, true); + LOG_ERROR_MESSAGE("Failed to transition the state of texture '", TextureVk.GetDesc().Name, "' because the state is unknown and is not explicitly specified."); + return; } } - - void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& TextureVk, - RESOURCE_STATE OldState, - RESOURCE_STATE NewState, - bool UpdateTextureState, - VkImageSubresourceRange* pSubresRange/* = nullptr*/) + else { - if (OldState == RESOURCE_STATE_UNKNOWN) + if (TextureVk.IsInKnownState() && TextureVk.GetState() != OldState) { - if (TextureVk.IsInKnownState()) - { - OldState = TextureVk.GetState(); - } - else - { - LOG_ERROR_MESSAGE("Failed to transition the state of texture '", TextureVk.GetDesc().Name, "' because the state is unknown and is not explicitly specified."); - return; - } - } - else - { - if (TextureVk.IsInKnownState() && TextureVk.GetState() != OldState) - { - LOG_ERROR_MESSAGE("The state ", GetResourceStateString(TextureVk.GetState()), " of texture '", - TextureVk.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), - " specified by the barrier"); - } + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(TextureVk.GetState()), " of texture '", + TextureVk.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); } + } - EnsureVkCmdBuffer(); + EnsureVkCmdBuffer(); - auto vkImg = TextureVk.GetVkImage(); - VkImageSubresourceRange FullSubresRange; - if (pSubresRange == nullptr) - { - pSubresRange = &FullSubresRange; - FullSubresRange.aspectMask = 0; - FullSubresRange.baseArrayLayer = 0; - FullSubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - FullSubresRange.baseMipLevel = 0; - FullSubresRange.levelCount = VK_REMAINING_MIP_LEVELS; - } + auto vkImg = TextureVk.GetVkImage(); - if (pSubresRange->aspectMask == 0) - { - const auto& TexDesc = TextureVk.GetDesc(); - const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); - if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) - pSubresRange->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) - { - // If image has a depth / stencil format with both depth and stencil components, then the - // aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and - // VK_IMAGE_ASPECT_STENCIL_BIT (6.7.3) - pSubresRange->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } - else - pSubresRange->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - } + VkImageSubresourceRange FullSubresRange; + if (pSubresRange == nullptr) + { + pSubresRange = &FullSubresRange; + + FullSubresRange.aspectMask = 0; + FullSubresRange.baseArrayLayer = 0; + FullSubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + FullSubresRange.baseMipLevel = 0; + FullSubresRange.levelCount = VK_REMAINING_MIP_LEVELS; + } - // Note that when both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier - // to make sure that all UAV writes are complete and visible. - auto OldLayout = ResourceStateToVkImageLayout(OldState); - auto NewLayout = ResourceStateToVkImageLayout(NewState); - m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange); - if(UpdateTextureState) + if (pSubresRange->aspectMask == 0) + { + const auto& TexDesc = TextureVk.GetDesc(); + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + pSubresRange->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) { - TextureVk.SetState(NewState); - VERIFY_EXPR(TextureVk.GetLayout() == NewLayout); + // If image has a depth / stencil format with both depth and stencil components, then the + // aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and + // VK_IMAGE_ASPECT_STENCIL_BIT (6.7.3) + pSubresRange->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; } + else + pSubresRange->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } - void DeviceContextVkImpl::TransitionOrVerifyTextureState(TextureVkImpl& Texture, - RESOURCE_STATE_TRANSITION_MODE TransitionMode, - RESOURCE_STATE RequiredState, - VkImageLayout ExpectedLayout, - const char* OperationName) + // Note that when both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier + // to make sure that all UAV writes are complete and visible. + auto OldLayout = ResourceStateToVkImageLayout(OldState); + auto NewLayout = ResourceStateToVkImageLayout(NewState); + m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange); + if (UpdateTextureState) { - if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + TextureVk.SetState(NewState); + VERIFY_EXPR(TextureVk.GetLayout() == NewLayout); + } +} + +void DeviceContextVkImpl::TransitionOrVerifyTextureState(TextureVkImpl& Texture, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + VkImageLayout ExpectedLayout, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + if (Texture.IsInKnownState()) { - if (Texture.IsInKnownState()) + if (!Texture.CheckState(RequiredState)) { - if (!Texture.CheckState(RequiredState)) - { - TransitionTextureState(Texture, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } - VERIFY_EXPR(Texture.GetLayout() == ExpectedLayout); + TransitionTextureState(Texture, RESOURCE_STATE_UNKNOWN, RequiredState, true); } + VERIFY_EXPR(Texture.GetLayout() == ExpectedLayout); } + } #ifdef DEVELOPMENT - else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) - { - DvpVerifyTextureState(Texture, RequiredState, OperationName); - } -#endif + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyTextureState(Texture, RequiredState, OperationName); } +#endif +} - void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl& TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange) - { - // Note that the method may be used to transition texture subresources when global texture state is not altered, - // so the debug check below can't be used - // VERIFY(!TextureVk.IsInKnownState() || TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout"); +void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl& TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange) +{ + // Note that the method may be used to transition texture subresources when global texture state is not altered, + // so the debug check below can't be used + // VERIFY(!TextureVk.IsInKnownState() || TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout"); + + VERIFY(OldLayout != NewLayout, "Old and new layouts are the same"); + EnsureVkCmdBuffer(); + auto vkImg = TextureVk.GetVkImage(); + m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, SubresRange); +} - VERIFY(OldLayout != NewLayout, "Old and new layouts are the same"); - EnsureVkCmdBuffer(); - auto vkImg = TextureVk.GetVkImage(); - m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, SubresRange); +void DeviceContextVkImpl::BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags NewAccessFlags) +{ + VERIFY_EXPR(pBuffer != nullptr); + auto pBuffVk = ValidatedCast(pBuffer); + if (!pBuffVk->IsInKnownState()) + { + LOG_ERROR_MESSAGE("Failed to execute buffer memory barrier for buffer '", pBuffVk->GetDesc().Name, "' because the buffer state is unknown"); + return; + } + auto NewState = VkAccessFlagsToResourceStates(NewAccessFlags); + if ((pBuffVk->GetState() & NewState) != NewState) + { + TransitionBufferState(*pBuffVk, RESOURCE_STATE_UNKNOWN, NewState, true); } +} - void DeviceContextVkImpl::BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags NewAccessFlags) +void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, bool UpdateBufferState) +{ + if (OldState == RESOURCE_STATE_UNKNOWN) { - VERIFY_EXPR(pBuffer != nullptr); - auto pBuffVk = ValidatedCast(pBuffer); - if (!pBuffVk->IsInKnownState()) + if (BufferVk.IsInKnownState()) { - LOG_ERROR_MESSAGE("Failed to execute buffer memory barrier for buffer '", pBuffVk->GetDesc().Name, "' because the buffer state is unknown"); - return; + OldState = BufferVk.GetState(); } - auto NewState = VkAccessFlagsToResourceStates(NewAccessFlags); - if ((pBuffVk->GetState() & NewState) != NewState) + else { - TransitionBufferState(*pBuffVk, RESOURCE_STATE_UNKNOWN, NewState, true); + LOG_ERROR_MESSAGE("Failed to transition the state of buffer '", BufferVk.GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); + return; } } - - void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, bool UpdateBufferState) + else { - if (OldState == RESOURCE_STATE_UNKNOWN) + if (BufferVk.IsInKnownState() && BufferVk.GetState() != OldState) { - if (BufferVk.IsInKnownState()) - { - OldState = BufferVk.GetState(); - } - else - { - LOG_ERROR_MESSAGE("Failed to transition the state of buffer '", BufferVk.GetDesc().Name, "' because the buffer state is unknown and is not explicitly specified"); - return; - } - } - else - { - if (BufferVk.IsInKnownState() && BufferVk.GetState() != OldState) - { - LOG_ERROR_MESSAGE("The state ", GetResourceStateString(BufferVk.GetState()), " of buffer '", - BufferVk.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), - " specified by the barrier"); - } + LOG_ERROR_MESSAGE("The state ", GetResourceStateString(BufferVk.GetState()), " of buffer '", + BufferVk.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState), + " specified by the barrier"); } + } + + // When both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier + // to make sure that all UAV writes are complete and visible. + if (((OldState & NewState) != NewState) || NewState == RESOURCE_STATE_UNORDERED_ACCESS) + { + DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); + VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); - // When both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier - // to make sure that all UAV writes are complete and visible. - if (((OldState & NewState) != NewState) || NewState == RESOURCE_STATE_UNORDERED_ACCESS) + EnsureVkCmdBuffer(); + auto vkBuff = BufferVk.GetVkBuffer(); + auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); + auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); + m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags); + if (UpdateBufferState) { - DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer"); - VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0); - - EnsureVkCmdBuffer(); - auto vkBuff = BufferVk.GetVkBuffer(); - auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState); - auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState); - m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags); - if (UpdateBufferState) - { - BufferVk.SetState(NewState); - } + BufferVk.SetState(NewState); } } +} - void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl& Buffer, - RESOURCE_STATE_TRANSITION_MODE TransitionMode, - RESOURCE_STATE RequiredState, - VkAccessFlagBits ExpectedAccessFlags, - const char* OperationName) +void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl& Buffer, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + VkAccessFlagBits ExpectedAccessFlags, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { - if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + if (Buffer.IsInKnownState()) { - if (Buffer.IsInKnownState()) + if (!Buffer.CheckState(RequiredState)) { - if (!Buffer.CheckState(RequiredState)) - { - TransitionBufferState(Buffer, RESOURCE_STATE_UNKNOWN, RequiredState, true); - } - VERIFY_EXPR(Buffer.CheckAccessFlags(ExpectedAccessFlags)); + TransitionBufferState(Buffer, RESOURCE_STATE_UNKNOWN, RequiredState, true); } + VERIFY_EXPR(Buffer.CheckAccessFlags(ExpectedAccessFlags)); } + } #ifdef DEVELOPMENT - else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) - { - DvpVerifyBufferState(Buffer, RequiredState, OperationName); - } -#endif + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyBufferState(Buffer, RequiredState, OperationName); } +#endif +} - VulkanDynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment) - { - auto DynAlloc = m_DynamicHeap.Allocate(SizeInBytes, Alignment); +VulkanDynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment) +{ + auto DynAlloc = m_DynamicHeap.Allocate(SizeInBytes, Alignment); #ifdef DEVELOPMENT - DynAlloc.dvpFrameNumber = m_ContextFrameNumber; + DynAlloc.dvpFrameNumber = m_ContextFrameNumber; #endif - return DynAlloc; - } + return DynAlloc; +} - void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) - { - if (BarrierCount == 0) - return; +void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) +{ + if (BarrierCount == 0) + return; - EnsureVkCmdBuffer(); + EnsureVkCmdBuffer(); - for(Uint32 i=0; i < BarrierCount; ++i) - { - const auto& Barrier = pResourceBarriers[i]; + for (Uint32 i = 0; i < BarrierCount; ++i) + { + const auto& Barrier = pResourceBarriers[i]; #ifdef DEVELOPMENT - DvpVerifyStateTransitionDesc(Barrier); + DvpVerifyStateTransitionDesc(Barrier); #endif - if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) - { - // Skip begin-split barriers - VERIFY(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier"); - continue; - } - VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type"); - - if (Barrier.pTexture) - { - auto* pTextureVkImpl = ValidatedCast(Barrier.pTexture); - VkImageSubresourceRange SubResRange; - SubResRange.aspectMask = 0; - SubResRange.baseMipLevel = Barrier.FirstMipLevel; - SubResRange.levelCount = (Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels) ? VK_REMAINING_MIP_LEVELS : Barrier.MipLevelsCount; - SubResRange.baseArrayLayer = Barrier.FirstArraySlice; - SubResRange.layerCount = (Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices) ? VK_REMAINING_ARRAY_LAYERS : Barrier.ArraySliceCount; - TransitionTextureState(*pTextureVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange); - } - else - { - VERIFY_EXPR(Barrier.pBuffer != nullptr); - auto* pBufferVkImpl = ValidatedCast(Barrier.pBuffer); - TransitionBufferState(*pBufferVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); - } + if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN) + { + // Skip begin-split barriers + VERIFY(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier"); + continue; } - } - - void DeviceContextVkImpl::ResolveTextureSubresource(ITexture* pSrcTexture, - ITexture* pDstTexture, - const ResolveTextureSubresourceAttribs& ResolveAttribs) - { - TDeviceContextBase::ResolveTextureSubresource(pSrcTexture, pDstTexture, ResolveAttribs); + VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type"); - auto* pSrcTexVk = ValidatedCast(pSrcTexture); - auto* pDstTexVk = ValidatedCast(pDstTexture); - const auto& SrcTexDesc = pSrcTexVk->GetDesc(); - const auto& DstTexDesc = pDstTexVk->GetDesc(); - - DEV_CHECK_ERR(SrcTexDesc.Format == DstTexDesc.Format, "Vulkan requires that source and destination textures of a resolve operation " - "have the same format (18.6)");(void)DstTexDesc; - - EnsureVkCmdBuffer(); - // srcImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.6) - TransitionOrVerifyTextureState(*pSrcTexVk, ResolveAttribs.SrcTextureTransitionMode, RESOURCE_STATE_RESOLVE_SOURCE, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - "Resolving multi-sampled texture (DeviceContextVkImpl::ResolveTextureSubresource)"); - - // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.6) - TransitionOrVerifyTextureState(*pDstTexVk, ResolveAttribs.DstTextureTransitionMode, RESOURCE_STATE_RESOLVE_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - "Resolving multi-sampled texture (DeviceContextVkImpl::ResolveTextureSubresource)"); - - const auto& ResolveFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); - DEV_CHECK_ERR(ResolveFmtAttribs.ComponentType != COMPONENT_TYPE_DEPTH && ResolveFmtAttribs.ComponentType != COMPONENT_TYPE_DEPTH_STENCIL, - "Vulkan only allows resolve operation for color formats");(void)ResolveFmtAttribs; - // The aspectMask member of srcSubresource and dstSubresource must only contain VK_IMAGE_ASPECT_COLOR_BIT (18.6) - VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - VkImageResolve ResolveRegion; - ResolveRegion.srcSubresource.baseArrayLayer = ResolveAttribs.SrcSlice; - ResolveRegion.srcSubresource.layerCount = 1; - ResolveRegion.srcSubresource.mipLevel = ResolveAttribs.SrcMipLevel; - ResolveRegion.srcSubresource.aspectMask = aspectMask; - - ResolveRegion.dstSubresource.baseArrayLayer = ResolveAttribs.DstSlice; - ResolveRegion.dstSubresource.layerCount = 1; - ResolveRegion.dstSubresource.mipLevel = ResolveAttribs.DstMipLevel; - ResolveRegion.dstSubresource.aspectMask = aspectMask; - - ResolveRegion.srcOffset = VkOffset3D{}; - ResolveRegion.dstOffset = VkOffset3D{}; - const auto& MipAttribs = GetMipLevelProperties(SrcTexDesc, ResolveAttribs.SrcMipLevel); - ResolveRegion.extent = VkExtent3D - { - static_cast(MipAttribs.LogicalWidth), - static_cast(MipAttribs.LogicalHeight), - static_cast(MipAttribs.Depth) - }; + if (Barrier.pTexture) + { + auto* pTextureVkImpl = ValidatedCast(Barrier.pTexture); - m_CommandBuffer.ResolveImage(pSrcTexVk->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - pDstTexVk->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &ResolveRegion); + VkImageSubresourceRange SubResRange; + SubResRange.aspectMask = 0; + SubResRange.baseMipLevel = Barrier.FirstMipLevel; + SubResRange.levelCount = (Barrier.MipLevelsCount == StateTransitionDesc::RemainingMipLevels) ? VK_REMAINING_MIP_LEVELS : Barrier.MipLevelsCount; + SubResRange.baseArrayLayer = Barrier.FirstArraySlice; + SubResRange.layerCount = (Barrier.ArraySliceCount == StateTransitionDesc::RemainingArraySlices) ? VK_REMAINING_ARRAY_LAYERS : Barrier.ArraySliceCount; + TransitionTextureState(*pTextureVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange); + } + else + { + VERIFY_EXPR(Barrier.pBuffer != nullptr); + auto* pBufferVkImpl = ValidatedCast(Barrier.pBuffer); + TransitionBufferState(*pBufferVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState); + } } } + +void DeviceContextVkImpl::ResolveTextureSubresource(ITexture* pSrcTexture, + ITexture* pDstTexture, + const ResolveTextureSubresourceAttribs& ResolveAttribs) +{ + TDeviceContextBase::ResolveTextureSubresource(pSrcTexture, pDstTexture, ResolveAttribs); + + auto* pSrcTexVk = ValidatedCast(pSrcTexture); + auto* pDstTexVk = ValidatedCast(pDstTexture); + const auto& SrcTexDesc = pSrcTexVk->GetDesc(); + const auto& DstTexDesc = pDstTexVk->GetDesc(); + + DEV_CHECK_ERR(SrcTexDesc.Format == DstTexDesc.Format, "Vulkan requires that source and destination textures of a resolve operation " + "have the same format (18.6)"); + (void)DstTexDesc; + + EnsureVkCmdBuffer(); + // srcImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.6) + TransitionOrVerifyTextureState(*pSrcTexVk, ResolveAttribs.SrcTextureTransitionMode, RESOURCE_STATE_RESOLVE_SOURCE, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + "Resolving multi-sampled texture (DeviceContextVkImpl::ResolveTextureSubresource)"); + + // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.6) + TransitionOrVerifyTextureState(*pDstTexVk, ResolveAttribs.DstTextureTransitionMode, RESOURCE_STATE_RESOLVE_DEST, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + "Resolving multi-sampled texture (DeviceContextVkImpl::ResolveTextureSubresource)"); + + const auto& ResolveFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); + DEV_CHECK_ERR(ResolveFmtAttribs.ComponentType != COMPONENT_TYPE_DEPTH && ResolveFmtAttribs.ComponentType != COMPONENT_TYPE_DEPTH_STENCIL, + "Vulkan only allows resolve operation for color formats"); + (void)ResolveFmtAttribs; + // The aspectMask member of srcSubresource and dstSubresource must only contain VK_IMAGE_ASPECT_COLOR_BIT (18.6) + VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + VkImageResolve ResolveRegion; + ResolveRegion.srcSubresource.baseArrayLayer = ResolveAttribs.SrcSlice; + ResolveRegion.srcSubresource.layerCount = 1; + ResolveRegion.srcSubresource.mipLevel = ResolveAttribs.SrcMipLevel; + ResolveRegion.srcSubresource.aspectMask = aspectMask; + + ResolveRegion.dstSubresource.baseArrayLayer = ResolveAttribs.DstSlice; + ResolveRegion.dstSubresource.layerCount = 1; + ResolveRegion.dstSubresource.mipLevel = ResolveAttribs.DstMipLevel; + ResolveRegion.dstSubresource.aspectMask = aspectMask; + + ResolveRegion.srcOffset = VkOffset3D{}; + ResolveRegion.dstOffset = VkOffset3D{}; + const auto& MipAttribs = GetMipLevelProperties(SrcTexDesc, ResolveAttribs.SrcMipLevel); + ResolveRegion.extent = VkExtent3D{ + static_cast(MipAttribs.LogicalWidth), + static_cast(MipAttribs.LogicalHeight), + static_cast(MipAttribs.Depth)}; + + m_CommandBuffer.ResolveImage(pSrcTexVk->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + pDstTexVk->GetVkImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &ResolveRegion); +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 496eb67f..0debf7eb 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -54,44 +54,44 @@ public: TBase{IID_EngineFactoryVk} {} - void CreateDeviceAndContextsVk(const EngineVkCreateInfo& EngineCI, - IRenderDevice** ppDevice, - IDeviceContext** ppContexts)override final; + void CreateDeviceAndContextsVk(const EngineVkCreateInfo& EngineCI, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts) override final; void AttachToVulkanDevice(std::shared_ptr Instance, std::unique_ptr PhysicalDevice, std::shared_ptr LogicalDevice, - size_t CommandQueueCount, - ICommandQueueVk** ppCommandQueues, - const EngineVkCreateInfo& EngineCI, - IRenderDevice** ppDevice, - IDeviceContext** ppContexts);//override final; - - void CreateSwapChainVk(IRenderDevice* pDevice, - IDeviceContext* pImmediateContext, - const SwapChainDesc& SwapChainDesc, - void* pNativeWndHandle, - ISwapChain** ppSwapChain)override final; + size_t CommandQueueCount, + ICommandQueueVk** ppCommandQueues, + const EngineVkCreateInfo& EngineCI, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts); //override final; + + void CreateSwapChainVk(IRenderDevice* pDevice, + IDeviceContext* pImmediateContext, + const SwapChainDesc& SwapChainDesc, + void* pNativeWndHandle, + ISwapChain** ppSwapChain) override final; }; /// Creates render device and device contexts for Vulkan backend /// \param [in] EngineCI - Engine creation attributes. -/// \param [out] ppDevice - Address of the memory location where pointer to +/// \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 +/// \param [out] ppContexts - Address of the memory location where pointers to /// the contexts will be written. Immediate context goes at /// position 0. If EngineCI.NumDeferredContexts > 0, /// pointers to the deferred contexts are written afterwards. void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _EngineCI, - IRenderDevice** ppDevice, + IRenderDevice** ppDevice, IDeviceContext** ppContexts) { if (_EngineCI.APIVersion != DILIGENT_API_VERSION) LOG_ERROR_AND_THROW("Diligent Engine runtime (", _EngineCI.APIVersion, ") is not compatible with the client API version (", DILIGENT_API_VERSION, ")"); - VERIFY( ppDevice && ppContexts, "Null pointer provided" ); - if( !ppDevice || !ppContexts ) + VERIFY(ppDevice && ppContexts, "Null pointer provided"); + if (!ppDevice || !ppContexts) return; EngineVkCreateInfo EngineCI = _EngineCI; @@ -123,52 +123,52 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E try { auto Instance = VulkanUtilities::VulkanInstance::Create( - EngineCI.EnableValidation, - EngineCI.GlobalExtensionCount, + EngineCI.EnableValidation, + EngineCI.GlobalExtensionCount, EngineCI.ppGlobalExtensionNames, reinterpret_cast(EngineCI.pVkAllocator)); - auto vkDevice = Instance->SelectPhysicalDevice(); - auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create(vkDevice); + auto vkDevice = Instance->SelectPhysicalDevice(); + auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create(vkDevice); const auto& PhysicalDeviceFeatures = PhysicalDevice->GetFeatures(); - // If an implementation exposes any queue family that supports graphics operations, - // at least one queue family of at least one physical device exposed by the implementation + // If an implementation exposes any queue family that supports graphics operations, + // at least one queue family of at least one physical device exposed by the implementation // must support both graphics and compute operations. VkDeviceQueueCreateInfo QueueInfo{}; QueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; QueueInfo.flags = 0; // reserved for future use - // All commands that are allowed on a queue that supports transfer operations are also allowed on a - // queue that supports either graphics or compute operations.Thus, if the capabilities of a queue family - // include VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT, then reporting the VK_QUEUE_TRANSFER_BIT + // All commands that are allowed on a queue that supports transfer operations are also allowed on a + // queue that supports either graphics or compute operations.Thus, if the capabilities of a queue family + // include VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT, then reporting the VK_QUEUE_TRANSFER_BIT // capability separately for that queue family is optional (4.1). - QueueInfo.queueFamilyIndex = PhysicalDevice->FindQueueFamily(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT); - QueueInfo.queueCount = 1; + QueueInfo.queueFamilyIndex = PhysicalDevice->FindQueueFamily(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT); + QueueInfo.queueCount = 1; const float defaultQueuePriority = 1.0f; // Ask for highest priority for our queue. (range [0,1]) - QueueInfo.pQueuePriorities = &defaultQueuePriority; + QueueInfo.pQueuePriorities = &defaultQueuePriority; VkDeviceCreateInfo DeviceCreateInfo = {}; - DeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - DeviceCreateInfo.flags = 0; // Reserved for future use + DeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + DeviceCreateInfo.flags = 0; // Reserved for future use // https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#extended-functionality-device-layer-deprecation - DeviceCreateInfo.enabledLayerCount = 0; // Deprecated and ignored. - DeviceCreateInfo.ppEnabledLayerNames = nullptr; // Deprecated and ignored - DeviceCreateInfo.queueCreateInfoCount = 1; - DeviceCreateInfo.pQueueCreateInfos = &QueueInfo; + DeviceCreateInfo.enabledLayerCount = 0; // Deprecated and ignored. + DeviceCreateInfo.ppEnabledLayerNames = nullptr; // Deprecated and ignored + DeviceCreateInfo.queueCreateInfoCount = 1; + DeviceCreateInfo.pQueueCreateInfos = &QueueInfo; VkPhysicalDeviceFeatures DeviceFeatures = {}; -#define ENABLE_FEATURE(Feature)\ - if (EngineCI.EnabledFeatures.Feature)\ - { \ - if (PhysicalDeviceFeatures.Feature) \ - DeviceFeatures.Feature = VK_TRUE; \ - else \ - { \ - LOG_WARNING_MESSAGE("Requested device feature " #Feature " is not supported by the physical device and will be disabled");\ - EngineCI.EnabledFeatures.Feature = false; \ - } \ - } +#define ENABLE_FEATURE(Feature) \ + if (EngineCI.EnabledFeatures.Feature) \ + { \ + if (PhysicalDeviceFeatures.Feature) \ + DeviceFeatures.Feature = VK_TRUE; \ + else \ + { \ + LOG_WARNING_MESSAGE("Requested device feature " #Feature " is not supported by the physical device and will be disabled"); \ + EngineCI.EnabledFeatures.Feature = false; \ + } \ + } ENABLE_FEATURE(depthBiasClamp) ENABLE_FEATURE(fillModeNonSolid) @@ -186,24 +186,24 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E ENABLE_FEATURE(shaderStorageImageExtendedFormats) #undef ENABLE_FEATURE - DeviceCreateInfo.pEnabledFeatures = &DeviceFeatures; // NULL or a pointer to a VkPhysicalDeviceFeatures structure that contains + DeviceCreateInfo.pEnabledFeatures = &DeviceFeatures; // NULL or a pointer to a VkPhysicalDeviceFeatures structure that contains // boolean indicators of all the features to be enabled. - std::vector DeviceExtensions = - { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height - }; + std::vector DeviceExtensions = + { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height + }; DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); - DeviceCreateInfo.enabledExtensionCount = static_cast(DeviceExtensions.size()); + DeviceCreateInfo.enabledExtensionCount = static_cast(DeviceExtensions.size()); - auto vkAllocator = Instance->GetVkAllocator(); + auto vkAllocator = Instance->GetVkAllocator(); auto vkPhysicalDevice = PhysicalDevice->GetVkDeviceHandle(); - auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(vkPhysicalDevice, DeviceCreateInfo, vkAllocator); + auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(vkPhysicalDevice, DeviceCreateInfo, vkAllocator); RefCntAutoPtr pCmdQueueVk; - auto &RawMemAllocator = GetRawAllocator(); - pCmdQueueVk = NEW_RC_OBJ(RawMemAllocator, "CommandQueueVk instance", CommandQueueVkImpl)(LogicalDevice, QueueInfo.queueFamilyIndex); + auto& RawMemAllocator = GetRawAllocator(); + pCmdQueueVk = NEW_RC_OBJ(RawMemAllocator, "CommandQueueVk instance", CommandQueueVkImpl)(LogicalDevice, QueueInfo.queueFamilyIndex); std::array CommandQueues = {{pCmdQueueVk}}; AttachToVulkanDevice(Instance, std::move(PhysicalDevice), LogicalDevice, CommandQueues.size(), CommandQueues.data(), EngineCI, ppDevice, ppContexts); @@ -211,12 +211,13 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E FenceDesc Desc; Desc.Name = "Command queue fence"; // Render device owns command queue that in turn owns the fence, so it is an internal device object - bool IsDeviceInternal = true; - auto* pRenderDeviceVk = ValidatedCast(*ppDevice); - RefCntAutoPtr pFenceVk( NEW_RC_OBJ(RawMemAllocator, "FenceVkImpl instance", FenceVkImpl)(pRenderDeviceVk, Desc, IsDeviceInternal) ); + bool IsDeviceInternal = true; + auto* pRenderDeviceVk = ValidatedCast(*ppDevice); + + RefCntAutoPtr pFenceVk(NEW_RC_OBJ(RawMemAllocator, "FenceVkImpl instance", FenceVkImpl)(pRenderDeviceVk, Desc, IsDeviceInternal)); pCmdQueueVk->SetFence(std::move(pFenceVk)); } - catch(std::runtime_error& ) + catch (std::runtime_error&) { return; } @@ -229,26 +230,26 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E /// \param [in] LogicalDevice - shared pointer to a VulkanUtilities::VulkanLogicalDevice object /// \param [in] pCommandQueue - pointer to the implementation of command queue /// \param [in] EngineCI - Engine creation attributes. -/// \param [out] ppDevice - Address of the memory location where pointer to +/// \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 +/// \param [out] ppContexts - Address of the memory location where pointers to /// the contexts will be written. Immediate context goes at /// position 0. If EngineCI.NumDeferredContexts > 0, /// pointers to the deferred contexts are written afterwards. void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptr Instance, std::unique_ptr PhysicalDevice, std::shared_ptr LogicalDevice, - size_t CommandQueueCount, - ICommandQueueVk** ppCommandQueues, - const EngineVkCreateInfo& EngineCI, - IRenderDevice** ppDevice, - IDeviceContext** ppContexts) + size_t CommandQueueCount, + ICommandQueueVk** ppCommandQueues, + const EngineVkCreateInfo& EngineCI, + IRenderDevice** ppDevice, + IDeviceContext** ppContexts) { if (EngineCI.APIVersion != DILIGENT_API_VERSION) LOG_ERROR_AND_THROW("Diligent Engine runtime (", EngineCI.APIVersion, ") is not compatible with the client API version (", DILIGENT_API_VERSION, ")"); - VERIFY( ppCommandQueues && ppDevice && ppContexts, "Null pointer provided" ); - if(!LogicalDevice || !ppCommandQueues || !ppDevice || !ppContexts ) + VERIFY(ppCommandQueues && ppDevice && ppContexts, "Null pointer provided"); + if (!LogicalDevice || !ppCommandQueues || !ppDevice || !ppContexts) return; *ppDevice = nullptr; @@ -256,44 +257,45 @@ void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptrQueryInterface(IID_RenderDevice, reinterpret_cast(ppDevice) ); + auto& RawMemAllocator = GetRawAllocator(); + + RenderDeviceVkImpl* pRenderDeviceVk(NEW_RC_OBJ(RawMemAllocator, "RenderDeviceVkImpl instance", RenderDeviceVkImpl)(RawMemAllocator, this, EngineCI, CommandQueueCount, ppCommandQueues, Instance, std::move(PhysicalDevice), LogicalDevice)); + pRenderDeviceVk->QueryInterface(IID_RenderDevice, reinterpret_cast(ppDevice)); std::shared_ptr GenerateMipsHelper(new GenerateMipsVkHelper(*pRenderDeviceVk)); - RefCntAutoPtr pImmediateCtxVk( NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, false, EngineCI, 0, 0, GenerateMipsHelper) ); + RefCntAutoPtr pImmediateCtxVk(NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, false, EngineCI, 0, 0, GenerateMipsHelper)); // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceVk will // keep a weak reference to the context - pImmediateCtxVk->QueryInterface(IID_DeviceContext, reinterpret_cast(ppContexts) ); + pImmediateCtxVk->QueryInterface(IID_DeviceContext, reinterpret_cast(ppContexts)); pRenderDeviceVk->SetImmediateContext(pImmediateCtxVk); for (Uint32 DeferredCtx = 0; DeferredCtx < EngineCI.NumDeferredContexts; ++DeferredCtx) { - RefCntAutoPtr pDeferredCtxVk( NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, true, EngineCI, 1+DeferredCtx, 0, GenerateMipsHelper) ); + RefCntAutoPtr pDeferredCtxVk(NEW_RC_OBJ(RawMemAllocator, "DeviceContextVkImpl instance", DeviceContextVkImpl)(pRenderDeviceVk, true, EngineCI, 1 + DeferredCtx, 0, GenerateMipsHelper)); // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceVk will // keep a weak reference to the context - pDeferredCtxVk->QueryInterface(IID_DeviceContext, reinterpret_cast(ppContexts + 1 + DeferredCtx) ); + pDeferredCtxVk->QueryInterface(IID_DeviceContext, reinterpret_cast(ppContexts + 1 + DeferredCtx)); pRenderDeviceVk->SetDeferredContext(DeferredCtx, pDeferredCtxVk); } } - catch( const std::runtime_error & ) + catch (const std::runtime_error&) { - if( *ppDevice ) + if (*ppDevice) { (*ppDevice)->Release(); *ppDevice = nullptr; } - for(Uint32 ctx=0; ctx < 1 + EngineCI.NumDeferredContexts; ++ctx) + for (Uint32 ctx = 0; ctx < 1 + EngineCI.NumDeferredContexts; ++ctx) { - if( ppContexts[ctx] != nullptr ) + if (ppContexts[ctx] != nullptr) { ppContexts[ctx]->Release(); ppContexts[ctx] = nullptr; } } - LOG_ERROR( "Failed to create device and contexts" ); + LOG_ERROR("Failed to create device and contexts"); } } @@ -303,31 +305,31 @@ void EngineFactoryVkImpl::AttachToVulkanDevice(std::shared_ptr( pDevice ); + auto* pDeviceVk = ValidatedCast(pDevice); auto* pDeviceContextVk = ValidatedCast(pImmediateContext); - auto& RawMemAllocator = GetRawAllocator(); + auto& RawMemAllocator = GetRawAllocator(); if (pDeviceContextVk->GetSwapChain() != nullptr && SCDesc.IsPrimary) { @@ -337,40 +339,40 @@ void EngineFactoryVkImpl::CreateSwapChainVk(IRenderDevice* pDevice, auto* pSwapChainVk = NEW_RC_OBJ(RawMemAllocator, "SwapChainVkImpl instance", SwapChainVkImpl)(SCDesc, pDeviceVk, pDeviceContextVk, pNativeWndHandle); - pSwapChainVk->QueryInterface( IID_SwapChain, reinterpret_cast(ppSwapChain) ); + pSwapChainVk->QueryInterface(IID_SwapChain, reinterpret_cast(ppSwapChain)); if (SCDesc.IsPrimary) { pDeviceContextVk->SetSwapChain(pSwapChainVk); // Bind default render target - pDeviceContextVk->SetRenderTargets( 0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION ); + pDeviceContextVk->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); // Set default viewport - pDeviceContextVk->SetViewports( 1, nullptr, 0, 0 ); - + 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 = pDeferredCtx.RawPtr(); + auto* pDeferredCtxVk = 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 + // in this frame. It is an error to bind // RTV of an inactive buffer in the swap chain } } } } - catch( const std::runtime_error & ) + catch (const std::runtime_error&) { - if( *ppSwapChain ) + if (*ppSwapChain) { (*ppSwapChain)->Release(); *ppSwapChain = nullptr; } - LOG_ERROR( "Failed to create the swap chain" ); + LOG_ERROR("Failed to create the swap chain"); } } @@ -385,10 +387,10 @@ void EngineFactoryVkImpl::CreateSwapChainVk(IRenderDevice* pDevice, /// x86 | GraphicsEngineVk_32d.dll | GraphicsEngineVk_32r.dll /// x64 | GraphicsEngineVk_64d.dll | GraphicsEngineVk_64r.dll /// -void LoadGraphicsEngineVk(GetEngineFactoryVkType &GetFactoryFunc) +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; +// 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 @@ -398,4 +400,4 @@ IEngineFactoryVk* GetEngineFactoryVk() return EngineFactoryVkImpl::GetInstance(); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/FenceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/FenceVkImpl.cpp index cb1be2b8..7f6f99a3 100644 --- a/Graphics/GraphicsEngineVulkan/src/FenceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/FenceVkImpl.cpp @@ -29,11 +29,12 @@ namespace Diligent { - -FenceVkImpl :: FenceVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pRendeDeviceVkImpl, - const FenceDesc& Desc, - bool IsDeviceInternal) : + +FenceVkImpl ::FenceVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pRendeDeviceVkImpl, + const FenceDesc& Desc, + bool IsDeviceInternal) : + // clang-format off TFenceBase { pRefCounters, @@ -42,30 +43,32 @@ FenceVkImpl :: FenceVkImpl(IReferenceCounters* pRefCounters, IsDeviceInternal }, m_FencePool{pRendeDeviceVkImpl->GetLogicalDevice().GetSharedPtr()} +// clang-format on { } -FenceVkImpl :: ~FenceVkImpl() +FenceVkImpl ::~FenceVkImpl() { if (!m_PendingFences.empty()) { LOG_INFO_MESSAGE("FenceVkImpl::~FenceVkImpl(): waiting for ", m_PendingFences.size(), " pending Vulkan ", (m_PendingFences.size() > 1 ? "fences." : "fence.")); - // Vulkan spec states that all queue submission commands that refer to + // Vulkan spec states that all queue submission commands that refer to // a fence must have completed execution before the fence is destroyed. // (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkDestroyFence-fence-01120) Wait(UINT64_MAX); } } -Uint64 FenceVkImpl :: GetCompletedValue() +Uint64 FenceVkImpl ::GetCompletedValue() { const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); while (!m_PendingFences.empty()) { auto& Value_Fence = m_PendingFences.front(); + auto status = LogicalDevice.GetFenceStatus(Value_Fence.second); - if(status == VK_SUCCESS) + if (status == VK_SUCCESS) { if (Value_Fence.first > m_LastCompletedFenceValue) m_LastCompletedFenceValue = Value_Fence.first; @@ -81,7 +84,7 @@ Uint64 FenceVkImpl :: GetCompletedValue() return m_LastCompletedFenceValue; } -void FenceVkImpl :: Reset(Uint64 Value) +void FenceVkImpl ::Reset(Uint64 Value) { DEV_CHECK_ERR(Value >= m_LastCompletedFenceValue, "Resetting fence '", m_Desc.Name, "' to the value (", Value, ") that is smaller than the last completed value (", m_LastCompletedFenceValue, ")"); if (Value > m_LastCompletedFenceValue) @@ -89,7 +92,7 @@ void FenceVkImpl :: Reset(Uint64 Value) } -void FenceVkImpl :: Wait(Uint64 Value) +void FenceVkImpl ::Wait(Uint64 Value) { const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); while (!m_PendingFences.empty()) @@ -102,10 +105,12 @@ void FenceVkImpl :: Wait(Uint64 Value) if (status == VK_NOT_READY) { VkFence FenceToWait = val_fence.second; + status = LogicalDevice.WaitForFences(1, &FenceToWait, VK_TRUE, UINT64_MAX); } - DEV_CHECK_ERR(status == VK_SUCCESS, "All pending fences must now be complete!"); (void)status; + DEV_CHECK_ERR(status == VK_SUCCESS, "All pending fences must now be complete!"); + (void)status; if (val_fence.first > m_LastCompletedFenceValue) m_LastCompletedFenceValue = val_fence.first; m_FencePool.DisposeFence(std::move(val_fence.second)); @@ -114,4 +119,4 @@ void FenceVkImpl :: Wait(Uint64 Value) } } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp b/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp index 050fb1aa..70b66475 100644 --- a/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp +++ b/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp @@ -29,9 +29,10 @@ namespace Diligent { - -bool FramebufferCache::FramebufferCacheKey::operator == (const FramebufferCacheKey &rhs)const + +bool FramebufferCache::FramebufferCacheKey::operator==(const FramebufferCacheKey& rhs) const { + // clang-format off if (GetHash() != rhs.GetHash() || Pass != rhs.Pass || NumRenderTargets != rhs.NumRenderTargets || @@ -40,6 +41,7 @@ bool FramebufferCache::FramebufferCacheKey::operator == (const FramebufferCacheK { return false; } + // clang-format on for (Uint32 rt = 0; rt < NumRenderTargets; ++rt) if (RTVs[rt] != rhs.RTVs[rt]) @@ -48,12 +50,12 @@ bool FramebufferCache::FramebufferCacheKey::operator == (const FramebufferCacheK return true; } -size_t FramebufferCache::FramebufferCacheKey::GetHash()const +size_t FramebufferCache::FramebufferCacheKey::GetHash() const { if (Hash == 0) { Hash = ComputeHash(Pass, NumRenderTargets, DSV, CommandQueueMask); - for(Uint32 rt = 0; rt < NumRenderTargets; ++rt) + for (Uint32 rt = 0; rt < NumRenderTargets; ++rt) HashCombine(Hash, RTVs[rt]); } return Hash; @@ -62,7 +64,7 @@ size_t FramebufferCache::FramebufferCacheKey::GetHash()const VkFramebuffer FramebufferCache::GetFramebuffer(const FramebufferCacheKey& Key, uint32_t width, uint32_t height, uint32_t layers) { std::lock_guard Lock{m_Mutex}; - auto it = m_Cache.find(Key); + auto it = m_Cache.find(Key); if (it != m_Cache.end()) { return it->second; @@ -70,32 +72,34 @@ VkFramebuffer FramebufferCache::GetFramebuffer(const FramebufferCacheKey& Key, u else { VkFramebufferCreateInfo FramebufferCI = {}; - FramebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - FramebufferCI.pNext = nullptr; - FramebufferCI.flags = 0; // reserved for future use - FramebufferCI.renderPass = Key.Pass; + + FramebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + FramebufferCI.pNext = nullptr; + FramebufferCI.flags = 0; // reserved for future use + FramebufferCI.renderPass = Key.Pass; FramebufferCI.attachmentCount = (Key.DSV != VK_NULL_HANDLE ? 1 : 0) + Key.NumRenderTargets; VkImageView Attachments[1 + MaxRenderTargets]; - uint32_t attachment = 0; + uint32_t attachment = 0; if (Key.DSV != VK_NULL_HANDLE) Attachments[attachment++] = Key.DSV; - for (Uint32 rt=0; rt < Key.NumRenderTargets; ++rt) + for (Uint32 rt = 0; rt < Key.NumRenderTargets; ++rt) Attachments[attachment++] = Key.RTVs[rt]; VERIFY_EXPR(attachment == FramebufferCI.attachmentCount); FramebufferCI.pAttachments = Attachments; - FramebufferCI.width = width; - FramebufferCI.height = height; - FramebufferCI.layers = layers; - auto Framebuffer = m_DeviceVk.GetLogicalDevice().CreateFramebuffer(FramebufferCI); - VkFramebuffer fb = Framebuffer; + FramebufferCI.width = width; + FramebufferCI.height = height; + FramebufferCI.layers = layers; + auto Framebuffer = m_DeviceVk.GetLogicalDevice().CreateFramebuffer(FramebufferCI); + VkFramebuffer fb = Framebuffer; auto new_it = m_Cache.insert(std::make_pair(Key, std::move(Framebuffer))); - VERIFY(new_it.second, "New framebuffer must be inserted into the map"); (void)new_it; + VERIFY(new_it.second, "New framebuffer must be inserted into the map"); + (void)new_it; m_RenderPassToKeyMap.emplace(Key.Pass, Key); if (Key.DSV != VK_NULL_HANDLE) m_ViewToKeyMap.emplace(Key.DSV, Key); - for (Uint32 rt=0; rt < Key.NumRenderTargets; ++rt) + for (Uint32 rt = 0; rt < Key.NumRenderTargets; ++rt) if (Key.RTVs[rt] != VK_NULL_HANDLE) m_ViewToKeyMap.emplace(Key.RTVs[rt], Key); @@ -112,11 +116,12 @@ FramebufferCache::~FramebufferCache() void FramebufferCache::OnDestroyImageView(VkImageView ImgView) { - // TODO: when a render pass is released, we need to also destroy + // TODO: when a render pass is released, we need to also destroy // all entries in the m_ViewToKeyMap that refer to all keys with // that render pass std::lock_guard Lock{m_Mutex}; + auto equal_range = m_ViewToKeyMap.equal_range(ImgView); for (auto it = equal_range.first; it != equal_range.second; ++it) { @@ -134,10 +139,11 @@ void FramebufferCache::OnDestroyImageView(VkImageView ImgView) void FramebufferCache::OnDestroyRenderPass(VkRenderPass Pass) { - // TODO: when an image view is released, we need to also destroy + // TODO: when an image view is released, we need to also destroy // all entries in the m_RenderPassToKeyMap that refer to the keys // with the same image view std::lock_guard Lock{m_Mutex}; + auto equal_range = m_RenderPassToKeyMap.equal_range(Pass); for (auto it = equal_range.first; it != equal_range.second; ++it) { @@ -153,4 +159,4 @@ void FramebufferCache::OnDestroyRenderPass(VkRenderPass Pass) m_RenderPassToKeyMap.erase(equal_range.first, equal_range.second); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp index 112c0bf3..cfa8ff75 100644 --- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp +++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp @@ -35,419 +35,434 @@ #include "../../GraphicsTools/include/CommonlyUsedStates.h" -static const char* g_GenerateMipsCSSource = +// clang-format off +static const char* g_GenerateMipsCSSource = { #include "../shaders/GenerateMipsCS_inc.h" }; +// clang-format on namespace Diligent { - void GenerateMipsVkHelper::GetGlImageFormat(const TextureFormatAttribs& FmtAttribs, std::array& GlFmt) - { - size_t pos = 0; - GlFmt[pos++] = 'r'; - if(FmtAttribs.NumComponents >= 2) - GlFmt[pos++] = 'g'; - if(FmtAttribs.NumComponents >= 3) - GlFmt[pos++] = 'b'; - if(FmtAttribs.NumComponents >= 4) - GlFmt[pos++] = 'a'; - VERIFY_EXPR(FmtAttribs.NumComponents <= 4); - auto ComponentSize = Uint32{FmtAttribs.ComponentSize} * 8; - int pow10 = 1; - while(ComponentSize / (10*pow10) != 0) - pow10 *= 10; - VERIFY_EXPR(ComponentSize !=0); - while(ComponentSize != 0) - { - char digit = static_cast(ComponentSize/pow10); - GlFmt[pos++] = '0' + digit; - ComponentSize -= digit * pow10; - pow10 /= 10; - } - - switch(FmtAttribs.ComponentType) - { - case COMPONENT_TYPE_FLOAT: - GlFmt[pos++] = 'f'; - break; - - case COMPONENT_TYPE_UNORM: - case COMPONENT_TYPE_UNORM_SRGB: - // No suffix - break; - - case COMPONENT_TYPE_SNORM: - GlFmt[pos++] = '_'; - GlFmt[pos++] = 's'; - GlFmt[pos++] = 'n'; - GlFmt[pos++] = 'o'; - GlFmt[pos++] = 'r'; - GlFmt[pos++] = 'm'; - break; - - case COMPONENT_TYPE_SINT: - GlFmt[pos++] = 'i'; - break; - - case COMPONENT_TYPE_UINT: - GlFmt[pos++] = 'u'; - GlFmt[pos++] = 'i'; - break; - - default: - UNSUPPORTED("Unsupported component type"); - } - GlFmt[pos] = 0; +void GenerateMipsVkHelper::GetGlImageFormat(const TextureFormatAttribs& FmtAttribs, std::array& GlFmt) +{ + size_t pos = 0; + GlFmt[pos++] = 'r'; + if (FmtAttribs.NumComponents >= 2) + GlFmt[pos++] = 'g'; + if (FmtAttribs.NumComponents >= 3) + GlFmt[pos++] = 'b'; + if (FmtAttribs.NumComponents >= 4) + GlFmt[pos++] = 'a'; + VERIFY_EXPR(FmtAttribs.NumComponents <= 4); + auto ComponentSize = Uint32{FmtAttribs.ComponentSize} * 8; + + int pow10 = 1; + while (ComponentSize / (10 * pow10) != 0) + pow10 *= 10; + VERIFY_EXPR(ComponentSize != 0); + while (ComponentSize != 0) + { + char digit = static_cast(ComponentSize / pow10); + GlFmt[pos++] = '0' + digit; + ComponentSize -= digit * pow10; + pow10 /= 10; } - std::array, 4> GenerateMipsVkHelper::CreatePSOs(TEXTURE_FORMAT Fmt) + switch (FmtAttribs.ComponentType) { - ShaderCreateInfo CSCreateInfo; - std::array, 4> PSOs; - - CSCreateInfo.Source = g_GenerateMipsCSSource; - CSCreateInfo.EntryPoint = "main"; - CSCreateInfo.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL; - CSCreateInfo.Desc.ShaderType = SHADER_TYPE_COMPUTE; - - const auto& FmtAttribs = GetTextureFormatAttribs(Fmt); - bool IsGamma = FmtAttribs.ComponentType == COMPONENT_TYPE_UNORM_SRGB; - std::array GlFmt; - GetGlImageFormat(FmtAttribs, GlFmt); - - for (Int32 NonPowOfTwo=0; NonPowOfTwo < 4; ++NonPowOfTwo) - { - ShaderMacroHelper Macros; - Macros.AddShaderMacro("NON_POWER_OF_TWO", NonPowOfTwo); - Macros.AddShaderMacro("CONVERT_TO_SRGB", IsGamma); - Macros.AddShaderMacro("IMG_FORMAT", GlFmt.data()); + case COMPONENT_TYPE_FLOAT: + GlFmt[pos++] = 'f'; + break; + + case COMPONENT_TYPE_UNORM: + case COMPONENT_TYPE_UNORM_SRGB: + // No suffix + break; + + case COMPONENT_TYPE_SNORM: + GlFmt[pos++] = '_'; + GlFmt[pos++] = 's'; + GlFmt[pos++] = 'n'; + GlFmt[pos++] = 'o'; + GlFmt[pos++] = 'r'; + GlFmt[pos++] = 'm'; + break; + + case COMPONENT_TYPE_SINT: + GlFmt[pos++] = 'i'; + break; + + case COMPONENT_TYPE_UINT: + GlFmt[pos++] = 'u'; + GlFmt[pos++] = 'i'; + break; + + default: + UNSUPPORTED("Unsupported component type"); + } + + GlFmt[pos] = 0; +} - Macros.Finalize(); - CSCreateInfo.Macros = Macros; +std::array, 4> GenerateMipsVkHelper::CreatePSOs(TEXTURE_FORMAT Fmt) +{ + ShaderCreateInfo CSCreateInfo; - std::stringstream name_ss; - name_ss << "Generate mips " << GlFmt.data(); - switch(NonPowOfTwo) - { - case 0: name_ss << " even"; break; - case 1: name_ss << " odd X"; break; - case 2: name_ss << " odd Y"; break; - case 3: name_ss << " odd XY"; break; - default: UNEXPECTED("Unexpected value"); - } - auto name = name_ss.str(); - CSCreateInfo.Desc.Name = name.c_str(); - RefCntAutoPtr pCS; - - m_DeviceVkImpl.CreateShader(CSCreateInfo, &pCS); - PipelineStateDesc PSODesc; - PSODesc.IsComputePipeline = true; - PSODesc.Name = name.c_str(); - PSODesc.ComputePipeline.pCS = pCS; - - PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; - ShaderResourceVariableDesc VarDesc{SHADER_TYPE_COMPUTE, "CB", SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - PSODesc.ResourceLayout.Variables = &VarDesc; - PSODesc.ResourceLayout.NumVariables = 1; - - const StaticSamplerDesc StaticSampler(SHADER_TYPE_COMPUTE, "SrcMip", Sam_LinearClamp); - PSODesc.ResourceLayout.StaticSamplers = &StaticSampler; - PSODesc.ResourceLayout.NumStaticSamplers = 1; - - m_DeviceVkImpl.CreatePipelineState(PSODesc, &PSOs[NonPowOfTwo]); - PSOs[NonPowOfTwo]->GetStaticVariableByName(SHADER_TYPE_COMPUTE, "CB")->Set(m_ConstantsCB); - } + std::array, 4> PSOs; - return PSOs; - } + CSCreateInfo.Source = g_GenerateMipsCSSource; + CSCreateInfo.EntryPoint = "main"; + CSCreateInfo.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL; + CSCreateInfo.Desc.ShaderType = SHADER_TYPE_COMPUTE; + + const auto& FmtAttribs = GetTextureFormatAttribs(Fmt); + bool IsGamma = FmtAttribs.ComponentType == COMPONENT_TYPE_UNORM_SRGB; - GenerateMipsVkHelper::GenerateMipsVkHelper(RenderDeviceVkImpl& DeviceVkImpl) : - m_DeviceVkImpl(DeviceVkImpl) + std::array GlFmt; + GetGlImageFormat(FmtAttribs, GlFmt); + + for (Int32 NonPowOfTwo = 0; NonPowOfTwo < 4; ++NonPowOfTwo) { - BufferDesc ConstantsCBDesc; - ConstantsCBDesc.Name = "Constants CB buffer"; - ConstantsCBDesc.BindFlags = BIND_UNIFORM_BUFFER; - ConstantsCBDesc.Usage = USAGE_DYNAMIC; - ConstantsCBDesc.CPUAccessFlags = CPU_ACCESS_WRITE; - ConstantsCBDesc.uiSizeInBytes = 32; - DeviceVkImpl.CreateBuffer(ConstantsCBDesc, nullptr, &m_ConstantsCB); - - FindPSOs(TEX_FORMAT_RGBA8_UNORM); - FindPSOs(TEX_FORMAT_BGRA8_UNORM); + ShaderMacroHelper Macros; + Macros.AddShaderMacro("NON_POWER_OF_TWO", NonPowOfTwo); + Macros.AddShaderMacro("CONVERT_TO_SRGB", IsGamma); + Macros.AddShaderMacro("IMG_FORMAT", GlFmt.data()); + + Macros.Finalize(); + CSCreateInfo.Macros = Macros; + + std::stringstream name_ss; + name_ss << "Generate mips " << GlFmt.data(); + switch (NonPowOfTwo) + { + case 0: name_ss << " even"; break; + case 1: name_ss << " odd X"; break; + case 2: name_ss << " odd Y"; break; + case 3: name_ss << " odd XY"; break; + default: UNEXPECTED("Unexpected value"); + } + auto name = name_ss.str(); + CSCreateInfo.Desc.Name = name.c_str(); + RefCntAutoPtr pCS; + + m_DeviceVkImpl.CreateShader(CSCreateInfo, &pCS); + PipelineStateDesc PSODesc; + PSODesc.IsComputePipeline = true; + PSODesc.Name = name.c_str(); + PSODesc.ComputePipeline.pCS = pCS; + + PSODesc.ResourceLayout.DefaultVariableType = SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; + ShaderResourceVariableDesc VarDesc{SHADER_TYPE_COMPUTE, "CB", SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; + PSODesc.ResourceLayout.Variables = &VarDesc; + PSODesc.ResourceLayout.NumVariables = 1; + + const StaticSamplerDesc StaticSampler(SHADER_TYPE_COMPUTE, "SrcMip", Sam_LinearClamp); + PSODesc.ResourceLayout.StaticSamplers = &StaticSampler; + PSODesc.ResourceLayout.NumStaticSamplers = 1; + + m_DeviceVkImpl.CreatePipelineState(PSODesc, &PSOs[NonPowOfTwo]); + PSOs[NonPowOfTwo]->GetStaticVariableByName(SHADER_TYPE_COMPUTE, "CB")->Set(m_ConstantsCB); } - void GenerateMipsVkHelper::CreateSRB(IShaderResourceBinding** ppSRB) + return PSOs; +} + +GenerateMipsVkHelper::GenerateMipsVkHelper(RenderDeviceVkImpl& DeviceVkImpl) : + m_DeviceVkImpl(DeviceVkImpl) +{ + BufferDesc ConstantsCBDesc; + ConstantsCBDesc.Name = "Constants CB buffer"; + ConstantsCBDesc.BindFlags = BIND_UNIFORM_BUFFER; + ConstantsCBDesc.Usage = USAGE_DYNAMIC; + ConstantsCBDesc.CPUAccessFlags = CPU_ACCESS_WRITE; + ConstantsCBDesc.uiSizeInBytes = 32; + DeviceVkImpl.CreateBuffer(ConstantsCBDesc, nullptr, &m_ConstantsCB); + + FindPSOs(TEX_FORMAT_RGBA8_UNORM); + FindPSOs(TEX_FORMAT_BGRA8_UNORM); +} + +void GenerateMipsVkHelper::CreateSRB(IShaderResourceBinding** ppSRB) +{ + // All PSOs are compatible + auto& PSO = FindPSOs(TEX_FORMAT_RGBA8_UNORM); + PSO[0]->CreateShaderResourceBinding(ppSRB, true); +} + +std::array, 4>& GenerateMipsVkHelper::FindPSOs(TEXTURE_FORMAT Fmt) +{ + std::lock_guard Lock{m_PSOMutex}; + + auto it = m_PSOHash.find(Fmt); + if (it == m_PSOHash.end()) + it = m_PSOHash.emplace(Fmt, CreatePSOs(Fmt)).first; + return it->second; +} + +void GenerateMipsVkHelper::WarmUpCache(TEXTURE_FORMAT Fmt) +{ + FindPSOs(Fmt); +} + +void GenerateMipsVkHelper::GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB) +{ + auto* pTexVk = TexView.GetTexture(); + if (!pTexVk->IsInKnownState()) { - // All PSOs are compatible - auto& PSO = FindPSOs(TEX_FORMAT_RGBA8_UNORM); - PSO[0]->CreateShaderResourceBinding(ppSRB, true); + LOG_ERROR_MESSAGE("Unable to generate mips for texture '", pTexVk->GetDesc().Name, "' because the texture state is unknown"); + return; } - std::array, 4>& GenerateMipsVkHelper::FindPSOs(TEXTURE_FORMAT Fmt) + const auto OriginalState = pTexVk->GetState(); + const auto OriginalLayout = pTexVk->GetLayout(); + const auto& TexDesc = pTexVk->GetDesc(); + const auto& ViewDesc = TexView.GetDesc(); + + DEV_CHECK_ERR(ViewDesc.NumMipLevels > 1, "Number of mip levels in the view must be greater than 1"); + DEV_CHECK_ERR(OriginalState != RESOURCE_STATE_UNDEFINED, + "Attempting to generate mipmaps for texture '", TexDesc.Name, + "' which is in RESOURCE_STATE_UNDEFINED state ." + "This is not expected in Vulkan backend as textures are transition to a defined state when created."); + (void)OriginalState; + + const auto& FmtAttribs = GetTextureFormatAttribs(ViewDesc.Format); + + VkImageSubresourceRange SubresRange = {}; + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) { - std::lock_guard Lock{m_PSOMutex}; - auto it = m_PSOHash.find(Fmt); - if(it == m_PSOHash.end()) - it = m_PSOHash.emplace(Fmt, CreatePSOs(Fmt)).first; - return it->second; + // If image has a depth / stencil format with both depth and stencil components, then the + // aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and + // VK_IMAGE_ASPECT_STENCIL_BIT (6.7.3) + SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; } - - void GenerateMipsVkHelper::WarmUpCache(TEXTURE_FORMAT Fmt) + else + SubresRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + SubresRange.baseArrayLayer = ViewDesc.FirstArraySlice; + SubresRange.layerCount = ViewDesc.NumArraySlices; + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = 1; + + VkImageLayout AffectedMipLevelLayout; + if (TexView.HasMipLevelViews()) { - FindPSOs(Fmt); + AffectedMipLevelLayout = GenerateMipsCS(TexView, Ctx, SRB, SubresRange); } - - void GenerateMipsVkHelper::GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB) + else { - auto* pTexVk = TexView.GetTexture(); - if (!pTexVk->IsInKnownState()) - { - LOG_ERROR_MESSAGE("Unable to generate mips for texture '", pTexVk->GetDesc().Name, "' because the texture state is unknown"); - return; - } + AffectedMipLevelLayout = GenerateMipsBlit(TexView, Ctx, SRB, SubresRange); + } - const auto OriginalState = pTexVk->GetState(); - const auto OriginalLayout = pTexVk->GetLayout(); - const auto& TexDesc = pTexVk->GetDesc(); - const auto& ViewDesc = TexView.GetDesc(); - - DEV_CHECK_ERR(ViewDesc.NumMipLevels > 1, "Number of mip levels in the view must be greater than 1"); - DEV_CHECK_ERR(OriginalState != RESOURCE_STATE_UNDEFINED, - "Attempting to generate mipmaps for texture '", TexDesc.Name, "' which is in RESOURCE_STATE_UNDEFINED state ." - "This is not expected in Vulkan backend as textures are transition to a defined state when created."); (void)OriginalState; - - const auto& FmtAttribs = GetTextureFormatAttribs(ViewDesc.Format); - VkImageSubresourceRange SubresRange = {}; - if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) - SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) - { - // If image has a depth / stencil format with both depth and stencil components, then the - // aspectMask member of subresourceRange must include both VK_IMAGE_ASPECT_DEPTH_BIT and - // VK_IMAGE_ASPECT_STENCIL_BIT (6.7.3) - SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } - else - SubresRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - SubresRange.baseArrayLayer = ViewDesc.FirstArraySlice; - SubresRange.layerCount = ViewDesc.NumArraySlices; - SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; - SubresRange.levelCount = 1; - - VkImageLayout AffectedMipLevelLayout; - if (TexView.HasMipLevelViews()) + // All affected mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state + if (AffectedMipLevelLayout != OriginalLayout) + { + bool IsAllSlices = (TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY && + TexDesc.Type != RESOURCE_DIM_TEX_2D_ARRAY && + TexDesc.Type != RESOURCE_DIM_TEX_CUBE_ARRAY) || + TexDesc.ArraySize == ViewDesc.NumArraySlices; + bool IsAllMips = ViewDesc.NumMipLevels == TexDesc.MipLevels; + if (IsAllSlices && IsAllMips) { - AffectedMipLevelLayout = GenerateMipsCS(TexView, Ctx, SRB, SubresRange); + pTexVk->SetLayout(AffectedMipLevelLayout); } else { - AffectedMipLevelLayout = GenerateMipsBlit(TexView, Ctx, SRB, SubresRange); - } - - // All affected mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state - if (AffectedMipLevelLayout != OriginalLayout) - { - bool IsAllSlices = (TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY && - TexDesc.Type != RESOURCE_DIM_TEX_2D_ARRAY && - TexDesc.Type != RESOURCE_DIM_TEX_CUBE_ARRAY) || - TexDesc.ArraySize == ViewDesc.NumArraySlices; - bool IsAllMips = ViewDesc.NumMipLevels == TexDesc.MipLevels; - if (IsAllSlices && IsAllMips) - { - pTexVk->SetLayout(AffectedMipLevelLayout); - } - else - { - VERIFY(OriginalLayout != VK_IMAGE_LAYOUT_UNDEFINED, "Original layout must not be undefined"); - SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; - SubresRange.levelCount = ViewDesc.NumMipLevels; - // Transition all affected subresources back to original layout - Ctx.TransitionImageLayout(*pTexVk, AffectedMipLevelLayout, OriginalLayout, SubresRange); - VERIFY_EXPR(pTexVk->GetLayout() == OriginalLayout); - } + VERIFY(OriginalLayout != VK_IMAGE_LAYOUT_UNDEFINED, "Original layout must not be undefined"); + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = ViewDesc.NumMipLevels; + // Transition all affected subresources back to original layout + Ctx.TransitionImageLayout(*pTexVk, AffectedMipLevelLayout, OriginalLayout, SubresRange); + VERIFY_EXPR(pTexVk->GetLayout() == OriginalLayout); } } +} - VkImageLayout GenerateMipsVkHelper::GenerateMipsCS(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange) - { - auto* pTexVk = TexView.GetTexture(); - const auto& TexDesc = pTexVk->GetDesc(); - - VERIFY(TexDesc.Type == RESOURCE_DIM_TEX_2D || TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY, - "CS-based mipmap generation is only supported for 2D textures and texture arrays"); - - const auto& ViewDesc = TexView.GetDesc(); - auto* pSrcMipVar = SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "SrcMip"); - IShaderResourceVariable* pOutMipVar[4] = +VkImageLayout GenerateMipsVkHelper::GenerateMipsCS(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange) +{ + auto* pTexVk = TexView.GetTexture(); + const auto& TexDesc = pTexVk->GetDesc(); + + VERIFY(TexDesc.Type == RESOURCE_DIM_TEX_2D || TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY, + "CS-based mipmap generation is only supported for 2D textures and texture arrays"); + + const auto& ViewDesc = TexView.GetDesc(); + auto* pSrcMipVar = SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "SrcMip"); + + IShaderResourceVariable* pOutMipVar[4] = { SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip0"), SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip1"), SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip2"), - SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip3") + SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip3") // }; - auto& PSOs = FindPSOs(ViewDesc.Format); - - const auto OriginalState = pTexVk->GetState(); - const auto OriginalLayout = pTexVk->GetLayout(); - - // Transition the lowest mip level to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; - SubresRange.levelCount = 1; - if (OriginalState != RESOURCE_STATE_SHADER_RESOURCE) - Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_SHADER_RESOURCE, false /*UpdateTextureState*/, &SubresRange); - VERIFY_EXPR(ResourceStateToVkImageLayout(RESOURCE_STATE_SHADER_RESOURCE) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - // Note that mip levels are relative to the view's most detailed mip - auto BottomMip = ViewDesc.NumMipLevels - 1; - for (uint32_t TopMip = 0; TopMip < BottomMip; ) - { - // In Vulkan, all subresources of a view must be transitioned to the same layout, so - // we can't bind the entire texture and have to bind single mip level at a time - auto SrcMipLevelSRV = TexView.GetMipLevelSRV(TopMip); - VERIFY_EXPR(SrcMipLevelSRV != nullptr); - pSrcMipVar->Set(SrcMipLevelSRV); - - uint32_t SrcWidth = std::max(TexDesc.Width >> (TopMip + ViewDesc.MostDetailedMip), 1u); - uint32_t SrcHeight = std::max(TexDesc.Height >> (TopMip + ViewDesc.MostDetailedMip), 1u); - uint32_t DstWidth = std::max(SrcWidth >> 1, 1u); - uint32_t DstHeight = std::max(SrcHeight >> 1, 1u); - - // 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; - Ctx.SetPipelineState(PSOs[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 = PlatformMisc::GetLSB(DstWidth | DstHeight); - uint32_t NumMips = 1 + (AdditionalMips > 3 ? 3 : AdditionalMips); - if (TopMip + NumMips > BottomMip) - NumMips = BottomMip - 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; + auto& PSOs = FindPSOs(ViewDesc.Format); + + const auto OriginalState = pTexVk->GetState(); + const auto OriginalLayout = pTexVk->GetLayout(); + + // Transition the lowest mip level to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = 1; + if (OriginalState != RESOURCE_STATE_SHADER_RESOURCE) + Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_SHADER_RESOURCE, false /*UpdateTextureState*/, &SubresRange); + VERIFY_EXPR(ResourceStateToVkImageLayout(RESOURCE_STATE_SHADER_RESOURCE) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + // Note that mip levels are relative to the view's most detailed mip + auto BottomMip = ViewDesc.NumMipLevels - 1; + for (uint32_t TopMip = 0; TopMip < BottomMip;) + { + // In Vulkan, all subresources of a view must be transitioned to the same layout, so + // we can't bind the entire texture and have to bind single mip level at a time + auto SrcMipLevelSRV = TexView.GetMipLevelSRV(TopMip); + VERIFY_EXPR(SrcMipLevelSRV != nullptr); + pSrcMipVar->Set(SrcMipLevelSRV); + + uint32_t SrcWidth = std::max(TexDesc.Width >> (TopMip + ViewDesc.MostDetailedMip), 1u); + uint32_t SrcHeight = std::max(TexDesc.Height >> (TopMip + ViewDesc.MostDetailedMip), 1u); + uint32_t DstWidth = std::max(SrcWidth >> 1, 1u); + uint32_t DstHeight = std::max(SrcHeight >> 1, 1u); + + // 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; + Ctx.SetPipelineState(PSOs[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 = PlatformMisc::GetLSB(DstWidth | DstHeight); + uint32_t NumMips = 1 + (AdditionalMips > 3 ? 3 : AdditionalMips); + if (TopMip + NumMips > BottomMip) + NumMips = BottomMip - 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; + { + struct CBData { - struct CBData - { - Int32 SrcMipLevel; // Texture level of source mip - Int32 NumMipLevels; // Number of OutMips to write: [1, 4] - Int32 ArraySlice; - Int32 Dummy; - float TexelSize[2]; // 1.0 / OutMip1.Dimensions - }; - MapHelper MappedData(&Ctx, m_ConstantsCB, MAP_WRITE, MAP_FLAG_DISCARD); - - *MappedData = + Int32 SrcMipLevel; // Texture level of source mip + Int32 NumMipLevels; // Number of OutMips to write: [1, 4] + Int32 ArraySlice; + Int32 Dummy; + float TexelSize[2]; // 1.0 / OutMip1.Dimensions + }; + MapHelper MappedData(&Ctx, m_ConstantsCB, MAP_WRITE, MAP_FLAG_DISCARD); + + *MappedData = { static_cast(TopMip), // Mip levels are relateive to the view's most detailed mip static_cast(NumMips), 0, // Array slices are relative to the view's first array slice 0, // Unused - {1.0f / static_cast(DstWidth), 1.0f / static_cast(DstHeight)} + { + 1.0f / static_cast(DstWidth), 1.0f / static_cast(DstHeight) // + } // }; - } - - constexpr const Uint32 MaxMipsHandledByCS = 4; // Max number of mip levels processed by one CS shader invocation - for (Uint32 u = 0; u < MaxMipsHandledByCS; ++u) - { - auto* MipLevelUAV = TexView.GetMipLevelUAV(TopMip + std::min(u + 1, NumMips)); - pOutMipVar[u]->Set(MipLevelUAV); - } + } - SubresRange.baseMipLevel = ViewDesc.MostDetailedMip + TopMip + 1; - SubresRange.levelCount = NumMips; - if (OriginalLayout != VK_IMAGE_LAYOUT_GENERAL) - Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_GENERAL, SubresRange); + constexpr const Uint32 MaxMipsHandledByCS = 4; // Max number of mip levels processed by one CS shader invocation + for (Uint32 u = 0; u < MaxMipsHandledByCS; ++u) + { + auto* MipLevelUAV = TexView.GetMipLevelUAV(TopMip + std::min(u + 1, NumMips)); + pOutMipVar[u]->Set(MipLevelUAV); + } - Ctx.CommitShaderResources(&SRB, RESOURCE_STATE_TRANSITION_MODE_NONE); - DispatchComputeAttribs DispatchAttrs((DstWidth + 7) / 8, (DstHeight + 7) / 8, ViewDesc.NumArraySlices); - Ctx.DispatchCompute(DispatchAttrs); + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip + TopMip + 1; + SubresRange.levelCount = NumMips; + if (OriginalLayout != VK_IMAGE_LAYOUT_GENERAL) + Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_GENERAL, SubresRange); - Ctx.TransitionImageLayout(*pTexVk, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresRange); + Ctx.CommitShaderResources(&SRB, RESOURCE_STATE_TRANSITION_MODE_NONE); + DispatchComputeAttribs DispatchAttrs((DstWidth + 7) / 8, (DstHeight + 7) / 8, ViewDesc.NumArraySlices); + Ctx.DispatchCompute(DispatchAttrs); - TopMip += NumMips; - } + Ctx.TransitionImageLayout(*pTexVk, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, SubresRange); - return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + TopMip += NumMips; } - VkImageLayout GenerateMipsVkHelper::GenerateMipsBlit(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange)const + return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; +} + +VkImageLayout GenerateMipsVkHelper::GenerateMipsBlit(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange) const +{ + auto* pTexVk = TexView.GetTexture(); + const auto& TexDesc = pTexVk->GetDesc(); + const auto& ViewDesc = TexView.GetDesc(); + auto vkImage = pTexVk->GetVkImage(); + + const auto OriginalState = pTexVk->GetState(); + const auto OriginalLayout = ResourceStateToVkImageLayout(OriginalState); + + VkImageBlit BlitRegion = {}; + + BlitRegion.srcSubresource.baseArrayLayer = ViewDesc.FirstArraySlice; + BlitRegion.srcSubresource.layerCount = ViewDesc.NumArraySlices; + BlitRegion.srcSubresource.aspectMask = SubresRange.aspectMask; + BlitRegion.dstSubresource.baseArrayLayer = BlitRegion.srcSubresource.baseArrayLayer; + BlitRegion.dstSubresource.layerCount = BlitRegion.srcSubresource.layerCount; + BlitRegion.dstSubresource.aspectMask = BlitRegion.srcSubresource.aspectMask; + BlitRegion.srcOffsets[0] = VkOffset3D{0, 0, 0}; + BlitRegion.dstOffsets[0] = VkOffset3D{0, 0, 0}; + + SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; + SubresRange.levelCount = 1; + if (OriginalState != RESOURCE_STATE_COPY_SOURCE) + Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_COPY_SOURCE, false /*UpdateTextureState*/, &SubresRange); + + auto& CmdBuffer = Ctx.GetCommandBuffer(); + for (uint32_t mip = ViewDesc.MostDetailedMip + 1; mip < ViewDesc.MostDetailedMip + ViewDesc.NumMipLevels; ++mip) { - auto* pTexVk = TexView.GetTexture(); - const auto& TexDesc = pTexVk->GetDesc(); - const auto& ViewDesc = TexView.GetDesc(); - auto vkImage = pTexVk->GetVkImage(); - - const auto OriginalState = pTexVk->GetState(); - const auto OriginalLayout = ResourceStateToVkImageLayout(OriginalState); - - VkImageBlit BlitRegion = {}; - BlitRegion.srcSubresource.baseArrayLayer = ViewDesc.FirstArraySlice; - BlitRegion.srcSubresource.layerCount = ViewDesc.NumArraySlices; - BlitRegion.srcSubresource.aspectMask = SubresRange.aspectMask; - BlitRegion.dstSubresource.baseArrayLayer = BlitRegion.srcSubresource.baseArrayLayer; - BlitRegion.dstSubresource.layerCount = BlitRegion.srcSubresource.layerCount; - BlitRegion.dstSubresource.aspectMask = BlitRegion.srcSubresource.aspectMask; - BlitRegion.srcOffsets[0] = VkOffset3D{0, 0, 0}; - BlitRegion.dstOffsets[0] = VkOffset3D{0, 0, 0}; - - SubresRange.baseMipLevel = ViewDesc.MostDetailedMip; - SubresRange.levelCount = 1; - if (OriginalState != RESOURCE_STATE_COPY_SOURCE) - Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_COPY_SOURCE, false /*UpdateTextureState*/, &SubresRange); - - auto& CmdBuffer = Ctx.GetCommandBuffer(); - for (uint32_t mip = ViewDesc.MostDetailedMip + 1; mip < ViewDesc.MostDetailedMip + ViewDesc.NumMipLevels; ++mip) - { - BlitRegion.srcSubresource.mipLevel = mip-1; - BlitRegion.dstSubresource.mipLevel = mip; - - BlitRegion.srcOffsets[1] = - VkOffset3D - { - static_cast(std::max(TexDesc.Width >> (mip-1), 1u)), - static_cast(std::max(TexDesc.Height >> (mip-1), 1u)), - 1 - }; - BlitRegion.dstOffsets[1] = - VkOffset3D - { - static_cast(std::max(TexDesc.Width >> mip, 1u)), - static_cast(std::max(TexDesc.Height >> mip, 1u)), - 1 - }; - if (TexDesc.Type == RESOURCE_DIM_TEX_3D) + BlitRegion.srcSubresource.mipLevel = mip - 1; + BlitRegion.dstSubresource.mipLevel = mip; + + BlitRegion.srcOffsets[1] = + VkOffset3D // + { + static_cast(std::max(TexDesc.Width >> (mip - 1), 1u)), + static_cast(std::max(TexDesc.Height >> (mip - 1), 1u)), + 1 // + }; + BlitRegion.dstOffsets[1] = + VkOffset3D // { - BlitRegion.srcOffsets[1].z = std::max(TexDesc.Depth >> (mip-1), 1u); - BlitRegion.dstOffsets[1].z = std::max(TexDesc.Depth >> mip, 1u); - } - - SubresRange.baseMipLevel = mip; - if (OriginalLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange); - - CmdBuffer.BlitImage(vkImage, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL - vkImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL - 1, - &BlitRegion, - VK_FILTER_LINEAR); - Ctx.TransitionImageLayout(*pTexVk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, SubresRange); + static_cast(std::max(TexDesc.Width >> mip, 1u)), + static_cast(std::max(TexDesc.Height >> mip, 1u)), + 1 // + }; + if (TexDesc.Type == RESOURCE_DIM_TEX_3D) + { + BlitRegion.srcOffsets[1].z = std::max(TexDesc.Depth >> (mip - 1), 1u); + BlitRegion.dstOffsets[1].z = std::max(TexDesc.Depth >> mip, 1u); } - return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + SubresRange.baseMipLevel = mip; + if (OriginalLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange); + + CmdBuffer.BlitImage(vkImage, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL + vkImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL + 1, + &BlitRegion, + VK_FILTER_LINEAR); + Ctx.TransitionImageLayout(*pTexVk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, SubresRange); } + + return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; } + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index 5179f38f..cda19a9a 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -39,16 +39,17 @@ namespace Diligent static VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType) { - switch(ShaderType) + switch (ShaderType) { + // clang-format off case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; - - default: + // clang-format on + default: UNEXPECTED("Unknown shader type"); return VK_SHADER_STAGE_VERTEX_BIT; } @@ -72,7 +73,7 @@ public: m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateSampler] = VK_DESCRIPTOR_TYPE_SAMPLER; } - VkDescriptorType operator[](SPIRVShaderResourceAttribs::ResourceType ResType)const + VkDescriptorType operator[](SPIRVShaderResourceAttribs::ResourceType ResType) const { return m_Map[static_cast(ResType)]; } @@ -81,26 +82,26 @@ private: std::array m_Map = {}; }; -VkDescriptorType PipelineLayout::GetVkDescriptorType(const SPIRVShaderResourceAttribs &Res) +VkDescriptorType PipelineLayout::GetVkDescriptorType(const SPIRVShaderResourceAttribs& Res) { static const ResourceTypeToVkDescriptorType ResTypeToVkDescrType; return ResTypeToVkDescrType[Res.Type]; } -PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayoutManager(IMemoryAllocator &MemAllocator): - m_MemAllocator {MemAllocator}, +PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayoutManager(IMemoryAllocator& MemAllocator) : + m_MemAllocator{MemAllocator}, m_LayoutBindings{STD_ALLOCATOR_RAW_MEM(VkDescriptorSetLayoutBinding, MemAllocator, "Allocator for Layout Bindings")} {} -void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::AddBinding(const VkDescriptorSetLayoutBinding &Binding, IMemoryAllocator &MemAllocator) +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::AddBinding(const VkDescriptorSetLayoutBinding& Binding, IMemoryAllocator& MemAllocator) { VERIFY(VkLayout == VK_NULL_HANDLE, "Descriptor set must not be finalized"); ReserveMemory(NumLayoutBindings + 1, MemAllocator); pBindings[NumLayoutBindings++] = Binding; TotalDescriptors += Binding.descriptorCount; - if (Binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || - Binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) + if (Binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || + Binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { VERIFY(NumDynamicDescriptors + Binding.descriptorCount <= std::numeric_limits::max(), "Number of dynamic descriptors exceeds max representable value"); NumDynamicDescriptors += static_cast(Binding.descriptorCount); @@ -121,25 +122,25 @@ size_t PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::GetMemor // NumBindings = 2^n // n n-1 2 1 0 // 2^n = 1 0 ... 0 0 0 - // + // // n n-1 2 1 0 // 2^n-1 = 0 1 ... 1 1 1 - // msb = n-1 + // msb = n-1 // MemSize = 2^n // NumBindings = 2^n + [1 .. 2^n-1] - // n n-1 - // 2^n = 1 0 ... 1 ... - // - // n n-1 - // 2^n-1 = 1 0 ... - // msb = n + // n n-1 + // 2^n = 1 0 ... 1 ... + // + // n n-1 + // 2^n-1 = 1 0 ... + // msb = n // MemSize = 2^(n+1) - MemSize = Uint32{2U << PlatformMisc::GetMSB(NumBindings-1)}; + MemSize = Uint32{2U << PlatformMisc::GetMSB(NumBindings - 1)}; } - VERIFY_EXPR( ((NumBindings & (NumBindings-1)) == 0) && NumBindings == MemSize || NumBindings < MemSize); + VERIFY_EXPR(((NumBindings & (NumBindings - 1)) == 0) && NumBindings == MemSize || NumBindings < MemSize); #ifdef _DEBUG static constexpr size_t MinMemSize = 1; @@ -150,7 +151,7 @@ size_t PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::GetMemor return MemSize * sizeof(VkDescriptorSetLayoutBinding); } -void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::ReserveMemory(Uint32 NumBindings, IMemoryAllocator &MemAllocator) +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::ReserveMemory(Uint32 NumBindings, IMemoryAllocator& MemAllocator) { size_t ReservedMemory = GetMemorySize(NumLayoutBindings); size_t RequiredMemory = GetMemorySize(NumBindings); @@ -166,33 +167,34 @@ void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::ReserveMem } } -void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice, - IMemoryAllocator &MemAllocator, - VkDescriptorSetLayoutBinding* pNewBindings) +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + IMemoryAllocator& MemAllocator, + VkDescriptorSetLayoutBinding* pNewBindings) { - VERIFY_EXPR( memcmp(pBindings, pNewBindings, sizeof(VkDescriptorSetLayoutBinding)*NumLayoutBindings) == 0 ); + VERIFY_EXPR(memcmp(pBindings, pNewBindings, sizeof(VkDescriptorSetLayoutBinding) * NumLayoutBindings) == 0); VkDescriptorSetLayoutCreateInfo SetLayoutCI = {}; - SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - SetLayoutCI.pNext = nullptr; - SetLayoutCI.flags = 0; + + SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + SetLayoutCI.pNext = nullptr; + SetLayoutCI.flags = 0; SetLayoutCI.bindingCount = NumLayoutBindings; - SetLayoutCI.pBindings = pBindings; - VkLayout = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI); + SetLayoutCI.pBindings = pBindings; + VkLayout = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI); MemAllocator.Free(pBindings); pBindings = pNewBindings; } -void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Release(RenderDeviceVkImpl *pRenderDeviceVk, IMemoryAllocator &MemAllocator, Uint64 CommandQueueMask) +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Release(RenderDeviceVkImpl* pRenderDeviceVk, IMemoryAllocator& MemAllocator, Uint64 CommandQueueMask) { pRenderDeviceVk->SafeReleaseDeviceObject(std::move(VkLayout), CommandQueueMask); - for (uint32_t b=0; b < NumLayoutBindings; ++b) + for (uint32_t b = 0; b < NumLayoutBindings; ++b) { if (pBindings[b].pImmutableSamplers != nullptr) MemAllocator.Free(const_cast(pBindings[b].pImmutableSamplers)); } - pBindings = nullptr; + pBindings = nullptr; NumLayoutBindings = 0; } @@ -201,55 +203,60 @@ PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::~DescriptorSetL VERIFY(VkLayout == VK_NULL_HANDLE, "Vulkan descriptor set layout has not been released. Did you forget to call Release()?"); } -bool PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::operator == (const DescriptorSetLayout& rhs)const +bool PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::operator==(const DescriptorSetLayout& rhs) const { + // clang-format off if (TotalDescriptors != rhs.TotalDescriptors || SetIndex != rhs.SetIndex || NumDynamicDescriptors != rhs.NumDynamicDescriptors || NumLayoutBindings != rhs.NumLayoutBindings) return false; + // clang-format on - for(uint32_t b=0; b < NumLayoutBindings; ++b) + for (uint32_t b = 0; b < NumLayoutBindings; ++b) { - const auto &B0 = pBindings[b]; - const auto &B1 = rhs.pBindings[b]; + const auto& B0 = pBindings[b]; + const auto& B1 = rhs.pBindings[b]; + // clang-format off if (B0.binding != B1.binding || B0.descriptorType != B1.descriptorType || B0.descriptorCount != B1.descriptorCount || B0.stageFlags != B1.stageFlags) return false; - if ( (B0.pImmutableSamplers != nullptr && B1.pImmutableSamplers == nullptr) || - (B0.pImmutableSamplers == nullptr && B1.pImmutableSamplers != nullptr) ) + if ((B0.pImmutableSamplers != nullptr && B1.pImmutableSamplers == nullptr) || + (B0.pImmutableSamplers == nullptr && B1.pImmutableSamplers != nullptr)) return false; // Static samplers themselves should not affect compatibility + // clang-format on } return true; } -size_t PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::GetHash()const +size_t PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::GetHash() const { size_t Hash = ComputeHash(SetIndex, NumLayoutBindings, TotalDescriptors, NumDynamicDescriptors); for (uint32_t b = 0; b < NumLayoutBindings; ++b) { - const auto &B = pBindings[b]; + const auto& B = pBindings[b]; HashCombine(Hash, B.binding, static_cast(B.descriptorType), B.descriptorCount, static_cast(B.stageFlags), B.pImmutableSamplers != nullptr); } return Hash; } -void PipelineLayout::DescriptorSetLayoutManager::Finalize(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice) +void PipelineLayout::DescriptorSetLayoutManager::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) { size_t TotalBindings = 0; - for (const auto &Layout : m_DescriptorSetLayouts) + for (const auto& Layout : m_DescriptorSetLayouts) { TotalBindings += Layout.NumLayoutBindings; } m_LayoutBindings.resize(TotalBindings); size_t BindingOffset = 0; + std::array ActiveDescrSetLayouts = {}; - for (auto &Layout : m_DescriptorSetLayouts) + for (auto& Layout : m_DescriptorSetLayouts) { if (Layout.SetIndex >= 0) { @@ -260,26 +267,29 @@ void PipelineLayout::DescriptorSetLayoutManager::Finalize(const VulkanUtilities: } } VERIFY_EXPR(BindingOffset == TotalBindings); + // clang-format off VERIFY_EXPR(m_ActiveSets == 0 && ActiveDescrSetLayouts[0] == VK_NULL_HANDLE && ActiveDescrSetLayouts[1] == VK_NULL_HANDLE || m_ActiveSets == 1 && ActiveDescrSetLayouts[0] != VK_NULL_HANDLE && ActiveDescrSetLayouts[1] == VK_NULL_HANDLE || m_ActiveSets == 2 && ActiveDescrSetLayouts[0] != VK_NULL_HANDLE && ActiveDescrSetLayouts[1] != VK_NULL_HANDLE); + // clang-format on VkPipelineLayoutCreateInfo PipelineLayoutCI = {}; - PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - PipelineLayoutCI.pNext = nullptr; - PipelineLayoutCI.flags = 0; // reserved for future use - PipelineLayoutCI.setLayoutCount = m_ActiveSets; - PipelineLayoutCI.pSetLayouts = PipelineLayoutCI.setLayoutCount != 0 ? ActiveDescrSetLayouts.data() : nullptr; + + PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + PipelineLayoutCI.pNext = nullptr; + PipelineLayoutCI.flags = 0; // reserved for future use + PipelineLayoutCI.setLayoutCount = m_ActiveSets; + PipelineLayoutCI.pSetLayouts = PipelineLayoutCI.setLayoutCount != 0 ? ActiveDescrSetLayouts.data() : nullptr; PipelineLayoutCI.pushConstantRangeCount = 0; - PipelineLayoutCI.pPushConstantRanges = nullptr; - m_VkPipelineLayout = LogicalDevice.CreatePipelineLayout(PipelineLayoutCI); + PipelineLayoutCI.pPushConstantRanges = nullptr; + m_VkPipelineLayout = LogicalDevice.CreatePipelineLayout(PipelineLayoutCI); VERIFY_EXPR(BindingOffset == TotalBindings); } -void PipelineLayout::DescriptorSetLayoutManager::Release(RenderDeviceVkImpl *pRenderDeviceVk, Uint64 CommandQueueMask) +void PipelineLayout::DescriptorSetLayoutManager::Release(RenderDeviceVkImpl* pRenderDeviceVk, Uint64 CommandQueueMask) { - for (auto &Layout : m_DescriptorSetLayouts) + for (auto& Layout : m_DescriptorSetLayouts) Layout.Release(pRenderDeviceVk, m_MemAllocator, CommandQueueMask); pRenderDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), CommandQueueMask); @@ -290,26 +300,26 @@ PipelineLayout::DescriptorSetLayoutManager::~DescriptorSetLayoutManager() VERIFY(m_VkPipelineLayout == VK_NULL_HANDLE, "Vulkan pipeline layout has not been released. Did you forget to call Release()?"); } -bool PipelineLayout::DescriptorSetLayoutManager::operator == (const DescriptorSetLayoutManager& rhs)const +bool PipelineLayout::DescriptorSetLayoutManager::operator==(const DescriptorSetLayoutManager& rhs) const { - // Two pipeline layouts are defined to be “compatible for set N” if they were created with identically - // defined descriptor set layouts for sets zero through N, and if they were created with identical push + // Two pipeline layouts are defined to be "compatible for set N" if they were created with identically + // defined descriptor set layouts for sets zero through N, and if they were created with identical push // constant ranges (13.2.2) if (m_ActiveSets != rhs.m_ActiveSets) return false; - for (size_t i=0; i < m_DescriptorSetLayouts.size(); ++i) + for (size_t i = 0; i < m_DescriptorSetLayouts.size(); ++i) if (m_DescriptorSetLayouts[i] != rhs.m_DescriptorSetLayouts[i]) return false; return true; } -size_t PipelineLayout::DescriptorSetLayoutManager::GetHash()const +size_t PipelineLayout::DescriptorSetLayoutManager::GetHash() const { size_t Hash = 0; - for (const auto &SetLayout : m_DescriptorSetLayouts) + for (const auto& SetLayout : m_DescriptorSetLayouts) HashCombine(Hash, SetLayout.GetHash()); return Hash; @@ -331,19 +341,21 @@ void PipelineLayout::DescriptorSetLayoutManager::AllocateResourceSlot(const SPIR DescriptorSet = DescrSet.SetIndex; VkDescriptorSetLayoutBinding VkBinding = {}; + Binding = DescrSet.NumLayoutBindings; - VkBinding.binding = Binding; - VkBinding.descriptorType = GetVkDescriptorType(ResAttribs); + + VkBinding.binding = Binding; + VkBinding.descriptorType = GetVkDescriptorType(ResAttribs); VkBinding.descriptorCount = ResAttribs.ArraySize; // There are no limitations on what combinations of stages can use a descriptor binding (13.2.1) VkBinding.stageFlags = ShaderTypeToVkShaderStageFlagBit(ShaderType); if (vkImmutableSampler != VK_NULL_HANDLE) { - // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and - // descriptorCount is not 0 and pImmutableSamplers is not NULL, pImmutableSamplers must be a valid pointer + // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, and + // descriptorCount is not 0 and pImmutableSamplers is not NULL, pImmutableSamplers must be a valid pointer // to an array of descriptorCount valid VkSampler handles (13.2.1) auto* pImmutableSamplers = ALLOCATE(m_MemAllocator, "Memory buffer for immutable samplers", VkSampler, VkBinding.descriptorCount); - for (uint32_t s=0; s < VkBinding.descriptorCount; ++s) + for (uint32_t s = 0; s < VkBinding.descriptorCount; ++s) pImmutableSamplers[s] = vkImmutableSampler; VkBinding.pImmutableSamplers = pImmutableSamplers; } @@ -354,13 +366,13 @@ void PipelineLayout::DescriptorSetLayoutManager::AllocateResourceSlot(const SPIR DescrSet.AddBinding(VkBinding, m_MemAllocator); } -PipelineLayout::PipelineLayout() : - m_MemAllocator(GetRawAllocator()), - m_LayoutMgr(m_MemAllocator) +PipelineLayout::PipelineLayout() : + m_MemAllocator{GetRawAllocator()}, + m_LayoutMgr{m_MemAllocator} { } -void PipelineLayout::Release(RenderDeviceVkImpl *pDeviceVkImpl, Uint64 CommandQueueMask) +void PipelineLayout::Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask) { m_LayoutMgr.Release(pDeviceVkImpl, CommandQueueMask); } @@ -370,15 +382,16 @@ void PipelineLayout::AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResA VkSampler vkImmutableSampler, SHADER_TYPE ShaderType, Uint32& DescriptorSet, // Output parameter - Uint32& Binding, // Output parameter + Uint32& Binding, // Output parameter Uint32& OffsetInCache, std::vector& SPIRV) { - VERIFY( (ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || - ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) || vkImmutableSampler == VK_NULL_HANDLE, - "Immutable sampler should only be specified for combined image samplers or separate samplers"); - m_LayoutMgr.AllocateResourceSlot(ResAttribs, VariableType ,vkImmutableSampler, ShaderType, DescriptorSet, Binding, OffsetInCache); - SPIRV[ResAttribs.BindingDecorationOffset] = Binding; + VERIFY((ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) || + vkImmutableSampler == VK_NULL_HANDLE, + "Immutable sampler should only be specified for combined image samplers or separate samplers"); + m_LayoutMgr.AllocateResourceSlot(ResAttribs, VariableType, vkImmutableSampler, ShaderType, DescriptorSet, Binding, OffsetInCache); + SPIRV[ResAttribs.BindingDecorationOffset] = Binding; SPIRV[ResAttribs.DescriptorSetDecorationOffset] = DescriptorSet; } @@ -387,22 +400,22 @@ void PipelineLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice& Logica m_LayoutMgr.Finalize(LogicalDevice); } -std::array PipelineLayout::GetDescriptorSetSizes(Uint32& NumSets)const +std::array PipelineLayout::GetDescriptorSetSizes(Uint32& NumSets) const { - NumSets = 0; + NumSets = 0; std::array SetSizes = {}; - const auto &StaticAndMutSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + const auto& StaticAndMutSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); if (StaticAndMutSet.SetIndex >= 0) { - NumSets = std::max(NumSets, static_cast(StaticAndMutSet.SetIndex + 1)); + NumSets = std::max(NumSets, static_cast(StaticAndMutSet.SetIndex + 1)); SetSizes[StaticAndMutSet.SetIndex] = StaticAndMutSet.TotalDescriptors; } - const auto &DynamicSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC); + const auto& DynamicSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC); if (DynamicSet.SetIndex >= 0) { - NumSets = std::max(NumSets, static_cast(DynamicSet.SetIndex + 1)); + NumSets = std::max(NumSets, static_cast(DynamicSet.SetIndex + 1)); SetSizes[DynamicSet.SetIndex] = DynamicSet.TotalDescriptors; } @@ -412,11 +425,11 @@ std::array PipelineLayout::GetDescriptorSetSizes(Uint32& NumSets)cons void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl, ShaderResourceCacheVk& ResourceCache, IMemoryAllocator& CacheMemAllocator, - const char* DbgPipelineName)const + const char* DbgPipelineName) const { - Uint32 NumSets = 0; - auto SetSizes = GetDescriptorSetSizes(NumSets); - + Uint32 NumSets = 0; + auto SetSizes = GetDescriptorSetSizes(NumSets); + // This call only initializes descriptor sets (ShaderResourceCacheVk::DescriptorSet) in the resource cache // Resources are initialized by source layout when shader resource binding objects are created ResourceCache.InitializeSets(CacheMemAllocator, NumSets, SetSizes.data()); @@ -435,24 +448,25 @@ void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl, } } -void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl, - bool IsCompute, - const ShaderResourceCacheVk& ResourceCache, - DescriptorSetBindInfo& BindInfo, - VkDescriptorSet VkDynamicDescrSet)const +void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl, + bool IsCompute, + const ShaderResourceCacheVk& ResourceCache, + DescriptorSetBindInfo& BindInfo, + VkDescriptorSet VkDynamicDescrSet) const { #ifdef _DEBUG BindInfo.vkSets.clear(); #endif - // Do not use vector::resize for BindInfo.vkSets and BindInfo.DynamicOffsets as this + // Do not use vector::resize for BindInfo.vkSets and BindInfo.DynamicOffsets as this // causes unnecessary work to zero-initialize new elements - VERIFY(m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC).SetIndex == m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE).SetIndex, + VERIFY(m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC).SetIndex == m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE).SetIndex, "Static and mutable variables are expected to share the same descriptor set"); Uint32 TotalDynamicDescriptors = 0; + BindInfo.SetCout = 0; - for(SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; VarType = static_cast(VarType+1)) + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; VarType = static_cast(VarType + 1)) { const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType); if (Set.SetIndex >= 0) @@ -481,7 +495,7 @@ void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkI BindInfo.DynamicOffsetCount = TotalDynamicDescriptors; if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size()) BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors); - BindInfo.BindPoint = IsCompute ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS; + BindInfo.BindPoint = IsCompute ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS; BindInfo.pResourceCache = &ResourceCache; #ifdef _DEBUG BindInfo.pDbgPipelineLayout = this; @@ -493,15 +507,15 @@ void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkI // There are no dynamic descriptors, so we can bind descriptor sets right now auto& CmdBuffer = pCtxVkImpl->GetCommandBuffer(); CmdBuffer.BindDescriptorSets(BindInfo.BindPoint, - m_LayoutMgr.GetVkPipelineLayout(), + m_LayoutMgr.GetVkPipelineLayout(), 0, // First set BindInfo.SetCout, BindInfo.vkSets.data(), // BindInfo.vkSets is never empty - 0, + 0, nullptr); } BindInfo.DynamicDescriptorsBound = false; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 1c4cd26c..3eb7851d 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -37,25 +37,26 @@ namespace Diligent { VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( - Uint32 NumRenderTargets, - const TEXTURE_FORMAT RTVFormats[], - TEXTURE_FORMAT DSVFormat, - Uint32 SampleCount, - std::array& Attachments, - std::array& AttachmentReferences, - VkSubpassDescription& SubpassDesc) + Uint32 NumRenderTargets, + const TEXTURE_FORMAT RTVFormats[], + TEXTURE_FORMAT DSVFormat, + Uint32 SampleCount, + std::array& Attachments, + std::array& AttachmentReferences, + VkSubpassDescription& SubpassDesc) { VERIFY_EXPR(NumRenderTargets <= MaxRenderTargets); // Prepare render pass create info (7.1) VkRenderPassCreateInfo RenderPassCI = {}; + RenderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; RenderPassCI.pNext = nullptr; RenderPassCI.flags = 0; // reserved for future use RenderPassCI.attachmentCount = (DSVFormat != TEX_FORMAT_UNKNOWN ? 1 : 0) + NumRenderTargets; - uint32_t AttachmentInd = 0; - VkSampleCountFlagBits SampleCountFlags = static_cast(SampleCount); + uint32_t AttachmentInd = 0; + VkSampleCountFlagBits SampleCountFlags = static_cast(SampleCount); VkAttachmentReference* pDepthAttachmentReference = nullptr; if (DSVFormat != TEX_FORMAT_UNKNOWN) { @@ -64,20 +65,20 @@ VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( DepthAttachment.flags = 0; // Allowed value VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT DepthAttachment.format = TexFormatToVkFormat(DSVFormat); DepthAttachment.samples = SampleCountFlags; - DepthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area - // will be preserved. For attachments with a depth/stencil format, - // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT. - DepthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render + DepthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area + // will be preserved. For attachments with a depth/stencil format, + // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT. + DepthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render // area are written to memory. For attachments with a depth/stencil format, - // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT. + // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT. DepthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; DepthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; DepthAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; DepthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - pDepthAttachmentReference = &AttachmentReferences[AttachmentInd]; + pDepthAttachmentReference = &AttachmentReferences[AttachmentInd]; pDepthAttachmentReference->attachment = AttachmentInd; - pDepthAttachmentReference->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + pDepthAttachmentReference->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; ++AttachmentInd; } @@ -90,18 +91,18 @@ VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( ColorAttachment.flags = 0; // Allowed value VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT ColorAttachment.format = TexFormatToVkFormat(RTVFormats[rt]); ColorAttachment.samples = SampleCountFlags; - ColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area - // will be preserved. For attachments with a depth/stencil format, - // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_READ_BIT. + ColorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area + // will be preserved. For attachments with a depth/stencil format, + // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_READ_BIT. ColorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render // area are written to memory. For attachments with a color format, - // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT. + // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT. ColorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; ColorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; ColorAttachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; ColorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd]; + auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd]; ColorAttachmentRef.attachment = AttachmentInd; ColorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } @@ -109,12 +110,12 @@ VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( RenderPassCI.pAttachments = Attachments.data(); RenderPassCI.subpassCount = 1; RenderPassCI.pSubpasses = &SubpassDesc; - RenderPassCI.dependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies. - RenderPassCI.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing - // dependencies between pairs of subpasses, or NULL if dependencyCount is zero. + RenderPassCI.dependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies. + RenderPassCI.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing + // dependencies between pairs of subpasses, or NULL if dependencyCount is zero. - SubpassDesc.flags = 0; // All bits for this type are defined by extensions + SubpassDesc.flags = 0; // All bits for this type are defined by extensions SubpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; // Currently, only graphics subpasses are supported. SubpassDesc.inputAttachmentCount = 0; SubpassDesc.pInputAttachments = nullptr; @@ -131,7 +132,7 @@ VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( static std::vector StripReflection(const std::vector& OriginalSPIRV) { std::vector StrippedSPIRV; - spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); + spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); @@ -144,30 +145,32 @@ static std::vector StripReflection(const std::vector& Origin return StrippedSPIRV; } -PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDeviceVk, - const PipelineStateDesc& PipelineDesc) : +PipelineStateVkImpl ::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const PipelineStateDesc& PipelineDesc) : TPipelineStateBase{pRefCounters, pDeviceVk, PipelineDesc}, - m_SRBMemAllocator {GetRawAllocator()} + m_SRBMemAllocator{GetRawAllocator()} { const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); // Initialize shader resource layouts auto& ShaderResLayoutAllocator = GetRawAllocator(); + std::array, MaxShadersInPipeline> ShaderResources; - std::array, MaxShadersInPipeline> ShaderSPIRVs; - m_ShaderResourceLayouts = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", ShaderResourceLayoutVk, m_NumShaders * 2); - m_StaticResCaches = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceCacheVk", ShaderResourceCacheVk, m_NumShaders); - m_StaticVarsMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", ShaderVariableManagerVk, m_NumShaders); - for (Uint32 s=0; s < m_NumShaders; ++s) + std::array, MaxShadersInPipeline> ShaderSPIRVs; + + m_ShaderResourceLayouts = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", ShaderResourceLayoutVk, m_NumShaders * 2); + m_StaticResCaches = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceCacheVk", ShaderResourceCacheVk, m_NumShaders); + m_StaticVarsMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", ShaderVariableManagerVk, m_NumShaders); + for (Uint32 s = 0; s < m_NumShaders; ++s) { new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk(LogicalDevice); - auto* pShaderVk = GetShader(s); + auto* pShaderVk = GetShader(s); ShaderResources[s] = pShaderVk->GetShaderResources(); ShaderSPIRVs[s] = pShaderVk->GetSPIRV(); - const auto ShaderType = pShaderVk->GetDesc().ShaderType; - const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType); + const auto ShaderType = pShaderVk->GetDesc().ShaderType; + const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType); m_ResourceLayoutIndex[ShaderTypeInd] = static_cast(s); auto* pStaticResLayout = new (m_ShaderResourceLayouts + m_NumShaders + s) ShaderResourceLayoutVk(LogicalDevice); @@ -186,13 +189,14 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters for (Uint32 s = 0; s < m_NumShaders; ++s) { const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; - Uint32 UnusedNumVars = 0; + + Uint32 UnusedNumVars = 0; ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars); } - Uint32 NumSets = 0; - auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); - auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); + Uint32 NumSets = 0; + auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets); + auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data()); m_SRBMemAllocator.Initialize(PipelineDesc.SRBAllocationGranularity, m_NumShaders, ShaderVariableDataSizes.data(), 1, &CacheMemorySize); } @@ -201,8 +205,8 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters std::array ShaderStages = {}; for (Uint32 s = 0; s < m_NumShaders; ++s) { - auto* pShaderVk = GetShader(s); - auto ShaderType = pShaderVk->GetDesc().ShaderType; + auto* pShaderVk = GetShader(s); + auto ShaderType = pShaderVk->GetDesc().ShaderType; auto& StageCI = ShaderStages[s]; StageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -210,6 +214,7 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters StageCI.flags = 0; // reserved for future use switch (ShaderType) { + // clang-format off case SHADER_TYPE_VERTEX: StageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; break; case SHADER_TYPE_HULL: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break; case SHADER_TYPE_DOMAIN: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break; @@ -217,16 +222,18 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters case SHADER_TYPE_PIXEL: StageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; break; case SHADER_TYPE_COMPUTE: StageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; break; default: UNEXPECTED("Unknown shader type"); + // clang-format on } VkShaderModuleCreateInfo ShaderModuleCI = {}; + ShaderModuleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; ShaderModuleCI.pNext = nullptr; ShaderModuleCI.flags = 0; - const auto& SPIRV = ShaderSPIRVs[s]; + const auto& SPIRV = ShaderSPIRVs[s]; // We have to strip reflection instructions to fix the follownig validation error: - // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string + // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string // Optimizer also performs validation and may catch problems with the byte code. auto StrippedSPIRV = StripReflection(SPIRV); if (!StrippedSPIRV.empty()) @@ -243,8 +250,8 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters m_ShaderModules[s] = LogicalDevice.CreateShaderModule(ShaderModuleCI, pShaderVk->GetDesc().Name); - StageCI.module = m_ShaderModules[s]; - StageCI.pName = pShaderVk->GetEntryPoint(); + StageCI.module = m_ShaderModules[s]; + StageCI.pName = pShaderVk->GetEntryPoint(); StageCI.pSpecializationInfo = nullptr; } @@ -253,79 +260,85 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters { auto& ComputePipeline = m_Desc.ComputePipeline; - if ( ComputePipeline.pCS == nullptr ) + if (ComputePipeline.pCS == nullptr) LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); VkComputePipelineCreateInfo PipelineCI = {}; + PipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; PipelineCI.pNext = nullptr; #ifdef _DEBUG PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; -#endif +#endif PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from + PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from PipelineCI.stage = ShaderStages[0]; PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); - + m_Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); } else { - const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); - - auto& GraphicsPipeline = m_Desc.GraphicsPipeline; + const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); + auto& GraphicsPipeline = m_Desc.GraphicsPipeline; + auto& RPCache = pDeviceVk->GetRenderPassCache(); - auto& RPCache = pDeviceVk->GetRenderPassCache(); - RenderPassCache::RenderPassCacheKey Key( + RenderPassCache::RenderPassCacheKey Key{ GraphicsPipeline.NumRenderTargets, GraphicsPipeline.SmplDesc.Count, GraphicsPipeline.RTVFormats, - GraphicsPipeline.DSVFormat); + GraphicsPipeline.DSVFormat}; m_RenderPass = RPCache.GetRenderPass(Key); VkGraphicsPipelineCreateInfo PipelineCI = {}; + PipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; PipelineCI.pNext = nullptr; #ifdef _DEBUG PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; -#endif +#endif PipelineCI.stageCount = m_NumShaders; PipelineCI.pStages = ShaderStages.data(); PipelineCI.layout = m_PipelineLayout.GetVkPipelineLayout(); - + VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; - std::array BindingDescriptions; + + std::array BindingDescriptions; std::array AttributeDescription; InputLayoutDesc_To_VkVertexInputStateCI(GraphicsPipeline.InputLayout, VertexInputStateCI, BindingDescriptions, AttributeDescription); PipelineCI.pVertexInputState = &VertexInputStateCI; VkPipelineInputAssemblyStateCreateInfo InputAssemblyCI = {}; - InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - InputAssemblyCI.pNext = nullptr; - InputAssemblyCI.flags = 0; // reserved for future use + + InputAssemblyCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + InputAssemblyCI.pNext = nullptr; + InputAssemblyCI.flags = 0; // reserved for future use InputAssemblyCI.primitiveRestartEnable = VK_FALSE; - PipelineCI.pInputAssemblyState = &InputAssemblyCI; + PipelineCI.pInputAssemblyState = &InputAssemblyCI; + VkPipelineTessellationStateCreateInfo TessStateCI = {}; - TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - TessStateCI.pNext = nullptr; - TessStateCI.flags = 0; // reserved for future use + + TessStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + TessStateCI.pNext = nullptr; + TessStateCI.flags = 0; // reserved for future use PipelineCI.pTessellationState = &TessStateCI; PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(GraphicsPipeline.PrimitiveTopology, InputAssemblyCI.topology, TessStateCI.patchControlPoints); - + VkPipelineViewportStateCreateInfo ViewPortStateCI = {}; + ViewPortStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; ViewPortStateCI.pNext = nullptr; ViewPortStateCI.flags = 0; // reserved for future use - ViewPortStateCI.viewportCount = - GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used - // by the pipeline is still specified by the viewportCount member (23.5) - ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states + ViewPortStateCI.viewportCount = + GraphicsPipeline.NumViewports; // Even though we use dynamic viewports, the number of viewports used + // by the pipeline is still specified by the viewportCount member (23.5) + ViewPortStateCI.pViewports = nullptr; // We will be using dynamic viewport & scissor states ViewPortStateCI.scissorCount = ViewPortStateCI.viewportCount; // the number of scissors must match the number of viewports (23.5) // (why the hell it is in the struct then?) VkRect2D ScissorRect = {}; @@ -343,86 +356,90 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters* pRefCounters ScissorRect.extent.height = Props.limits.maxViewportDimensions[1]; ViewPortStateCI.pScissors = &ScissorRect; } - PipelineCI.pViewportState = &ViewPortStateCI; - - VkPipelineRasterizationStateCreateInfo RasterizerStateCI = + PipelineCI.pViewportState = &ViewPortStateCI; + + VkPipelineRasterizationStateCreateInfo RasterizerStateCI = RasterizerStateDesc_To_VkRasterizationStateCI(GraphicsPipeline.RasterizerDesc); PipelineCI.pRasterizationState = &RasterizerStateCI; - + // Multisample state (24) VkPipelineMultisampleStateCreateInfo MSStateCI = {}; + MSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; MSStateCI.pNext = nullptr; MSStateCI.flags = 0; // reserved for future use - // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of + // If subpass uses color and/or depth/stencil attachments, then the rasterizationSamples member of // pMultisampleState must be the same as the sample count for those subpass attachments MSStateCI.rasterizationSamples = static_cast(GraphicsPipeline.SmplDesc.Count); - MSStateCI.sampleShadingEnable = VK_FALSE; - MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. - uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples - MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with - // the coverage information generated during rasterization (25.3) - MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on - // the alpha component of the fragment's first color output - MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one + MSStateCI.sampleShadingEnable = VK_FALSE; + MSStateCI.minSampleShading = 0; // a minimum fraction of sample shading if sampleShadingEnable is set to VK_TRUE. + uint32_t SampleMask[] = {GraphicsPipeline.SampleMask, 0}; // Vulkan spec allows up to 64 samples + MSStateCI.pSampleMask = SampleMask; // an array of static coverage information that is ANDed with + // the coverage information generated during rasterization (25.3) + MSStateCI.alphaToCoverageEnable = VK_FALSE; // whether a temporary coverage value is generated based on + // the alpha component of the fragment's first color output + MSStateCI.alphaToOneEnable = VK_FALSE; // whether the alpha component of the fragment's first color output is replaced with one PipelineCI.pMultisampleState = &MSStateCI; - VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = + VkPipelineDepthStencilStateCreateInfo DepthStencilStateCI = DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); PipelineCI.pDepthStencilState = &DepthStencilStateCI; std::vector ColorBlendAttachmentStates(m_Desc.GraphicsPipeline.NumRenderTargets); + VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; - BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; - BlendStateCI.attachmentCount = m_Desc.GraphicsPipeline.NumRenderTargets; // must equal the colorAttachmentCount for the subpass + + BlendStateCI.pAttachments = !ColorBlendAttachmentStates.empty() ? ColorBlendAttachmentStates.data() : nullptr; + BlendStateCI.attachmentCount = m_Desc.GraphicsPipeline.NumRenderTargets; // must equal the colorAttachmentCount for the subpass // in which this pipeline is used. BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); PipelineCI.pColorBlendState = &BlendStateCI; VkPipelineDynamicStateCreateInfo DynamicStateCI = {}; + DynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; DynamicStateCI.pNext = nullptr; DynamicStateCI.flags = 0; // reserved for future use - std::vector DynamicStates = - { - VK_DYNAMIC_STATE_VIEWPORT,// pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be - // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports - // used by a pipeline is still specified by the viewportCount member of - // VkPipelineViewportStateCreateInfo. + std::vector DynamicStates = + { + VK_DYNAMIC_STATE_VIEWPORT, // pViewports state in VkPipelineViewportStateCreateInfo will be ignored and must be + // set dynamically with vkCmdSetViewport before any draw commands. The number of viewports + // used by a pipeline is still specified by the viewportCount member of + // VkPipelineViewportStateCreateInfo. - VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored - // and must be set dynamically with vkCmdSetBlendConstants + VK_DYNAMIC_STATE_BLEND_CONSTANTS, // blendConstants state in VkPipelineColorBlendStateCreateInfo will be ignored + // and must be set dynamically with vkCmdSetBlendConstants - VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo - // for both front and back will be ignored and must be set dynamically - // with vkCmdSetStencilReference - }; + VK_DYNAMIC_STATE_STENCIL_REFERENCE // pecifies that the reference state in VkPipelineDepthStencilStateCreateInfo + // for both front and back will be ignored and must be set dynamically + // with vkCmdSetStencilReference + }; if (GraphicsPipeline.RasterizerDesc.ScissorEnable) { - // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set - // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles - // used by a pipeline is still specified by the scissorCount member of + // pScissors state in VkPipelineViewportStateCreateInfo will be ignored and must be set + // dynamically with vkCmdSetScissor before any draw commands. The number of scissor rectangles + // used by a pipeline is still specified by the scissorCount member of // VkPipelineViewportStateCreateInfo. DynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); } DynamicStateCI.dynamicStateCount = static_cast(DynamicStates.size()); - DynamicStateCI.pDynamicStates = DynamicStates.data(); - PipelineCI.pDynamicState = &DynamicStateCI; + DynamicStateCI.pDynamicStates = DynamicStates.data(); + PipelineCI.pDynamicState = &DynamicStateCI; + - - PipelineCI.renderPass = m_RenderPass; - PipelineCI.subpass = 0; + PipelineCI.renderPass = m_RenderPass; + PipelineCI.subpass = 0; PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from - PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from + PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from m_Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); } - m_HasStaticResources = false; + m_HasStaticResources = false; m_HasNonStaticResources = false; - for (Uint32 s=0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < m_NumShaders; ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0) @@ -450,12 +467,12 @@ PipelineStateVkImpl::~PipelineStateVkImpl() } auto& RawAllocator = GetRawAllocator(); - for (Uint32 s=0; s < m_NumShaders*2; ++s) + for (Uint32 s = 0; s < m_NumShaders * 2; ++s) { m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk(); } - for (Uint32 s=0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < m_NumShaders; ++s) { m_StaticResCaches[s].~ShaderResourceCacheVk(); m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator()); @@ -466,19 +483,19 @@ PipelineStateVkImpl::~PipelineStateVkImpl() RawAllocator.Free(m_StaticVarsMgrs); } -IMPLEMENT_QUERY_INTERFACE( PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase ) +IMPLEMENT_QUERY_INTERFACE(PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase) -void PipelineStateVkImpl::CreateShaderResourceBinding(IShaderResourceBinding **ppShaderResourceBinding, bool InitStaticResources) +void PipelineStateVkImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) { - auto& SRBAllocator = m_pDevice->GetSRBAllocator(); - auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false); + auto& SRBAllocator = m_pDevice->GetSRBAllocator(); + auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false); if (InitStaticResources) pResBindingVk->InitializeStaticResources(nullptr); pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast(ppShaderResourceBinding)); } -bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState *pPSO)const +bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const { VERIFY_EXPR(pPSO != nullptr); @@ -527,11 +544,11 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState *pPSO)const } -void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBinding* pShaderResourceBinding, +void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBinding* pShaderResourceBinding, DeviceContextVkImpl* pCtxVkImpl, bool CommitResources, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, - PipelineLayout::DescriptorSetBindInfo* pDescrSetBindInfo)const + PipelineLayout::DescriptorSetBindInfo* pDescrSetBindInfo) const { VERIFY(CommitResources || StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION, "Resources should be transitioned or committed or both"); @@ -548,7 +565,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind #endif auto* pResBindingVkImpl = ValidatedCast(pShaderResourceBinding); - + #ifdef DEVELOPMENT { auto* pRefPSO = pResBindingVkImpl->GetPipelineState(); @@ -561,7 +578,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind if (m_HasStaticResources && !pResBindingVkImpl->StaticResourcesInitialized()) { - LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object being committed for PSO '", m_Desc.Name,"'. Please call IShaderResourceBinding::InitializeStaticResources()."); + LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object being committed for PSO '", m_Desc.Name, "'. Please call IShaderResourceBinding::InitializeStaticResources()."); } #endif @@ -590,8 +607,8 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind if (CommitResources) { - VkDescriptorSet DynamicDescrSet = VK_NULL_HANDLE; - auto DynamicDescriptorSetVkLayout = m_PipelineLayout.GetDynamicDescriptorSetVkLayout(); + VkDescriptorSet DynamicDescrSet = VK_NULL_HANDLE; + auto DynamicDescriptorSetVkLayout = m_PipelineLayout.GetDynamicDescriptorSetVkLayout(); if (DynamicDescriptorSetVkLayout != VK_NULL_HANDLE) { const char* DynamicDescrSetName = "Dynamic Descriptor Set"; @@ -603,7 +620,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind // Allocate vulkan descriptor set for dynamic resources DynamicDescrSet = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout, DynamicDescrSetName); // Commit all dynamic resource descriptors - for (Uint32 s=0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < m_NumShaders; ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) != 0) @@ -613,14 +630,14 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind // Prepare descriptor sets, and also bind them if there are no dynamic descriptors VERIFY_EXPR(pDescrSetBindInfo != nullptr); m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline, ResourceCache, *pDescrSetBindInfo, DynamicDescrSet); - // Dynamic descriptor sets are not released individually. Instead, all dynamic descriptor pools + // Dynamic descriptor sets are not released individually. Instead, all dynamic descriptor pools // are released at the end of the frame by DeviceContextVkImpl::FinishFrame(). } } void PipelineStateVkImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) { - for (Uint32 s=0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < m_NumShaders; ++s) { auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); if ((ShaderType & ShaderFlags) != 0) @@ -662,19 +679,20 @@ IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByIndex(SHADER_TY } -void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache)const +void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const { for (Uint32 s = 0; s < m_NumShaders; ++s) { const auto& StaticResLayout = GetStaticShaderResLayout(s); - const auto& StaticResCache = GetStaticResCache(s); + const auto& StaticResCache = GetStaticResCache(s); #ifdef DEVELOPMENT if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) { const auto* pShaderVk = GetShader(s); - LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", GetDesc().Name, "' will not be successfully initialized " - "because not all static resource bindings in shader '", pShaderVk->GetDesc().Name, "' are valid. " - "Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " + LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", GetDesc().Name, + "' will not be successfully initialized because not all static resource bindings in shader '", + pShaderVk->GetDesc().Name, + "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); } #endif @@ -686,4 +704,4 @@ void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& Re #endif } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index c2086c95..665fa5d8 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -37,15 +37,16 @@ namespace Diligent { -RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters* pRefCounters, - IMemoryAllocator& RawMemAllocator, - IEngineFactory* pEngineFactory, - const EngineVkCreateInfo& EngineCI, - size_t CommandQueueCount, - ICommandQueueVk** CmdQueues, - std::shared_ptr Instance, - std::unique_ptr PhysicalDevice, - std::shared_ptr LogicalDevice) : +RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* pRefCounters, + IMemoryAllocator& RawMemAllocator, + IEngineFactory* pEngineFactory, + const EngineVkCreateInfo& EngineCI, + size_t CommandQueueCount, + ICommandQueueVk** CmdQueues, + std::shared_ptr Instance, + std::unique_ptr PhysicalDevice, + std::shared_ptr LogicalDevice) : + // clang-format off TRenderDeviceBase { pRefCounters, @@ -138,13 +139,14 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters* EngineCI.DynamicHeapSize, ~Uint64{0} } +// clang-format on { - m_DeviceCaps.DevType = DeviceType::Vulkan; - m_DeviceCaps.MajorVersion = 1; - m_DeviceCaps.MinorVersion = 0; - m_DeviceCaps.bSeparableProgramSupported = True; + m_DeviceCaps.DevType = DeviceType::Vulkan; + m_DeviceCaps.MajorVersion = 1; + m_DeviceCaps.MinorVersion = 0; + m_DeviceCaps.bSeparableProgramSupported = True; m_DeviceCaps.bMultithreadedResourceCreationSupported = True; - for(int fmt = 1; fmt < m_TextureFormatsInfo.size(); ++fmt) + for (int fmt = 1; fmt < m_TextureFormatsInfo.size(); ++fmt) m_TextureFormatsInfo[fmt].Supported = true; // We will test every format on a specific hardware device m_DeviceCaps.bGeometryShadersSupported = EngineCI.EnabledFeatures.geometryShader; @@ -154,13 +156,13 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters* RenderDeviceVkImpl::~RenderDeviceVkImpl() { - // Explicitly destroy dynamic heap. This will move resources owned by + // Explicitly destroy dynamic heap. This will move resources owned by // the heap into release queues m_DynamicMemoryManager.Destroy(); // Wait for the GPU to complete all its operations IdleGPU(); - + ReleaseStaleResources(true); DEV_CHECK_ERR(m_DescriptorSetAllocator.GetAllocatedDescriptorSetCounter() == 0, "All allocated descriptor sets must have been released now."); @@ -183,29 +185,35 @@ RenderDeviceVkImpl::~RenderDeviceVkImpl() } -void RenderDeviceVkImpl::AllocateTransientCmdPool(VulkanUtilities::CommandPoolWrapper& CmdPool, VkCommandBuffer& vkCmdBuff, const Char *DebugPoolName) +void RenderDeviceVkImpl::AllocateTransientCmdPool(VulkanUtilities::CommandPoolWrapper& CmdPool, VkCommandBuffer& vkCmdBuff, const Char* DebugPoolName) { CmdPool = m_TransientCmdPoolMgr.AllocateCommandPool(DebugPoolName); // Allocate command buffer from the cmd pool VkCommandBufferAllocateInfo BuffAllocInfo = {}; + BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; BuffAllocInfo.pNext = nullptr; BuffAllocInfo.commandPool = CmdPool; BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; BuffAllocInfo.commandBufferCount = 1; + vkCmdBuff = m_LogicalVkDevice->AllocateVkCommandBuffer(BuffAllocInfo); DEV_CHECK_ERR(vkCmdBuff != VK_NULL_HANDLE, "Failed to allocate Vulkan command buffer"); - + + VkCommandBufferBeginInfo CmdBuffBeginInfo = {}; + CmdBuffBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; CmdBuffBeginInfo.pNext = nullptr; - CmdBuffBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; // Each recording of the command buffer will only be - // submitted once, and the command buffer will be reset + CmdBuffBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; // Each recording of the command buffer will only be + // submitted once, and the command buffer will be reset // and recorded again between each submission. - CmdBuffBeginInfo.pInheritanceInfo = nullptr; // Ignored for a primary command buffer + CmdBuffBeginInfo.pInheritanceInfo = nullptr; // Ignored for a primary command buffer + auto err = vkBeginCommandBuffer(vkCmdBuff, &CmdBuffBeginInfo); - DEV_CHECK_ERR(err == VK_SUCCESS, "vkBeginCommandBuffer() failed"); (void)err; + DEV_CHECK_ERR(err == VK_SUCCESS, "vkBeginCommandBuffer() failed"); + (void)err; } @@ -214,17 +222,19 @@ void RenderDeviceVkImpl::ExecuteAndDisposeTransientCmdBuff(Uint32 QueueIndex, Vk VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); auto err = vkEndCommandBuffer(vkCmdBuff); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to end command buffer"); (void)err; + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to end command buffer"); + (void)err; VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; SubmitInfo.commandBufferCount = 1; SubmitInfo.pCommandBuffers = &vkCmdBuff; // We MUST NOT discard stale objects when executing transient command buffer, // otherwise a resource can be destroyed while still being used by the GPU: - // - // + // + // // Next Cmd Buff| Next Fence | Immediate Context | This thread | // | | | | // N | F | | | @@ -247,24 +257,24 @@ void RenderDeviceVkImpl::ExecuteAndDisposeTransientCmdBuff(Uint32 QueueIndex, Vk // Since transient command buffers do not count as real command buffers, submit them directly to the queue // to avoid interference with the command buffer counter Uint64 FenceValue = 0; - LockCmdQueueAndRun(QueueIndex, - [&](ICommandQueueVk* pCmdQueueVk) - { - FenceValue = pCmdQueueVk->Submit(SubmitInfo); - } + LockCmdQueueAndRun(QueueIndex, + [&](ICommandQueueVk* pCmdQueueVk) // + { + FenceValue = pCmdQueueVk->Submit(SubmitInfo); + } // ); m_TransientCmdPoolMgr.SafeReleaseCommandPool(std::move(CmdPool), QueueIndex, FenceValue); } -void RenderDeviceVkImpl::SubmitCommandBuffer(Uint32 QueueIndex, - const VkSubmitInfo& SubmitInfo, - Uint64& SubmittedCmdBuffNumber, // Number of the submitted command buffer - Uint64& SubmittedFenceValue, // Fence value associated with the submitted command buffer - std::vector > >* pFences // List of fences to signal - ) +void RenderDeviceVkImpl::SubmitCommandBuffer(Uint32 QueueIndex, + const VkSubmitInfo& SubmitInfo, + Uint64& SubmittedCmdBuffNumber, // Number of the submitted command buffer + Uint64& SubmittedFenceValue, // Fence value associated with the submitted command buffer + std::vector>>* pFences // List of fences to signal +) { - // Submit the command list to the queue - auto CmbBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, SubmitInfo, true); + // Submit the command list to the queue + auto CmbBuffInfo = TRenderDeviceBase::SubmitCommandBuffer(QueueIndex, SubmitInfo, true); SubmittedFenceValue = CmbBuffInfo.FenceValue; SubmittedCmdBuffNumber = CmbBuffInfo.CmdBufferNumber; if (pFences != nullptr) @@ -272,20 +282,20 @@ void RenderDeviceVkImpl::SubmitCommandBuffer(Uint32 QueueIndex, for (auto& val_fence : *pFences) { auto* pFenceVkImpl = val_fence.second.RawPtr(); - auto vkFence = pFenceVkImpl->GetVkFence(); + auto vkFence = pFenceVkImpl->GetVkFence(); m_CommandQueues[QueueIndex].CmdQueue->SignalFence(vkFence); pFenceVkImpl->AddPendingFence(std::move(vkFence), val_fence.first); } } } -Uint64 RenderDeviceVkImpl::ExecuteCommandBuffer(Uint32 QueueIndex, const VkSubmitInfo& SubmitInfo, DeviceContextVkImpl* pImmediateCtx, std::vector > >* pSignalFences) +Uint64 RenderDeviceVkImpl::ExecuteCommandBuffer(Uint32 QueueIndex, const VkSubmitInfo& SubmitInfo, DeviceContextVkImpl* pImmediateCtx, std::vector>>* pSignalFences) { // pImmediateCtx parameter is only used to make sure the command buffer is submitted from the immediate context // Stale objects MUST only be discarded when submitting cmd list from the immediate context VERIFY(!pImmediateCtx->IsDeferred(), "Command buffers must be submitted from immediate context only"); - Uint64 SubmittedFenceValue = 0; + Uint64 SubmittedFenceValue = 0; Uint64 SubmittedCmdBuffNumber = 0; SubmitCommandBuffer(QueueIndex, SubmitInfo, SubmittedCmdBuffNumber, SubmittedFenceValue, pSignalFences); @@ -296,8 +306,8 @@ Uint64 RenderDeviceVkImpl::ExecuteCommandBuffer(Uint32 QueueIndex, const VkSubmi } -void RenderDeviceVkImpl::IdleGPU() -{ +void RenderDeviceVkImpl::IdleGPU() +{ IdleAllCommandQueues(true); m_LogicalVkDevice->WaitIdle(); ReleaseStaleResources(); @@ -305,7 +315,7 @@ void RenderDeviceVkImpl::IdleGPU() void RenderDeviceVkImpl::FlushStaleResources(Uint32 CmdQueueIndex) { - // Submit empty command buffer to the queue. This will effectively signal the fence and + // Submit empty command buffer to the queue. This will effectively signal the fence and // discard all resources VkSubmitInfo DummySumbitInfo = {}; TRenderDeviceBase::SubmitCommandBuffer(0, DummySumbitInfo, true); @@ -318,67 +328,71 @@ void RenderDeviceVkImpl::ReleaseStaleResources(bool ForceRelease) } -void RenderDeviceVkImpl::TestTextureFormat( TEXTURE_FORMAT TexFormat ) +void RenderDeviceVkImpl::TestTextureFormat(TEXTURE_FORMAT TexFormat) { - auto &TexFormatInfo = m_TextureFormatsInfo[TexFormat]; - VERIFY( TexFormatInfo.Supported, "Texture format is not supported" ); + auto& TexFormatInfo = m_TextureFormatsInfo[TexFormat]; + VERIFY(TexFormatInfo.Supported, "Texture format is not supported"); auto vkPhysicalDevice = m_PhysicalDevice->GetVkDeviceHandle(); auto SRVFormat = GetDefaultTextureViewFormat(TexFormat, TEXTURE_VIEW_SHADER_RESOURCE, BIND_SHADER_RESOURCE); auto RTVFormat = GetDefaultTextureViewFormat(TexFormat, TEXTURE_VIEW_RENDER_TARGET, BIND_RENDER_TARGET); auto DSVFormat = GetDefaultTextureViewFormat(TexFormat, TEXTURE_VIEW_DEPTH_STENCIL, BIND_DEPTH_STENCIL); - - if(SRVFormat != TEX_FORMAT_UNKNOWN) + + if (SRVFormat != TEX_FORMAT_UNKNOWN) { - VkFormat vkSrvFormat = TexFormatToVkFormat(SRVFormat); + VkFormat vkSrvFormat = TexFormatToVkFormat(SRVFormat); VkFormatProperties vkSrvFmtProps = {}; vkGetPhysicalDeviceFormatProperties(vkPhysicalDevice, vkSrvFormat, &vkSrvFmtProps); - if(vkSrvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) + if (vkSrvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { TexFormatInfo.Filterable = true; { VkImageFormatProperties ImgFmtProps = {}; - auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_1D, VK_IMAGE_TILING_OPTIMAL, + + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_1D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, 0, &ImgFmtProps); TexFormatInfo.Tex1DFmt = err == VK_SUCCESS; } { VkImageFormatProperties ImgFmtProps = {}; - auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, 0, &ImgFmtProps); TexFormatInfo.Tex2DFmt = err == VK_SUCCESS; } { VkImageFormatProperties ImgFmtProps = {}; - auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_3D, VK_IMAGE_TILING_OPTIMAL, + + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_3D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, 0, &ImgFmtProps); TexFormatInfo.Tex3DFmt = err == VK_SUCCESS; } { VkImageFormatProperties ImgFmtProps = {}; - auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkSrvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, &ImgFmtProps); TexFormatInfo.TexCubeFmt = err == VK_SUCCESS; } - } } if (RTVFormat != TEX_FORMAT_UNKNOWN) { - VkFormat vkRtvFormat = TexFormatToVkFormat(RTVFormat); + VkFormat vkRtvFormat = TexFormatToVkFormat(RTVFormat); VkFormatProperties vkRtvFmtProps = {}; vkGetPhysicalDeviceFormatProperties(vkPhysicalDevice, vkRtvFormat, &vkRtvFmtProps); if (vkRtvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { VkImageFormatProperties ImgFmtProps = {}; - auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkRtvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkRtvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &ImgFmtProps); TexFormatInfo.ColorRenderable = err == VK_SUCCESS; if (TexFormatInfo.ColorRenderable) @@ -390,15 +404,15 @@ void RenderDeviceVkImpl::TestTextureFormat( TEXTURE_FORMAT TexFormat ) if (DSVFormat != TEX_FORMAT_UNKNOWN) { - VkFormat vkDsvFormat = TexFormatToVkFormat(DSVFormat); + VkFormat vkDsvFormat = TexFormatToVkFormat(DSVFormat); VkFormatProperties vkDsvFmtProps = {}; vkGetPhysicalDeviceFormatProperties(vkPhysicalDevice, vkDsvFormat, &vkDsvFmtProps); if (vkDsvFmtProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { VkImageFormatProperties ImgFmtProps = {}; - auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkDsvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + auto err = vkGetPhysicalDeviceImageFormatProperties(vkPhysicalDevice, vkDsvFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &ImgFmtProps); - TexFormatInfo.DepthRenderable = err == VK_SUCCESS; + TexFormatInfo.DepthRenderable = err == VK_SUCCESS; if (TexFormatInfo.DepthRenderable) { TexFormatInfo.SampleCounts = ImgFmtProps.sampleCounts; @@ -408,132 +422,140 @@ void RenderDeviceVkImpl::TestTextureFormat( TEXTURE_FORMAT TexFormat ) } -IMPLEMENT_QUERY_INTERFACE( RenderDeviceVkImpl, IID_RenderDeviceVk, TRenderDeviceBase ) +IMPLEMENT_QUERY_INTERFACE(RenderDeviceVkImpl, IID_RenderDeviceVk, TRenderDeviceBase) -void RenderDeviceVkImpl::CreatePipelineState(const PipelineStateDesc &PipelineDesc, IPipelineState **ppPipelineState) +void RenderDeviceVkImpl::CreatePipelineState(const PipelineStateDesc& PipelineDesc, IPipelineState** ppPipelineState) { - CreateDeviceObject("Pipeline State", PipelineDesc, ppPipelineState, - [&]() + CreateDeviceObject( + "Pipeline State", PipelineDesc, ppPipelineState, + [&]() // { - PipelineStateVkImpl *pPipelineStateVk( NEW_RC_OBJ(m_PSOAllocator, "PipelineStateVkImpl instance", PipelineStateVkImpl)(this, PipelineDesc ) ); - pPipelineStateVk->QueryInterface( IID_PipelineState, reinterpret_cast(ppPipelineState) ); - OnCreateDeviceObject( pPipelineStateVk ); - } + PipelineStateVkImpl* pPipelineStateVk(NEW_RC_OBJ(m_PSOAllocator, "PipelineStateVkImpl instance", PipelineStateVkImpl)(this, PipelineDesc)); + pPipelineStateVk->QueryInterface(IID_PipelineState, reinterpret_cast(ppPipelineState)); + OnCreateDeviceObject(pPipelineStateVk); + } // ); } -void RenderDeviceVkImpl :: CreateBufferFromVulkanResource(VkBuffer vkBuffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) +void RenderDeviceVkImpl::CreateBufferFromVulkanResource(VkBuffer vkBuffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) { - CreateDeviceObject("buffer", BuffDesc, ppBuffer, - [&]() + CreateDeviceObject( + "buffer", BuffDesc, ppBuffer, + [&]() // { - BufferVkImpl* pBufferVk( NEW_RC_OBJ(m_BufObjAllocator, "BufferVkImpl instance", BufferVkImpl)(m_BuffViewObjAllocator, this, BuffDesc, InitialState, vkBuffer ) ); - pBufferVk->QueryInterface( IID_Buffer, reinterpret_cast(ppBuffer) ); + BufferVkImpl* pBufferVk(NEW_RC_OBJ(m_BufObjAllocator, "BufferVkImpl instance", BufferVkImpl)(m_BuffViewObjAllocator, this, BuffDesc, InitialState, vkBuffer)); + pBufferVk->QueryInterface(IID_Buffer, reinterpret_cast(ppBuffer)); pBufferVk->CreateDefaultViews(); - OnCreateDeviceObject( pBufferVk ); - } + OnCreateDeviceObject(pBufferVk); + } // ); } -void RenderDeviceVkImpl :: CreateBuffer(const BufferDesc& BuffDesc, const BufferData* pBuffData, IBuffer **ppBuffer) +void RenderDeviceVkImpl::CreateBuffer(const BufferDesc& BuffDesc, const BufferData* pBuffData, IBuffer** ppBuffer) { - CreateDeviceObject("buffer", BuffDesc, ppBuffer, - [&]() + CreateDeviceObject( + "buffer", BuffDesc, ppBuffer, + [&]() // { - BufferVkImpl* pBufferVk( NEW_RC_OBJ(m_BufObjAllocator, "BufferVkImpl instance", BufferVkImpl)(m_BuffViewObjAllocator, this, BuffDesc, pBuffData ) ); - pBufferVk->QueryInterface( IID_Buffer, reinterpret_cast(ppBuffer) ); + BufferVkImpl* pBufferVk(NEW_RC_OBJ(m_BufObjAllocator, "BufferVkImpl instance", BufferVkImpl)(m_BuffViewObjAllocator, this, BuffDesc, pBuffData)); + pBufferVk->QueryInterface(IID_Buffer, reinterpret_cast(ppBuffer)); pBufferVk->CreateDefaultViews(); - OnCreateDeviceObject( pBufferVk ); - } + OnCreateDeviceObject(pBufferVk); + } // ); } -void RenderDeviceVkImpl :: CreateShader(const ShaderCreateInfo& ShaderCI, IShader **ppShader) +void RenderDeviceVkImpl::CreateShader(const ShaderCreateInfo& ShaderCI, IShader** ppShader) { - CreateDeviceObject( "shader", ShaderCI.Desc, ppShader, - [&]() + CreateDeviceObject( + "shader", ShaderCI.Desc, ppShader, + [&]() // { - ShaderVkImpl *pShaderVk( NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderVkImpl instance", ShaderVkImpl)(this, ShaderCI) ); - pShaderVk->QueryInterface( IID_Shader, reinterpret_cast(ppShader) ); + ShaderVkImpl* pShaderVk(NEW_RC_OBJ(m_ShaderObjAllocator, "ShaderVkImpl instance", ShaderVkImpl)(this, ShaderCI)); + pShaderVk->QueryInterface(IID_Shader, reinterpret_cast(ppShader)); - OnCreateDeviceObject( pShaderVk ); - } + OnCreateDeviceObject(pShaderVk); + } // ); } void RenderDeviceVkImpl::CreateTextureFromVulkanImage(VkImage vkImage, const TextureDesc& TexDesc, RESOURCE_STATE InitialState, ITexture** ppTexture) { - CreateDeviceObject( "texture", TexDesc, ppTexture, - [&]() + CreateDeviceObject( + "texture", TexDesc, ppTexture, + [&]() // { - TextureVkImpl* pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, InitialState, vkImage ); + TextureVkImpl* pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, InitialState, vkImage); - pTextureVk->QueryInterface( IID_Texture, reinterpret_cast(ppTexture) ); + pTextureVk->QueryInterface(IID_Texture, reinterpret_cast(ppTexture)); pTextureVk->CreateDefaultViews(); - OnCreateDeviceObject( pTextureVk ); - } + OnCreateDeviceObject(pTextureVk); + } // ); } -void RenderDeviceVkImpl::CreateTexture(const TextureDesc& TexDesc, VkImage vkImgHandle, RESOURCE_STATE InitialState, class TextureVkImpl **ppTexture) +void RenderDeviceVkImpl::CreateTexture(const TextureDesc& TexDesc, VkImage vkImgHandle, RESOURCE_STATE InitialState, class TextureVkImpl** ppTexture) { - CreateDeviceObject( "texture", TexDesc, ppTexture, - [&]() + CreateDeviceObject( + "texture", TexDesc, ppTexture, + [&]() // { TextureVkImpl* pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, InitialState, std::move(vkImgHandle)); - pTextureVk->QueryInterface( IID_TextureVk, reinterpret_cast(ppTexture) ); - } + pTextureVk->QueryInterface(IID_TextureVk, reinterpret_cast(ppTexture)); + } // ); } -void RenderDeviceVkImpl :: CreateTexture(const TextureDesc& TexDesc, const TextureData* pData, ITexture **ppTexture) +void RenderDeviceVkImpl::CreateTexture(const TextureDesc& TexDesc, const TextureData* pData, ITexture** ppTexture) { - CreateDeviceObject( "texture", TexDesc, ppTexture, - [&]() + CreateDeviceObject( + "texture", TexDesc, ppTexture, + [&]() // { - TextureVkImpl* pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, pData ); + TextureVkImpl* pTextureVk = NEW_RC_OBJ(m_TexObjAllocator, "TextureVkImpl instance", TextureVkImpl)(m_TexViewObjAllocator, this, TexDesc, pData); - pTextureVk->QueryInterface( IID_Texture, reinterpret_cast(ppTexture) ); + pTextureVk->QueryInterface(IID_Texture, reinterpret_cast(ppTexture)); pTextureVk->CreateDefaultViews(); - OnCreateDeviceObject( pTextureVk ); - } + OnCreateDeviceObject(pTextureVk); + } // ); } -void RenderDeviceVkImpl :: CreateSampler(const SamplerDesc& SamplerDesc, ISampler **ppSampler) +void RenderDeviceVkImpl::CreateSampler(const SamplerDesc& SamplerDesc, ISampler** ppSampler) { - CreateDeviceObject( "sampler", SamplerDesc, ppSampler, - [&]() + CreateDeviceObject( + "sampler", SamplerDesc, ppSampler, + [&]() // { - m_SamplersRegistry.Find( SamplerDesc, reinterpret_cast(ppSampler) ); - if( *ppSampler == nullptr ) + m_SamplersRegistry.Find(SamplerDesc, reinterpret_cast(ppSampler)); + if (*ppSampler == nullptr) { - SamplerVkImpl* pSamplerVk( NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerVkImpl instance", SamplerVkImpl)(this, SamplerDesc ) ); - pSamplerVk->QueryInterface( IID_Sampler, reinterpret_cast(ppSampler) ); - OnCreateDeviceObject( pSamplerVk ); - m_SamplersRegistry.Add( SamplerDesc, *ppSampler ); + SamplerVkImpl* pSamplerVk(NEW_RC_OBJ(m_SamplerObjAllocator, "SamplerVkImpl instance", SamplerVkImpl)(this, SamplerDesc)); + pSamplerVk->QueryInterface(IID_Sampler, reinterpret_cast(ppSampler)); + OnCreateDeviceObject(pSamplerVk); + m_SamplersRegistry.Add(SamplerDesc, *ppSampler); } - } + } // ); } void RenderDeviceVkImpl::CreateFence(const FenceDesc& Desc, IFence** ppFence) { - CreateDeviceObject( "Fence", Desc, ppFence, - [&]() + CreateDeviceObject( + "Fence", Desc, ppFence, + [&]() // { - FenceVkImpl* pFenceVk( NEW_RC_OBJ(m_FenceAllocator, "FenceVkImpl instance", FenceVkImpl) - (this, Desc) ); - pFenceVk->QueryInterface( IID_Fence, reinterpret_cast(ppFence) ); - OnCreateDeviceObject( pFenceVk ); - } + FenceVkImpl* pFenceVk(NEW_RC_OBJ(m_FenceAllocator, "FenceVkImpl instance", FenceVkImpl)(this, Desc)); + pFenceVk->QueryInterface(IID_Fence, reinterpret_cast(ppFence)); + OnCreateDeviceObject(pFenceVk); + } // ); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp b/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp index 7bc212c0..fbe574dc 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp @@ -33,7 +33,7 @@ namespace Diligent RenderPassCache::~RenderPassCache() { auto& FBCache = m_DeviceVkImpl.GetFramebufferCache(); - for(auto it = m_Cache.begin(); it != m_Cache.end(); ++it) + for (auto it = m_Cache.begin(); it != m_Cache.end(); ++it) { FBCache.OnDestroyRenderPass(it->second); } @@ -42,19 +42,22 @@ RenderPassCache::~RenderPassCache() VkRenderPass RenderPassCache::GetRenderPass(const RenderPassCacheKey& Key) { std::lock_guard Lock{m_Mutex}; - auto it = m_Cache.find(Key); - if(it == m_Cache.end()) + auto it = m_Cache.find(Key); + if (it == m_Cache.end()) { // Do not zero-intitialize arrays - std::array Attachments; - std::array AttachmentReferences; - VkSubpassDescription Subpass; - auto RenderPassCI = PipelineStateVkImpl::GetRenderPassCreateInfo(Key.NumRenderTargets, Key.RTVFormats, Key.DSVFormat, - Key.SampleCount, Attachments, AttachmentReferences, Subpass); + std::array Attachments; + std::array AttachmentReferences; + + VkSubpassDescription Subpass; + + auto RenderPassCI = + PipelineStateVkImpl::GetRenderPassCreateInfo(Key.NumRenderTargets, Key.RTVFormats, Key.DSVFormat, + Key.SampleCount, Attachments, AttachmentReferences, Subpass); std::stringstream PassNameSS; - PassNameSS << "Render pass: rt count: " << Key.NumRenderTargets << "; sample count: "<< Key.SampleCount + PassNameSS << "Render pass: rt count: " << Key.NumRenderTargets << "; sample count: " << Key.SampleCount << "; DSV Format: " << GetTextureFormatAttribs(Key.DSVFormat).Name << "; RTV Formats: "; - for(Uint32 rt = 0; rt < Key.NumRenderTargets; ++rt) + for (Uint32 rt = 0; rt < Key.NumRenderTargets; ++rt) PassNameSS << (rt > 0 ? ", " : "") << GetTextureFormatAttribs(Key.RTVFormats[rt]).Name; auto RenderPass = m_DeviceVkImpl.GetLogicalDevice().CreateRenderPass(RenderPassCI, PassNameSS.str().c_str()); VERIFY_EXPR(RenderPass != VK_NULL_HANDLE); @@ -64,4 +67,4 @@ VkRenderPass RenderPassCache::GetRenderPass(const RenderPassCacheKey& Key) return it->second; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp index 534f01ba..97896641 100644 --- a/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SamplerVkImpl.cpp @@ -30,30 +30,34 @@ namespace Diligent { -SamplerVkImpl::SamplerVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, const SamplerDesc& SamplerDesc) : +SamplerVkImpl::SamplerVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, const SamplerDesc& SamplerDesc) : + // clang-format off TSamplerBase { pRefCounters, pRenderDeviceVk, SamplerDesc } +// clang-format on { - const auto &LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); + const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); + VkSamplerCreateInfo SamplerCI = {}; - SamplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - SamplerCI.pNext = nullptr; - SamplerCI.flags = 0; // reserved for future use - SamplerCI.magFilter = FilterTypeToVkFilter(m_Desc.MagFilter); - SamplerCI.minFilter = FilterTypeToVkFilter(m_Desc.MinFilter); - SamplerCI.mipmapMode = FilterTypeToVkMipmapMode(m_Desc.MipFilter); - SamplerCI.addressModeU = AddressModeToVkAddressMode(m_Desc.AddressU); - SamplerCI.addressModeV = AddressModeToVkAddressMode(m_Desc.AddressV); - SamplerCI.addressModeW = AddressModeToVkAddressMode(m_Desc.AddressW); - SamplerCI.mipLodBias = m_Desc.MipLODBias; + + SamplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + SamplerCI.pNext = nullptr; + SamplerCI.flags = 0; // reserved for future use + SamplerCI.magFilter = FilterTypeToVkFilter(m_Desc.MagFilter); + SamplerCI.minFilter = FilterTypeToVkFilter(m_Desc.MinFilter); + SamplerCI.mipmapMode = FilterTypeToVkMipmapMode(m_Desc.MipFilter); + SamplerCI.addressModeU = AddressModeToVkAddressMode(m_Desc.AddressU); + SamplerCI.addressModeV = AddressModeToVkAddressMode(m_Desc.AddressV); + SamplerCI.addressModeW = AddressModeToVkAddressMode(m_Desc.AddressW); + SamplerCI.mipLodBias = m_Desc.MipLODBias; SamplerCI.anisotropyEnable = IsAnisotropicFilter(m_Desc.MinFilter); #ifdef DEVELOPMENT - if( !( (SamplerCI.anisotropyEnable && IsAnisotropicFilter(m_Desc.MagFilter)) || - (!SamplerCI.anisotropyEnable && !IsAnisotropicFilter(m_Desc.MagFilter)) ) ) + if (!((SamplerCI.anisotropyEnable && IsAnisotropicFilter(m_Desc.MagFilter)) || + (!SamplerCI.anisotropyEnable && !IsAnisotropicFilter(m_Desc.MagFilter)))) { LOG_ERROR("Min and mag fiters must both be either anisotropic filters or non-anisotropic ones"); } @@ -62,17 +66,17 @@ SamplerVkImpl::SamplerVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImp SamplerCI.maxAnisotropy = static_cast(m_Desc.MaxAnisotropy); SamplerCI.compareEnable = IsComparisonFilter(m_Desc.MinFilter); #ifdef DEVELOPMENT - if( !( (SamplerCI.compareEnable && IsComparisonFilter(m_Desc.MagFilter)) || - (!SamplerCI.compareEnable && !IsComparisonFilter(m_Desc.MagFilter)) ) ) + if (!((SamplerCI.compareEnable && IsComparisonFilter(m_Desc.MagFilter)) || + (!SamplerCI.compareEnable && !IsComparisonFilter(m_Desc.MagFilter)))) { LOG_ERROR("Min and mag fiters must both be either comparison filters or non-comparison ones"); } #endif - SamplerCI.compareOp = ComparisonFuncToVkCompareOp(m_Desc.ComparisonFunc); - SamplerCI.minLod = m_Desc.MinLOD; - SamplerCI.maxLod = m_Desc.MaxLOD; - SamplerCI.borderColor = BorderColorToVkBorderColor(m_Desc.BorderColor); + SamplerCI.compareOp = ComparisonFuncToVkCompareOp(m_Desc.ComparisonFunc); + SamplerCI.minLod = m_Desc.MinLOD; + SamplerCI.maxLod = m_Desc.MaxLOD; + SamplerCI.borderColor = BorderColorToVkBorderColor(m_Desc.BorderColor); SamplerCI.unnormalizedCoordinates = VK_FALSE; m_VkSampler = LogicalDevice.CreateSampler(SamplerCI); @@ -83,6 +87,6 @@ SamplerVkImpl::~SamplerVkImpl() m_pDevice->SafeReleaseDeviceObject(std::move(m_VkSampler), m_CommandQueueMask); } -IMPLEMENT_QUERY_INTERFACE( SamplerVkImpl, IID_SamplerVk, TSamplerBase ) +IMPLEMENT_QUERY_INTERFACE(SamplerVkImpl, IID_SamplerVk, TSamplerBase) -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp index 1d47c00b..e6f1fff2 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp @@ -30,7 +30,10 @@ namespace Diligent { -ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pRefCounters, PipelineStateVkImpl* pPSO, bool IsPSOInternal) : +ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pRefCounters, + PipelineStateVkImpl* pPSO, + bool IsPSOInternal) : + // clang-format off TBase { pRefCounters, @@ -38,23 +41,25 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pRe IsPSOInternal }, m_ShaderResourceCache{ShaderResourceCacheVk::DbgCacheContentType::SRBResources} +// clang-format on { auto* ppShaders = pPSO->GetShaders(); - m_NumShaders = static_cast(pPSO->GetNumShaders()); + m_NumShaders = static_cast(pPSO->GetNumShaders()); auto* pRenderDeviceVkImpl = pPSO->GetDevice(); // This will only allocate memory and initialize descriptor sets in the resource cache // Resources will be initialized by InitializeResourceMemoryInCache() auto& ResourceCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); pPSO->GetPipelineLayout().InitResourceCache(pRenderDeviceVkImpl, m_ShaderResourceCache, ResourceCacheDataAllocator, pPSO->GetDesc().Name); - + m_pShaderVarMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", ShaderVariableManagerVk, m_NumShaders); for (Uint32 s = 0; s < m_NumShaders; ++s) { - auto* pShader = ppShaders[s]; - auto ShaderType = pShader->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypeIndex(ShaderType); + auto* pShader = ppShaders[s]; + auto ShaderType = pShader->GetDesc().ShaderType; + auto ShaderInd = GetShaderTypeIndex(ShaderType); + m_ResourceLayoutIndex[ShaderInd] = static_cast(s); auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); @@ -72,13 +77,12 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pRe #ifdef _DEBUG m_ShaderResourceCache.DbgVerifyResourceInitialization(); #endif - } ShaderResourceBindingVkImpl::~ShaderResourceBindingVkImpl() { PipelineStateVkImpl* pPSO = ValidatedCast(m_pPSO); - for(Uint32 s = 0; s < m_NumShaders; ++s) + for (Uint32 s = 0; s < m_NumShaders; ++s) { auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); m_pShaderVarMgrs[s].DestroyVariables(VarDataAllocator); @@ -88,16 +92,16 @@ ShaderResourceBindingVkImpl::~ShaderResourceBindingVkImpl() GetRawAllocator().Free(m_pShaderVarMgrs); } -IMPLEMENT_QUERY_INTERFACE( ShaderResourceBindingVkImpl, IID_ShaderResourceBindingVk, TBase ) +IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingVkImpl, IID_ShaderResourceBindingVk, TBase) -void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMapping *pResMapping, Uint32 Flags) +void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags) { - for (auto ShaderInd = 0; ShaderInd <= CSInd; ++ShaderInd ) + for (auto ShaderInd = 0; ShaderInd <= CSInd; ++ShaderInd) { if (ShaderFlags & GetShaderTypeFromIndex(ShaderInd)) { auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; - if(ResLayoutInd >= 0) + if (ResLayoutInd >= 0) { m_pShaderVarMgrs[ResLayoutInd].BindResources(pResMapping, Flags); } @@ -107,7 +111,7 @@ void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMap IShaderResourceVariable* ShaderResourceBindingVkImpl::GetVariableByName(SHADER_TYPE ShaderType, const char* Name) { - auto ShaderInd = GetShaderTypeIndex(ShaderType); + auto ShaderInd = GetShaderTypeIndex(ShaderType); auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; if (ResLayoutInd < 0) { @@ -120,7 +124,7 @@ IShaderResourceVariable* ShaderResourceBindingVkImpl::GetVariableByName(SHADER_T Uint32 ShaderResourceBindingVkImpl::GetVariableCount(SHADER_TYPE ShaderType) const { - auto ShaderInd = GetShaderTypeIndex(ShaderType); + auto ShaderInd = GetShaderTypeIndex(ShaderType); auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; if (ResLayoutInd < 0) { @@ -133,7 +137,7 @@ Uint32 ShaderResourceBindingVkImpl::GetVariableCount(SHADER_TYPE ShaderType) con IShaderResourceVariable* ShaderResourceBindingVkImpl::GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) { - auto ShaderInd = GetShaderTypeIndex(ShaderType); + auto ShaderInd = GetShaderTypeIndex(ShaderType); auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; if (ResLayoutInd < 0) { @@ -158,9 +162,9 @@ void ShaderResourceBindingVkImpl::InitializeStaticResources(const IPipelineState } else { - DEV_CHECK_ERR(pPipelineState->IsCompatibleWith(GetPipelineState()), "The pipeline state '", pPipelineState->GetDesc().Name, "' " - "is not compatible with the pipeline state '", m_pPSO->GetDesc().Name, "' this SRB was created from and cannot be " - "used to initialize static resources."); + DEV_CHECK_ERR(pPipelineState->IsCompatibleWith(GetPipelineState()), "The pipeline state '", pPipelineState->GetDesc().Name, + "' is not compatible with the pipeline state '", m_pPSO->GetDesc().Name, + "' this SRB was created from and cannot be used to initialize static resources."); } auto* pPSOVK = ValidatedCast(pPipelineState); @@ -168,4 +172,4 @@ void ShaderResourceBindingVkImpl::InitializeStaticResources(const IPipelineState m_bStaticResourcesInitialized = true; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index c899d706..8caafad6 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -37,7 +37,7 @@ namespace Diligent size_t ShaderResourceCacheVk::GetRequiredMemorySize(Uint32 NumSets, Uint32 SetSizes[]) { Uint32 TotalResources = 0; - for (Uint32 t=0; t < NumSets; ++t) + for (Uint32 t = 0; t < NumSets; ++t) TotalResources += SetSizes[t]; auto MemorySize = NumSets * sizeof(DescriptorSet) + TotalResources * sizeof(Resource); return MemorySize; @@ -56,11 +56,11 @@ void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint3 // Ns = m_NumSets VERIFY(m_pAllocator == nullptr && m_pMemory == nullptr, "Cache already initialized"); - m_pAllocator = &MemAllocator; + m_pAllocator = &MemAllocator; VERIFY(NumSets < std::numeric_limits::max(), "NumSets (", NumSets, ") exceed maximum representable value"); m_NumSets = static_cast(NumSets); m_TotalResources = 0; - for (Uint32 t=0; t < NumSets; ++t) + for (Uint32 t = 0; t < NumSets; ++t) m_TotalResources += SetSizes[t]; auto MemorySize = NumSets * sizeof(DescriptorSet) + m_TotalResources * sizeof(Resource); VERIFY_EXPR(MemorySize == GetRequiredMemorySize(NumSets, SetSizes)); @@ -69,12 +69,12 @@ void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint3 #endif if (MemorySize > 0) { - m_pMemory = ALLOCATE_RAW( *m_pAllocator, "Memory for shader resource cache data", MemorySize); - auto* pSets = reinterpret_cast(m_pMemory); + m_pMemory = ALLOCATE_RAW(*m_pAllocator, "Memory for shader resource cache data", MemorySize); + auto* pSets = reinterpret_cast(m_pMemory); auto* pCurrResPtr = reinterpret_cast(pSets + m_NumSets); for (Uint32 t = 0; t < NumSets; ++t) { - new(&GetDescriptorSet(t)) DescriptorSet(SetSizes[t], SetSizes[t] > 0 ? pCurrResPtr : nullptr); + new (&GetDescriptorSet(t)) DescriptorSet(SetSizes[t], SetSizes[t] > 0 ? pCurrResPtr : nullptr); pCurrResPtr += SetSizes[t]; #ifdef _DEBUG m_DbgInitializedResources[t].resize(SetSizes[t]); @@ -89,7 +89,7 @@ void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint3 auto& DescrSet = GetDescriptorSet(Set); for (Uint32 res = 0; res < ArraySize; ++res) { - new(&DescrSet.GetResource(Offset + res)) Resource{Type}; + new (&DescrSet.GetResource(Offset + res)) Resource{Type}; #ifdef _DEBUG m_DbgInitializedResources[Set][Offset + res] = true; #endif @@ -97,7 +97,7 @@ void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint3 } #ifdef _DEBUG -void ShaderResourceCacheVk::DbgVerifyResourceInitialization()const +void ShaderResourceCacheVk::DbgVerifyResourceInitialization() const { for (const auto& SetFlags : m_DbgInitializedResources) { @@ -105,11 +105,11 @@ void ShaderResourceCacheVk::DbgVerifyResourceInitialization()const VERIFY(ResInitialized, "Not all resources in the cache have been initialized. This is a bug."); } } -void ShaderResourceCacheVk::DbgVerifyDynamicBuffersCounter()const +void ShaderResourceCacheVk::DbgVerifyDynamicBuffersCounter() const { - const auto* pResources = GetFirstResourcePtr(); - Uint32 NumDynamicBuffers = 0; - for (Uint32 res=0; res < m_TotalResources; ++res) + const auto* pResources = GetFirstResourcePtr(); + Uint32 NumDynamicBuffers = 0; + for (Uint32 res = 0; res < m_TotalResources; ++res) { const auto& Res = pResources[res]; if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer) @@ -117,8 +117,8 @@ void ShaderResourceCacheVk::DbgVerifyDynamicBuffersCounter()const if (Res.pObject && Res.pObject.RawPtr()->GetDesc().Usage == USAGE_DYNAMIC) ++NumDynamicBuffers; } - else if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || - Res.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer || + else if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || + Res.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer || Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer || Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer) { @@ -135,7 +135,7 @@ ShaderResourceCacheVk::~ShaderResourceCacheVk() if (m_pMemory) { auto* pResources = GetFirstResourcePtr(); - for (Uint32 res=0; res < m_TotalResources; ++res) + for (Uint32 res = 0; res < m_TotalResources; ++res) pResources[res].~Resource(); for (Uint32 t = 0; t < m_NumSets; ++t) GetDescriptorSet(t).~DescriptorSet(); @@ -144,7 +144,7 @@ ShaderResourceCacheVk::~ShaderResourceCacheVk() } } -template +template void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) { auto* pResources = GetFirstResourcePtr(); @@ -166,11 +166,11 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", - GetResourceStateString(RequiredState), ". Actual state: ", - GetResourceStateString(pBufferVk->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " - "with IDeviceContext::TransitionResourceStates()."); + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pBufferVk->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " + "with IDeviceContext::TransitionResourceStates()."); } } else @@ -191,17 +191,19 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: { auto* pBuffViewVk = Res.pObject.RawPtr(); - auto* pBufferVk = pBuffViewVk != nullptr ? ValidatedCast(pBuffViewVk->GetBuffer()) : nullptr; + auto* pBufferVk = pBuffViewVk != nullptr ? ValidatedCast(pBuffViewVk->GetBuffer()) : nullptr; if (pBufferVk != nullptr && pBufferVk->IsInKnownState()) { - const RESOURCE_STATE RequiredState = - (Res.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer || + const RESOURCE_STATE RequiredState = + (Res.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer || Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer) ? - RESOURCE_STATE_UNORDERED_ACCESS : RESOURCE_STATE_SHADER_RESOURCE; + RESOURCE_STATE_UNORDERED_ACCESS : + RESOURCE_STATE_SHADER_RESOURCE; #ifdef _DEBUG - const VkAccessFlags RequiredAccessFlags = (RequiredState == RESOURCE_STATE_SHADER_RESOURCE) ? - VK_ACCESS_SHADER_READ_BIT : (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); - VERIFY_EXPR( (ResourceStateFlagsToVkAccessFlags(RequiredState) & RequiredAccessFlags) == RequiredAccessFlags); + const VkAccessFlags RequiredAccessFlags = (RequiredState == RESOURCE_STATE_SHADER_RESOURCE) ? + VK_ACCESS_SHADER_READ_BIT : + (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); + VERIFY_EXPR((ResourceStateFlagsToVkAccessFlags(RequiredState) & RequiredAccessFlags) == RequiredAccessFlags); #endif const bool IsInRequiredState = pBufferVk->CheckState(RequiredState); @@ -210,11 +212,11 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of buffer '", pBufferVk->GetDesc().Name, "' is incorrect. Required state: ", - GetResourceStateString(RequiredState), ". Actual state: ", - GetResourceStateString(pBufferVk->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " - "with IDeviceContext::TransitionResourceStates()."); + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pBufferVk->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " + "with IDeviceContext::TransitionResourceStates()."); } } else @@ -236,13 +238,13 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) case SPIRVShaderResourceAttribs::ResourceType::StorageImage: { auto* pTextureViewVk = Res.pObject.RawPtr(); - auto* pTextureVk = pTextureViewVk != nullptr ? ValidatedCast(pTextureViewVk->GetTexture()) : nullptr; + auto* pTextureVk = pTextureViewVk != nullptr ? ValidatedCast(pTextureViewVk->GetTexture()) : nullptr; if (pTextureVk != nullptr && pTextureVk->IsInKnownState()) { - // The image subresources for a storage image must be in the VK_IMAGE_LAYOUT_GENERAL layout in + // The image subresources for a storage image must be in the VK_IMAGE_LAYOUT_GENERAL layout in // order to access its data in a shader (13.1.1) - // The image subresources for a sampled image or a combined image sampler must be in the - // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + // The image subresources for a sampled image or a combined image sampler must be in the + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // or VK_IMAGE_LAYOUT_GENERAL layout in order to access its data in a shader (13.1.3, 13.1.4). RESOURCE_STATE RequiredState; if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage) @@ -254,9 +256,9 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) { if (pTextureVk->GetDesc().BindFlags & BIND_DEPTH_STENCIL) { - // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL must only be used as a read - only depth / stencil attachment - // in a VkFramebuffer and/or as a read - only image in a shader (which can be read as a sampled image, combined - // image / sampler and /or input attachment). This layout is valid only for image subresources of images created + // VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL must only be used as a read - only depth / stencil attachment + // in a VkFramebuffer and/or as a read - only image in a shader (which can be read as a sampled image, combined + // image / sampler and /or input attachment). This layout is valid only for image subresources of images created // with the VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT usage bit enabled. (11.4) RequiredState = RESOURCE_STATE_DEPTH_READ; VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); @@ -274,11 +276,11 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) if (!IsInRequiredState) { LOG_ERROR_MESSAGE("State of texture '", pTextureVk->GetDesc().Name, "' is incorrect. Required state: ", - GetResourceStateString(RequiredState), ". Actual state: ", - GetResourceStateString(pTextureVk->GetState()), + GetResourceStateString(RequiredState), ". Actual state: ", + GetResourceStateString(pTextureVk->GetState()), ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the texture state " - "with IDeviceContext::TransitionResourceStates()."); + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the texture state " + "with IDeviceContext::TransitionResourceStates()."); } } else @@ -315,7 +317,7 @@ template void ShaderResourceCacheVk::TransitionResources(DeviceContextVkI template void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl); -VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescriptorWriteInfo()const +VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescriptorWriteInfo() const { VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected"); DEV_CHECK_ERR(pObject != nullptr, "Unable to get uniform buffer write info: cached object is null"); @@ -323,41 +325,45 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescript auto* pBuffVk = pObject.RawPtr(); // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC descriptor type require // buffer to be created with VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT - VERIFY_EXPR( (pBuffVk->GetDesc().BindFlags & BIND_UNIFORM_BUFFER) != 0); + VERIFY_EXPR((pBuffVk->GetDesc().BindFlags & BIND_UNIFORM_BUFFER) != 0); VkDescriptorBufferInfo DescrBuffInfo; DescrBuffInfo.buffer = pBuffVk->GetVkBuffer(); - // If descriptorType is VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, the offset member + // If descriptorType is VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, the offset member // of each element of pBufferInfo must be a multiple of VkPhysicalDeviceLimits::minUniformBufferOffsetAlignment (13.2.4) DescrBuffInfo.offset = 0; DescrBuffInfo.range = pBuffVk->GetDesc().uiSizeInBytes; return DescrBuffInfo; } -VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescriptorWriteInfo()const +VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescriptorWriteInfo() const { - VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || + // clang-format off + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer, "Storage buffer resource is expected"); + // clang-format on DEV_CHECK_ERR(pObject != nullptr, "Unable to get storage buffer write info: cached object is null"); - auto* pBuffViewVk = pObject.RawPtr(); - const auto& ViewDesc = pBuffViewVk->GetDesc(); - auto* pBuffVk = pBuffViewVk->GetBufferVk(); + auto* pBuffViewVk = pObject.RawPtr(); + const auto& ViewDesc = pBuffViewVk->GetDesc(); + auto* pBuffVk = pBuffViewVk->GetBufferVk(); - // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type + // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type // require buffer to be created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT (13.2.4) if (Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer) { // HLSL buffer SRVs are mapped to read-only storge buffers in SPIR-V - VERIFY(ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Attempting to bind buffer view '", ViewDesc.Name, "' as read-only storage buffer. " - "Expected view type is BUFFER_VIEW_SHADER_RESOURCE. Actual type: ", GetBufferViewTypeLiteralName(ViewDesc.ViewType)); + VERIFY(ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Attempting to bind buffer view '", ViewDesc.Name, + "' as read-only storage buffer. Expected view type is BUFFER_VIEW_SHADER_RESOURCE. Actual type: ", + GetBufferViewTypeLiteralName(ViewDesc.ViewType)); VERIFY((pBuffVk->GetDesc().BindFlags & BIND_SHADER_RESOURCE) != 0, "Buffer '", pBuffVk->GetDesc().Name, "' being set as read-only storage buffer was not created with BIND_SHADER_RESOURCE flag"); } else if (Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer) { - VERIFY(ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Attempting to bind buffer view '", ViewDesc.Name, "' as writable storage buffer. " - "Expected view type is BUFFER_VIEW_UNORDERED_ACCESS. Actual type: ", GetBufferViewTypeLiteralName(ViewDesc.ViewType)); + VERIFY(ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Attempting to bind buffer view '", ViewDesc.Name, + "' as writable storage buffer. Expected view type is BUFFER_VIEW_UNORDERED_ACCESS. Actual type: ", + GetBufferViewTypeLiteralName(ViewDesc.ViewType)); VERIFY((pBuffVk->GetDesc().BindFlags & BIND_UNORDERED_ACCESS) != 0, "Buffer '", pBuffVk->GetDesc().Name, "' being set as writable storage buffer was not created with BIND_UNORDERED_ACCESS flag"); } else @@ -374,12 +380,14 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript return DescrBuffInfo; } -VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo(bool IsImmutableSampler)const +VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo(bool IsImmutableSampler) const { - VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || + // clang-format off + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage, "Storage image, separate image or sampled image resource is expected"); + // clang-format on DEV_CHECK_ERR(pObject != nullptr, "Unable to get image descriptor write info: cached object is null"); bool IsStorageImage = Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage; @@ -393,14 +401,14 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn "Immutable sampler can't be assigned to separarate image or storage image"); if (Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSampler) { - // Immutable samplers are permanently bound into the set layout; later binding a sampler + // Immutable samplers are permanently bound into the set layout; later binding a sampler // into an immutable sampler slot in a descriptor set is not allowed (13.2.1) auto* pSamplerVk = ValidatedCast(pTexViewVk->GetSampler()); if (pSamplerVk != nullptr) { - // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - // and dstSet was not allocated with a layout that included immutable samplers for dstBinding with - // descriptorType, the sampler member of each element of pImageInfo must be a valid VkSampler + // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + // and dstSet was not allocated with a layout that included immutable samplers for dstBinding with + // descriptorType, the sampler member of each element of pImageInfo must be a valid VkSampler // object (13.2.4) DescrImgInfo.sampler = pSamplerVk->GetVkSampler(); } @@ -412,9 +420,9 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn #endif } DescrImgInfo.imageView = pTexViewVk->GetVulkanImageView(); - - // If descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, for each descriptor that will be accessed - // via load or store operations the imageLayout member for corresponding elements of pImageInfo + + // If descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, for each descriptor that will be accessed + // via load or store operations the imageLayout member for corresponding elements of pImageInfo // MUST be VK_IMAGE_LAYOUT_GENERAL (13.2.4) if (IsStorageImage) DescrImgInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -429,11 +437,13 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn return DescrImgInfo; } -VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo()const +VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo() const { + // clang-format off VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer || Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer, "Uniform or storage buffer resource is expected"); + // clang-format on DEV_CHECK_ERR(pObject != nullptr, "Unable to get buffer view write info: cached object is null"); // The following bits must have been set at buffer creation time: @@ -443,12 +453,13 @@ VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo()const return pBuffViewVk->GetVkBufferView(); } -VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWriteInfo()const +VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWriteInfo() const { VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected"); DEV_CHECK_ERR(pObject != nullptr, "Unable to get separate sampler descriptor write info: cached object is null"); auto* pSamplerVk = pObject.RawPtr(); + VkDescriptorImageInfo DescrImgInfo; // For VK_DESCRIPTOR_TYPE_SAMPLER, only the sample member of each element of VkWriteDescriptorSet::pImageInfo is accessed (13.2.4) DescrImgInfo.sampler = pSamplerVk->GetVkSampler(); @@ -457,4 +468,4 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWrite return DescrImgInfo; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index 0bf676ba..c61f3608 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -38,7 +38,7 @@ namespace Diligent { - + static Int32 FindImmutableSampler(SHADER_TYPE ShaderType, const PipelineResourceLayoutDesc& ResourceLayoutDesc, const SPIRVShaderResourceAttribs& Attribs, @@ -59,10 +59,10 @@ static Int32 FindImmutableSampler(SHADER_TYPE ShaderType, return -1; } - for (Uint32 s=0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) + for (Uint32 s = 0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) { const auto& StSam = ResourceLayoutDesc.StaticSamplers[s]; - if ( ((StSam.ShaderStages & ShaderType) != 0) && StreqSuff(Attribs.Name, StSam.SamplerOrTextureName, SamplerSuffix) ) + if (((StSam.ShaderStages & ShaderType) != 0) && StreqSuff(Attribs.Name, StSam.SamplerOrTextureName, SamplerSuffix)) return s; } @@ -79,8 +79,7 @@ static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE // Use texture or sampler name to derive separate sampler type // When HLSL-style combined image samplers are not used, CombinedSamplerSuffix is null return GetShaderVariableType(ShaderType, ResourceLayoutDesc.DefaultVariableType, ResourceLayoutDesc.Variables, ResourceLayoutDesc.NumVariables, - [&](const char* VarName) - { + [&](const char* VarName) { return StreqSuff(Attribs.Name, VarName, CombinedSamplerSuffix); }); } @@ -93,19 +92,19 @@ static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE ShaderResourceLayoutVk::~ShaderResourceLayoutVk() { - for (Uint32 r=0; r < GetTotalResourceCount(); ++r) + for (Uint32 r = 0; r < GetTotalResourceCount(); ++r) GetResource(r).~VkResource(); - for(Uint32 s=0; s < m_NumImmutableSamplers; ++s) + for (Uint32 s = 0; s < m_NumImmutableSamplers; ++s) GetImmutableSampler(s).~ImmutableSamplerPtrType(); } -void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr pSrcResources, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers) +void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr pSrcResources, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + bool AllocateImmutableSamplers) { VERIFY(!m_ResourceBuffer, "Memory has already been initialized"); VERIFY_EXPR(!m_pResources); @@ -118,31 +117,31 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptrGetCombinedSamplerSuffix(); // Count the number of resources to allocate all needed memory m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) + [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // { auto VarType = FindShaderVariableType(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); if (IsAllowedType(VarType, AllowedTypeBits)) { // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app - VERIFY( Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits::max()}, "Number of resources exceeds Uint16 maximum representable value"); + VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits::max()}, "Number of resources exceeds Uint16 maximum representable value"); ++m_NumResources[VarType]; } - } + } // ); Uint32 TotalResources = 0; - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType + 1)) { TotalResources += m_NumResources[VarType]; } - VERIFY(TotalResources <= Uint32{std::numeric_limits::max()}, "Total number of resources exceeds Uint16 maximum representable value" ); + VERIFY(TotalResources <= Uint32{std::numeric_limits::max()}, "Total number of resources exceeds Uint16 maximum representable value"); m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES] = static_cast(TotalResources); m_NumImmutableSamplers = 0; if (AllocateImmutableSamplers) { - for (Uint32 s=0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) + for (Uint32 s = 0; s < ResourceLayoutDesc.NumStaticSamplers; ++s) { const auto& StSamDesc = ResourceLayoutDesc.StaticSamplers[s]; if ((StSamDesc.ShaderStages & ShaderType) != 0) @@ -151,17 +150,17 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptr >(pRawMem, Allocator); - for (Uint32 s=0; s < m_NumImmutableSamplers; ++s) + auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader resource layout resources", MemSize); + m_ResourceBuffer = std::unique_ptr>(pRawMem, Allocator); + for (Uint32 s = 0; s < m_NumImmutableSamplers; ++s) { // We need to initialize immutable samplers auto& UninitializedImmutableSampler = GetImmutableSampler(s); - new(std::addressof(UninitializedImmutableSampler)) ImmutableSamplerPtrType; + new (std::addressof(UninitializedImmutableSampler)) ImmutableSamplerPtrType; } } @@ -173,11 +172,12 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr CurrResInd = {}; + Uint32 StaticResCacheSize = 0; const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); @@ -185,14 +185,14 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptrGetCombinedSamplerSuffix(); m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) + [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // { auto VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); if (!IsAllowedType(VarType, AllowedTypeBits)) return; Int32 SrcImmutableSamplerInd = -1; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) { // Only search for the immutable sampler for combined image samplers and separate samplers @@ -204,7 +204,7 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr= 0); - } + } // ); #ifdef _DEBUG @@ -231,14 +231,14 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptr pShaderResources[], - const PipelineResourceLayoutDesc& ResourceLayoutDesc) +void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 NumShaders, + const std::shared_ptr pShaderResources[], + const PipelineResourceLayoutDesc& ResourceLayoutDesc) { - auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) + auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) // { std::string ShadersStr; - for (Uint32 s=0; s < NumShaders; ++s) + for (Uint32 s = 0; s < NumShaders; ++s) { const auto& Resources = *pShaderResources[s]; if ((ShaderStages & Resources.GetShaderType()) != 0) @@ -263,15 +263,15 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool VariableFound = false; - for (Uint32 s=0; s < NumShaders && !VariableFound; ++s) + for (Uint32 s = 0; s < NumShaders && !VariableFound; ++s) { const auto& Resources = *pShaderResources[s]; - if ( (VarDesc.ShaderStages & Resources.GetShaderType()) != 0 ) + if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0) { for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res) { const auto& ResAttribs = Resources.GetResource(res); - VariableFound = (strcmp(ResAttribs.Name, VarDesc.Name) == 0); + VariableFound = (strcmp(ResAttribs.Name, VarDesc.Name) == 0); } } } @@ -293,10 +293,10 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } bool SamplerFound = false; - for (Uint32 s=0; s < NumShaders && !SamplerFound; ++s) + for (Uint32 s = 0; s < NumShaders && !SamplerFound; ++s) { const auto& Resources = *pShaderResources[s]; - if ( (StSamDesc.ShaderStages & Resources.GetShaderType()) == 0 ) + if ((StSamDesc.ShaderStages & Resources.GetShaderType()) == 0) continue; // Irrespective of whether HLSL-style combined image samplers are used, @@ -304,19 +304,19 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 for (Uint32 i = 0; i < Resources.GetNumSmpldImgs() && !SamplerFound; ++i) { const auto& SmplImg = Resources.GetSmpldImg(i); - SamplerFound = (strcmp(SmplImg.Name, StSamDesc.SamplerOrTextureName) == 0); + SamplerFound = (strcmp(SmplImg.Name, StSamDesc.SamplerOrTextureName) == 0); } if (!SamplerFound) { - // Check if static sampler is assigned to a separate sampler. + // Check if static sampler is assigned to a separate sampler. // In case HLSL-style combined image samplers are used, the condition is SepSmpl.Name == "g_Texture" + "_sampler". // Otherwise the condition is SepSmpl.Name == "g_Texture_sampler" + "". const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix(); for (Uint32 i = 0; i < Resources.GetNumSepSmplrs() && !SamplerFound; ++i) { const auto& SepSmpl = Resources.GetSepSmplr(i); - SamplerFound = StreqSuff(SepSmpl.Name, StSamDesc.SamplerOrTextureName, CombinedSamplerSuffix); + SamplerFound = StreqSuff(SepSmpl.Name, StSamDesc.SamplerOrTextureName, CombinedSamplerSuffix); } } } @@ -331,14 +331,14 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(Uint32 } #endif -void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, - Uint32 NumShaders, - ShaderResourceLayoutVk Layouts[], - std::shared_ptr pShaderResources[], - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - std::vector SPIRVs[], - class PipelineLayout& PipelineLayout) +void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice, + Uint32 NumShaders, + ShaderResourceLayoutVk Layouts[], + std::shared_ptr pShaderResources[], + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + std::vector SPIRVs[], + class PipelineLayout& PipelineLayout) { #ifdef DEVELOPMENT dvpVerifyResourceLayoutDesc(NumShaders, pShaderResources, ResourceLayoutDesc); @@ -348,26 +348,26 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* const Uint32 NumAllowedTypes = 0; const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - for (Uint32 s=0; s < NumShaders; ++s) + for (Uint32 s = 0; s < NumShaders; ++s) { constexpr bool AllocateImmutableSamplers = true; Layouts[s].AllocateMemory(std::move(pShaderResources[s]), LayoutDataAllocator, ResourceLayoutDesc, AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); } - + VERIFY_EXPR(NumShaders <= MaxShadersInPipeline); - std::array, MaxShadersInPipeline> CurrResInd = {}; - std::array CurrImmutableSamplerInd = {}; + std::array, MaxShadersInPipeline> CurrResInd = {}; + std::array CurrImmutableSamplerInd = {}; #ifdef _DEBUG std::unordered_map> dbgBindings_CacheOffsets; #endif auto AddResource = [&](Uint32 ShaderInd, ShaderResourceLayoutVk& ResLayout, - const SPIRVShaderResources& Resources, - const SPIRVShaderResourceAttribs& Attribs) + const SPIRVShaderResources& Resources, + const SPIRVShaderResourceAttribs& Attribs) // { - const auto ShaderType = Resources.GetShaderType(); - const SHADER_RESOURCE_VARIABLE_TYPE VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, Resources.GetCombinedSamplerSuffix()); + const auto ShaderType = Resources.GetShaderType(); + const SHADER_RESOURCE_VARIABLE_TYPE VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, Resources.GetCombinedSamplerSuffix()); if (!IsAllowedType(VarType, AllowedTypeBits)) return; @@ -375,7 +375,7 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* Uint32 DescriptorSet = 0; Uint32 CacheOffset = 0; Uint32 SamplerInd = VkResource::InvalidSamplerInd; - + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) { // Separate samplers are enumerated before separate images, so the sampler @@ -384,7 +384,7 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* } VkSampler vkImmutableSampler = VK_NULL_HANDLE; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) { // Only search for the immutable sampler for combined image samplers and separate samplers @@ -398,18 +398,18 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* vkImmutableSampler = ImmutableSampler.RawPtr()->GetVkSampler(); } } - + auto& ShaderSPIRV = SPIRVs[ShaderInd]; PipelineLayout.AllocateResourceSlot(Attribs, VarType, vkImmutableSampler, Resources.GetShaderType(), DescriptorSet, Binding, CacheOffset, ShaderSPIRV); VERIFY(DescriptorSet <= std::numeric_limits::max(), "Descriptor set (", DescriptorSet, ") excceeds maximum representable value"); - VERIFY(Binding <= std::numeric_limits ::max(), "Binding (", Binding, ") excceeds maximum representable value"); + VERIFY(Binding <= std::numeric_limits::max(), "Binding (", Binding, ") excceeds maximum representable value"); #ifdef _DEBUG // Verify that bindings and cache offsets monotonically increase in every descriptor set auto Binding_OffsetIt = dbgBindings_CacheOffsets.find(DescriptorSet); - if(Binding_OffsetIt != dbgBindings_CacheOffsets.end()) + if (Binding_OffsetIt != dbgBindings_CacheOffsets.end()) { - VERIFY(Binding > Binding_OffsetIt->second.first, "Binding for descriptor set ", DescriptorSet, " is not strictly monotonic"); + VERIFY(Binding > Binding_OffsetIt->second.first, "Binding for descriptor set ", DescriptorSet, " is not strictly monotonic"); VERIFY(CacheOffset > Binding_OffsetIt->second.second, "Cache offset for descriptor set ", DescriptorSet, " is not strictly monotonic"); } dbgBindings_CacheOffsets[DescriptorSet] = std::make_pair(Binding, CacheOffset); @@ -422,12 +422,12 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* // First process uniform buffers for all shader stages to make sure all UBs go first in every descriptor set for (Uint32 s = 0; s < NumShaders; ++s) { - auto& Layout = Layouts[s]; + auto& Layout = Layouts[s]; const auto& Resources = *Layout.m_pResources; for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n) { - const auto& UB = Resources.GetUB(n); - auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); + const auto& UB = Resources.GetUB(n); + auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { AddResource(s, Layout, Resources, UB); @@ -438,12 +438,12 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* // Second, process all storage buffers for (Uint32 s = 0; s < NumShaders; ++s) { - auto& Layout = Layouts[s]; + auto& Layout = Layouts[s]; const auto& Resources = *Layout.m_pResources; for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n) { - const auto& SB = Resources.GetSB(n); - auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); + const auto& SB = Resources.GetSB(n); + auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); if (IsAllowedType(VarType, AllowedTypeBits)) { AddResource(s, Layout, Resources, SB); @@ -454,8 +454,9 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* // Finally, process all other resource types for (Uint32 s = 0; s < NumShaders; ++s) { - auto& Layout = Layouts[s]; + auto& Layout = Layouts[s]; const auto& Resources = *Layout.m_pResources; + // clang-format off Resources.ProcessResources( [&](const SPIRVShaderResourceAttribs& UB, Uint32) { @@ -493,6 +494,7 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* AddResource(s, Layout, Resources, SepImg); } ); + // clang-format on } #ifdef _DEBUG @@ -512,10 +514,10 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, Uint32 CurrResourceCount, - SHADER_RESOURCE_VARIABLE_TYPE ImgVarType)const + SHADER_RESOURCE_VARIABLE_TYPE ImgVarType) const { VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); - + Uint32 SamplerInd = VkResource::InvalidSamplerInd; if (m_pResources->IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned()) { @@ -523,13 +525,14 @@ Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttr for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) { const auto& Res = GetResource(ImgVarType, SamplerInd); - if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) { VERIFY(ImgVarType == Res.GetVariableType(), - "The type (", GetShaderVariableTypeLiteralName(ImgVarType),") of separate image variable '", SepImg.Name, + "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()), - ") of the separate sampler '", SepSampler.Name, "' that is assigned to it. " + ") of the separate sampler '", SepSampler.Name, + "' that is assigned to it. " "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler " "is derived from the type of the corresponding separate image."); break; @@ -545,22 +548,22 @@ Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttr } -void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, - uint32_t ArrayElement, - const VkDescriptorImageInfo* pImageInfo, - const VkDescriptorBufferInfo* pBufferInfo, - const VkBufferView* pTexelBufferView)const +void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, + uint32_t ArrayElement, + const VkDescriptorImageInfo* pImageInfo, + const VkDescriptorBufferInfo* pBufferInfo, + const VkBufferView* pTexelBufferView) const { VERIFY_EXPR(vkDescrSet != VK_NULL_HANDLE); VkWriteDescriptorSet WriteDescrSet; - WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - WriteDescrSet.pNext = nullptr; - WriteDescrSet.dstSet = vkDescrSet; - WriteDescrSet.dstBinding = Binding; - WriteDescrSet.dstArrayElement = ArrayElement; - WriteDescrSet.descriptorCount = 1; - // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. + WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + WriteDescrSet.pNext = nullptr; + WriteDescrSet.dstSet = vkDescrSet; + WriteDescrSet.dstBinding = Binding; + WriteDescrSet.dstArrayElement = ArrayElement; + WriteDescrSet.descriptorCount = 1; + // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4) WriteDescrSet.descriptorType = PipelineLayout::GetVkDescriptorType(SpirvAttribs); WriteDescrSet.pImageInfo = pImageInfo; @@ -570,10 +573,10 @@ void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet ParentResLayout.m_LogicalDevice.UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr); } -template +template bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes, RefCntAutoPtr&& pObject, - TPreUpdateObject PreUpdateObject)const + TPreUpdateObject PreUpdateObject) const { // We cannot use ValidatedCast<> here as the resource retrieved from the // resource mapping can be of wrong type @@ -581,7 +584,7 @@ bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCach { if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) { - // Do not update resource if one is already bound unless it is dynamic. This may be + // Do not update resource if one is already bound unless it is dynamic. This may be // dangerous as writing descriptors while they are used by the GPU is an undefined behavior return false; } @@ -596,11 +599,11 @@ bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCach } } -void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* pBuffer, - ShaderResourceCacheVk::Resource& DstRes, - VkDescriptorSet vkDescrSet, - Uint32 ArrayInd, - Uint16& DynamicBuffersCounter)const +void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* pBuffer, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd, + Uint16& DynamicBuffersCounter) const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected"); RefCntAutoPtr pBufferVk(pBuffer, IID_BufferVk); @@ -608,8 +611,7 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* VerifyConstantBufferBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); #endif - auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) - { + auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) { if (pOldBuffer != nullptr && pOldBuffer->GetDesc().Usage == USAGE_DYNAMIC) { VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache"); @@ -623,7 +625,7 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC descriptor type require // buffer to be created with VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT - // Do not update descriptor for a dynamic uniform buffer. All dynamic resource + // Do not update descriptor for a dynamic uniform buffer. All dynamic resource // descriptors are updated at once by CommitDynamicResources() when SRB is committed. if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { @@ -633,15 +635,17 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* } } -void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* pBufferView, - ShaderResourceCacheVk::Resource& DstRes, - VkDescriptorSet vkDescrSet, - Uint32 ArrayInd, - Uint16& DynamicBuffersCounter)const +void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* pBufferView, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd, + Uint16& DynamicBuffersCounter) const { + // clang-format off VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer, "Storage buffer resource is expected"); + // clang-format on RefCntAutoPtr pBufferViewVk(pBufferView, IID_BufferViewVk); #ifdef DEVELOPMENT @@ -652,8 +656,7 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* } #endif - auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) - { + auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) { if (pOldBufferView != nullptr && pOldBufferView->GetBuffer()->GetDesc().Usage == USAGE_DYNAMIC) { VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache"); @@ -665,10 +668,10 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* if (UpdateCachedResource(DstRes, std::move(pBufferViewVk), UpdateDynamicBuffersCounter)) { - // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type + // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type // require buffer to be created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT (13.2.4) - // Do not update descriptor for a dynamic storage buffer. All dynamic resource + // Do not update descriptor for a dynamic storage buffer. All dynamic resource // descriptors are updated at once by CommitDynamicResources() when SRB is committed. if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { @@ -678,15 +681,17 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* } } -void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* pBufferView, - ShaderResourceCacheVk::Resource& DstRes, - VkDescriptorSet vkDescrSet, - Uint32 ArrayInd, - Uint16& DynamicBuffersCounter)const +void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* pBufferView, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd, + Uint16& DynamicBuffersCounter) const { + // clang-format off VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer, "Uniform or storage buffer resource is expected"); + // clang-format on RefCntAutoPtr pBufferViewVk(pBufferView, IID_BufferViewVk); #ifdef DEVELOPMENT @@ -697,8 +702,7 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* } #endif - auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) - { + auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) { if (pOldBufferView != nullptr && pOldBufferView->GetBuffer()->GetDesc().Usage == USAGE_DYNAMIC) { VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache"); @@ -714,7 +718,7 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* // * VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER -> VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT // * VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER -> VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT - // Do not update descriptor for a dynamic texel buffer. All dynamic resource descriptors + // Do not update descriptor for a dynamic texel buffer. All dynamic resource descriptors // are updated at once by CommitDynamicResources() when SRB is committed. if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { @@ -724,17 +728,19 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* } } -template +template void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* pTexView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, Uint32 ArrayInd, - TCacheSampler CacheSampler)const + TCacheSampler CacheSampler) const { + // clang-format off VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage, "Storage image, separate image or sampled image resource is expected"); + // clang-format on RefCntAutoPtr pTexViewVk0(pTexView, IID_TextureViewVk); #ifdef DEVELOPMENT @@ -744,7 +750,7 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); } #endif - if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*){})) + if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {})) { // We can do RawPtr here safely since UpdateCachedResource() returned true auto* pTexViewVk = DstRes.pObject.RawPtr(); @@ -759,7 +765,7 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* } #endif - // Do not update descriptor for a dynamic image. All dynamic resource descriptors + // Do not update descriptor for a dynamic image. All dynamic resource descriptors // are updated at once by CommitDynamicResources() when SRB is committed. if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { @@ -783,19 +789,19 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* } else { - LOG_ERROR_MESSAGE( "Failed to bind sampler to sampler variable '", SamplerAttribs.SpirvAttribs.Name, - "' assigned to separate image '", SpirvAttribs.GetPrintName(ArrayInd), "' in shader '", - ParentResLayout.GetShaderName(), "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\''); \ + LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.SpirvAttribs.Name, + "' assigned to separate image '", SpirvAttribs.GetPrintName(ArrayInd), "' in shader '", + ParentResLayout.GetShaderName(), "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\''); } } } } } -void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* pSampler, - ShaderResourceCacheVk::Resource& DstRes, - VkDescriptorSet vkDescrSet, - Uint32 ArrayInd)const +void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* pSampler, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd) const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected"); VERIFY(!IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler"); @@ -811,13 +817,14 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* { auto VarTypeStr = GetShaderVariableTypeLiteralName(GetVariableType()); LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", SpirvAttribs.GetPrintName(ArrayInd), - "' in shader '", ParentResLayout.GetShaderName(), "'. Attempting to bind another sampler or null is an error and may " + "' in shader '", ParentResLayout.GetShaderName(), + "'. Attempting to bind another sampler or null is an error and may " "cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic."); } #endif - if (UpdateCachedResource(DstRes, std::move(pSamplerVk), [](const SamplerVkImpl*, const SamplerVkImpl*){})) + if (UpdateCachedResource(DstRes, std::move(pSamplerVk), [](const SamplerVkImpl*, const SamplerVkImpl*) {})) { - // Do not update descriptor for a dynamic sampler. All dynamic resource descriptors + // Do not update descriptor for a dynamic sampler. All dynamic resource descriptors // are updated at once by CommitDynamicResources() when SRB is committed. if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { @@ -828,16 +835,16 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* } -void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache)const +void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const { VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize); auto& DstDescrSet = ResourceCache.GetDescriptorSet(DescriptorSet); - auto vkDescrSet = DstDescrSet.GetVkDescriptorSet(); + auto vkDescrSet = DstDescrSet.GetVkDescriptorSet(); #ifdef _DEBUG if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources) { - if(VariableType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || VariableType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) + if (VariableType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || VariableType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) { VERIFY(vkDescrSet != VK_NULL_HANDLE, "Static and mutable variables must have valid vulkan descriptor set assigned"); // Dynamic variables do not have vulkan descriptor set only until they are assigned one the first time @@ -855,18 +862,18 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 auto& DstRes = DstDescrSet.GetResource(CacheOffset + ArrayIndex); VERIFY(DstRes.Type == SpirvAttribs.Type, "Inconsistent types"); - if( pObj ) + if (pObj) { switch (SpirvAttribs.Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: CacheUniformBuffer(pObj, DstRes, vkDescrSet, ArrayIndex, ResourceCache.GetDynamicBuffersCounter()); - break; + break; case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: CacheStorageBuffer(pObj, DstRes, vkDescrSet, ArrayIndex, ResourceCache.GetDynamicBuffersCounter()); - break; + break; case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: @@ -876,20 +883,20 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 case SPIRVShaderResourceAttribs::ResourceType::StorageImage: case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: case SPIRVShaderResourceAttribs::ResourceType::SampledImage: - CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex, - [&](const VkResource& SeparateSampler, ISampler* pSampler) - { - VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.SpirvAttribs.Name, "' is assigned an immutable sampler"); - VERIFY_EXPR(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); - DEV_CHECK_ERR(SeparateSampler.SpirvAttribs.ArraySize == 1 || SeparateSampler.SpirvAttribs.ArraySize == SpirvAttribs.ArraySize, - "Array size (", SeparateSampler.SpirvAttribs.ArraySize,") of separate sampler variable '", - SeparateSampler.SpirvAttribs.Name, "' must be one or the same as the array size (", SpirvAttribs.ArraySize, - ") of separate image variable '", SpirvAttribs.Name, "' it is assigned to"); - Uint32 SamplerArrInd = SeparateSampler.SpirvAttribs.ArraySize == 1 ? 0 : ArrayIndex; - SeparateSampler.BindResource(pSampler, SamplerArrInd, ResourceCache); - } - ); - break; + CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex, + [&](const VkResource& SeparateSampler, ISampler* pSampler) { + VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.SpirvAttribs.Name, "' is assigned an immutable sampler"); + VERIFY_EXPR(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + DEV_CHECK_ERR(SeparateSampler.SpirvAttribs.ArraySize == 1 || SeparateSampler.SpirvAttribs.ArraySize == SpirvAttribs.ArraySize, + "Array size (", SeparateSampler.SpirvAttribs.ArraySize, + ") of separate sampler variable '", + SeparateSampler.SpirvAttribs.Name, + "' must be one or the same as the array size (", SpirvAttribs.ArraySize, + ") of separate image variable '", SpirvAttribs.Name, "' it is assigned to"); + Uint32 SamplerArrInd = SeparateSampler.SpirvAttribs.ArraySize == 1 ? 0 : ArrayIndex; + SeparateSampler.BindResource(pSampler, SamplerArrInd, ResourceCache); + }); + break; case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: if (!IsImmutableSamplerAssigned()) @@ -898,11 +905,11 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 } else { - // Immutable samplers are permanently bound into the set layout; later binding a sampler + // Immutable samplers are permanently bound into the set layout; later binding a sampler // into an immutable sampler slot in a descriptor set is not allowed (13.2.1) LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", SpirvAttribs.Name, '\''); } - break; + break; default: UNEXPECTED("Unknown resource type ", static_cast(SpirvAttribs.Type)); } @@ -911,14 +918,16 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 { if (DstRes.pObject && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { - LOG_ERROR_MESSAGE( "Shader variable '", SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource." ); + LOG_ERROR_MESSAGE("Shader variable '", SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), + "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. " + "Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource."); } DstRes.pObject.Release(); } } -bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache)const +bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const { VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize); @@ -938,14 +947,14 @@ bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const Shader void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout, const ShaderResourceCacheVk& SrcResourceCache, - ShaderResourceCacheVk& DstResourceCache)const + ShaderResourceCacheVk& DstResourceCache) const { auto NumStaticResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC]; VERIFY(NumStaticResources == SrcLayout.m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC], "Inconsistent number of static resources"); VERIFY(SrcLayout.m_pResources->GetShaderType() == m_pResources->GetShaderType(), "Incosistent shader types"); // Static shader resources are stored in one large continuous descriptor set - for (Uint32 r=0; r < NumStaticResources; ++r) + for (Uint32 r = 0; r < NumStaticResources; ++r) { // Get resource attributes const auto& DstRes = GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r); @@ -953,20 +962,20 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou VERIFY(SrcRes.Binding == SrcRes.SpirvAttribs.Type, "Unexpected binding"); VERIFY(SrcRes.SpirvAttribs.ArraySize == DstRes.SpirvAttribs.ArraySize, "Inconsistent array size"); - if (DstRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + if (DstRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && DstRes.IsImmutableSamplerAssigned()) continue; // Skip immutable samplers for (Uint32 ArrInd = 0; ArrInd < DstRes.SpirvAttribs.ArraySize; ++ArrInd) { - auto SrcOffset = SrcRes.CacheOffset + ArrInd; - const auto& SrcCachedSet = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet); - const auto& SrcCachedRes = SrcCachedSet.GetResource(SrcOffset); - IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr(); + auto SrcOffset = SrcRes.CacheOffset + ArrInd; + const auto& SrcCachedSet = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet); + const auto& SrcCachedRes = SrcCachedSet.GetResource(SrcOffset); + IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr(); if (!pObject) LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); - - auto DstOffset = DstRes.CacheOffset + ArrInd; + + auto DstOffset = DstRes.CacheOffset + ArrInd; IDeviceObject* pCachedResource = DstResourceCache.GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject; if (pCachedResource != pObject) { @@ -979,28 +988,28 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou #ifdef DEVELOPMENT -bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache)const +bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache) const { bool BindingsOK = true; - for(SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType + 1)) { - for(Uint32 r=0; r < m_NumResources[VarType]; ++r) + for (Uint32 r = 0; r < m_NumResources[VarType]; ++r) { const auto& Res = GetResource(VarType, r); VERIFY(Res.GetVariableType() == VarType, "Unexpected variable type"); - for(Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) + for (Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) { const auto& CachedDescrSet = ResourceCache.GetDescriptorSet(Res.DescriptorSet); - const auto& CachedRes = CachedDescrSet.GetResource(Res.CacheOffset + ArrInd); + const auto& CachedRes = CachedDescrSet.GetResource(Res.CacheOffset + ArrInd); VERIFY(CachedRes.Type == Res.SpirvAttribs.Type, "Inconsistent types"); - if (CachedRes.pObject == nullptr && - !(Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned())) + if (CachedRes.pObject == nullptr && + !(Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned())) { LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.GetVariableType()), " variable '", Res.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); BindingsOK = false; } -#ifdef _DEBUG - auto vkDescSet = CachedDescrSet.GetVkDescriptorSet(); +# ifdef _DEBUG + auto vkDescSet = CachedDescrSet.GetVkDescriptorSet(); auto dbgCacheContentType = ResourceCache.DbgGetContentType(); if (dbgCacheContentType == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources) VERIFY(vkDescSet == VK_NULL_HANDLE, "Static resource cache should never have vulkan descriptor set"); @@ -1017,7 +1026,7 @@ bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& Reso } else UNEXPECTED("Unexpected cache content type"); -#endif +# endif } } } @@ -1025,7 +1034,7 @@ bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& Reso } #endif -void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache)const +void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const { auto TotalResources = GetTotalResourceCount(); for (Uint32 r = 0; r < TotalResources; ++r) @@ -1035,8 +1044,8 @@ void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCache } } -void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache, - VkDescriptorSet vkDynamicDescriptorSet)const +void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache, + VkDescriptorSet vkDynamicDescriptorSet) const { Uint32 NumDynamicResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]; VERIFY(NumDynamicResources != 0, "This shader resource layout does not contain dynamic resources"); @@ -1055,43 +1064,43 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& #endif // Do not zero-initiaize arrays! - std::array DescrImgInfoArr; - std::array DescrBuffInfoArr; - std::array DescrBuffViewArr; - std::array WriteDescrSetArr; + std::array DescrImgInfoArr; + std::array DescrBuffInfoArr; + std::array DescrBuffViewArr; + std::array WriteDescrSetArr; Uint32 ResNum = 0, ArrElem = 0; - auto DescrImgIt = DescrImgInfoArr.begin(); - auto DescrBuffIt = DescrBuffInfoArr.begin(); - auto BuffViewIt = DescrBuffViewArr.begin(); - auto WriteDescrSetIt = WriteDescrSetArr.begin(); + auto DescrImgIt = DescrImgInfoArr.begin(); + auto DescrBuffIt = DescrBuffInfoArr.begin(); + auto BuffViewIt = DescrBuffViewArr.begin(); + auto WriteDescrSetIt = WriteDescrSetArr.begin(); #ifdef _DEBUG Int32 DynamicDescrSetIndex = -1; #endif - while(ResNum < NumDynamicResources) + while (ResNum < NumDynamicResources) { const auto& Res = GetResource(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC, ResNum); VERIFY_EXPR(Res.GetVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC); #ifdef _DEBUG - if(DynamicDescrSetIndex < 0) + if (DynamicDescrSetIndex < 0) DynamicDescrSetIndex = Res.DescriptorSet; else VERIFY(DynamicDescrSetIndex == Res.DescriptorSet, "Inconsistent dynamic resource desriptor set index"); #endif const auto& SetResources = ResourceCache.GetDescriptorSet(Res.DescriptorSet); - WriteDescrSetIt->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - WriteDescrSetIt->pNext = nullptr; + WriteDescrSetIt->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + WriteDescrSetIt->pNext = nullptr; VERIFY(SetResources.GetVkDescriptorSet() == VK_NULL_HANDLE, "Dynamic descriptor set must not be assigned to the resource cache"); WriteDescrSetIt->dstSet = vkDynamicDescriptorSet; VERIFY(WriteDescrSetIt->dstSet != VK_NULL_HANDLE, "Vulkan descriptor set must not be null"); - WriteDescrSetIt->dstBinding = Res.Binding; + WriteDescrSetIt->dstBinding = Res.Binding; WriteDescrSetIt->dstArrayElement = ArrElem; - // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. + // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4) WriteDescrSetIt->descriptorType = PipelineLayout::GetVkDescriptorType(Res.SpirvAttribs); - + // For every resource type, try to batch as many descriptor updates as we can switch (Res.SpirvAttribs.Type) { @@ -1100,23 +1109,23 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& while (ArrElem < Res.SpirvAttribs.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); - *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo(); + *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo(); ++DescrBuffIt; ++ArrElem; } - break; - + break; + case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt); while (ArrElem < Res.SpirvAttribs.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); - *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo(); + *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo(); ++DescrBuffIt; ++ArrElem; } - break; + break; case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: @@ -1124,11 +1133,11 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& while (ArrElem < Res.SpirvAttribs.ArraySize && BuffViewIt != DescrBuffViewArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); - *BuffViewIt = CachedRes.GetBufferViewWriteInfo(); + *BuffViewIt = CachedRes.GetBufferViewWriteInfo(); ++BuffViewIt; ++ArrElem; } - break; + break; case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: case SPIRVShaderResourceAttribs::ResourceType::StorageImage: @@ -1137,19 +1146,19 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& while (ArrElem < Res.SpirvAttribs.ArraySize && DescrImgIt != DescrImgInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); - *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Res.IsImmutableSamplerAssigned()); + *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Res.IsImmutableSamplerAssigned()); ++DescrImgIt; ++ArrElem; } - break; + break; case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter: // Do nothing - break; - + break; + case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: - // Immutable samplers are permanently bound into the set layout; later binding a sampler + // Immutable samplers are permanently bound into the set layout; later binding a sampler // into an immutable sampler slot in a descriptor set is not allowed (13.2.1) if (!Res.IsImmutableSamplerAssigned()) { @@ -1157,17 +1166,17 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& while (ArrElem < Res.SpirvAttribs.ArraySize && DescrImgIt != DescrImgInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); - *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo(); + *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo(); ++DescrImgIt; ++ArrElem; } } else { - ArrElem = Res.SpirvAttribs.ArraySize; + ArrElem = Res.SpirvAttribs.ArraySize; WriteDescrSetIt->dstArrayElement = Res.SpirvAttribs.ArraySize; } - break; + break; default: UNEXPECTED("Unexpected resource type"); @@ -1185,22 +1194,22 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& // If we ran out of space in any of the arrays or if we processed all resources, // flush pending updates and reset iterators - if (ResNum == NumDynamicResources || - DescrImgIt == DescrImgInfoArr.end() || - DescrBuffIt == DescrBuffInfoArr.end() || - BuffViewIt == DescrBuffViewArr.end() || + if (ResNum == NumDynamicResources || + DescrImgIt == DescrImgInfoArr.end() || + DescrBuffIt == DescrBuffInfoArr.end() || + BuffViewIt == DescrBuffViewArr.end() || WriteDescrSetIt == WriteDescrSetArr.end()) { auto DescrWriteCount = static_cast(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt)); if (DescrWriteCount > 0) m_LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr); - DescrImgIt = DescrImgInfoArr.begin(); - DescrBuffIt = DescrBuffInfoArr.begin(); - BuffViewIt = DescrBuffViewArr.begin(); + DescrImgIt = DescrImgInfoArr.begin(); + DescrBuffIt = DescrBuffInfoArr.begin(); + BuffViewIt = DescrBuffViewArr.begin(); WriteDescrSetIt = WriteDescrSetArr.begin(); } } } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp index 02bdfa93..ae7ee32e 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp @@ -29,74 +29,76 @@ namespace Diligent { -size_t ShaderVariableManagerVk::GetRequiredMemorySize(const ShaderResourceLayoutVk& Layout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumVariables) +size_t ShaderVariableManagerVk::GetRequiredMemorySize(const ShaderResourceLayoutVk& Layout, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + Uint32& NumVariables) { - NumVariables = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - const bool UsingSeparateSamplers = Layout.IsUsingSeparateSamplers(); - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) + NumVariables = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + const bool UsingSeparateSamplers = Layout.IsUsingSeparateSamplers(); + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType + 1)) { if (IsAllowedType(VarType, AllowedTypeBits)) { auto NumResources = Layout.GetResourceCount(VarType); - for (Uint32 r=0; r < NumResources; ++r) + for (Uint32 r = 0; r < NumResources; ++r) { const auto& SrcRes = Layout.GetResource(VarType, r); // When using HLSL-style combined image samplers, we need to skip separate samplers. // Also always skip immutable separate samplers. - if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && - (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()) ) + if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned())) continue; ++NumVariables; } } } - + return NumVariables * sizeof(ShaderVariableVkImpl); } // Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes -ShaderVariableManagerVk::ShaderVariableManagerVk(IObject& Owner, - const ShaderResourceLayoutVk& SrcLayout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheVk& ResourceCache) : +ShaderVariableManagerVk::ShaderVariableManagerVk(IObject& Owner, + const ShaderResourceLayoutVk& SrcLayout, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheVk& ResourceCache) : + // clang-format off m_Owner {Owner }, m_ResourceCache{ResourceCache} #ifdef _DEBUG , m_DbgAllocator {Allocator} #endif +// clang-format on { const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); VERIFY_EXPR(m_NumVariables == 0); auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables); - - if(m_NumVariables == 0) + + if (m_NumVariables == 0) return; - + auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader variables", MemSize); - m_pVariables = reinterpret_cast(pRawMem); + m_pVariables = reinterpret_cast(pRawMem); - Uint32 VarInd = 0; + Uint32 VarInd = 0; const bool UsingSeparateSamplers = SrcLayout.IsUsingSeparateSamplers(); - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType+1)) + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType + 1)) { if (!IsAllowedType(VarType, AllowedTypeBits)) continue; Uint32 NumResources = SrcLayout.GetResourceCount(VarType); - for (Uint32 r=0; r < NumResources; ++r) + for (Uint32 r = 0; r < NumResources; ++r) { const auto& SrcRes = SrcLayout.GetResource(VarType, r); // Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers. - if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && - (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()) ) + if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned())) continue; ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this, SrcRes); @@ -117,7 +119,7 @@ void ShaderVariableManagerVk::DestroyVariables(IMemoryAllocator& Allocator) if (m_pVariables != nullptr) { - for (Uint32 v=0; v < m_NumVariables; ++v) + for (Uint32 v = 0; v < m_NumVariables; ++v) m_pVariables[v].~ShaderVariableVkImpl(); Allocator.Free(m_pVariables); m_pVariables = nullptr; @@ -129,7 +131,7 @@ ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) ShaderVariableVkImpl* pVar = nullptr; for (Uint32 v = 0; v < m_NumVariables; ++v) { - auto& Var = m_pVariables[v]; + auto& Var = m_pVariables[v]; const auto& Res = Var.m_Resource; if (strcmp(Res.SpirvAttribs.Name, Name) == 0) { @@ -176,45 +178,48 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, { if (!pResourceMapping) { - LOG_ERROR_MESSAGE( "Failed to bind resources: resource mapping is null" ); + LOG_ERROR_MESSAGE("Failed to bind resources: resource mapping is null"); return; } - if ( (Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0 ) + if ((Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0) Flags |= BIND_SHADER_RESOURCES_UPDATE_ALL; - for (Uint32 v=0; v < m_NumVariables; ++v) + for (Uint32 v = 0; v < m_NumVariables; ++v) { - auto& Var = m_pVariables[v]; + auto& Var = m_pVariables[v]; const auto& Res = Var.m_Resource; - + // There should be no immutable separate samplers VERIFY(Res.SpirvAttribs.Type != SPIRVShaderResourceAttribs::ResourceType::SeparateSampler || !Res.IsImmutableSamplerAssigned(), "There must be no shader resource variables for immutable separate samplers"); - if ( (Flags & (1 << Res.GetVariableType())) == 0 ) + if ((Flags & (1 << Res.GetVariableType())) == 0) continue; for (Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) { - if ( (Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(ArrInd, m_ResourceCache) ) + if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(ArrInd, m_ResourceCache)) continue; - const auto* VarName = Res.SpirvAttribs.Name; + const auto* VarName = Res.SpirvAttribs.Name; RefCntAutoPtr pObj; - pResourceMapping->GetResource( VarName, &pObj, ArrInd ); + pResourceMapping->GetResource(VarName, &pObj, ArrInd); if (pObj) { Res.BindResource(pObj, ArrInd, m_ResourceCache); } else { - if ( (Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(ArrInd, m_ResourceCache) ) - LOG_ERROR_MESSAGE( "Unable to bind resource to shader variable '", Res.SpirvAttribs.GetPrintName(ArrInd), "': resource is not found in the resource mapping. " - "Do not use BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED flag to suppress the message if this is not an issue." ); + if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(ArrInd, m_ResourceCache)) + { + LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.SpirvAttribs.GetPrintName(ArrInd), + "': resource is not found in the resource mapping. " + "Do not use BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED flag to suppress the message if this is not an issue."); + } } } } } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp index 75bd3001..8ad01c6b 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp @@ -31,7 +31,7 @@ #include "GLSLSourceBuilder.h" #if !NO_GLSLANG -#include "SPIRVUtils.h" +# include "SPIRVUtils.h" #endif namespace Diligent @@ -39,13 +39,15 @@ namespace Diligent ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, - const ShaderCreateInfo& CreationAttribs) : + const ShaderCreateInfo& CreationAttribs) : + // clang-format off TShaderBase { pRefCounters, pRenderDeviceVk, CreationAttribs.Desc } +// clang-format on { if (CreationAttribs.Source != nullptr || CreationAttribs.FilePath != nullptr) { @@ -62,9 +64,9 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters, else { auto GLSLSource = BuildGLSLSourceString(CreationAttribs, pRenderDeviceVk->GetDeviceCaps(), TargetGLSLCompiler::glslang, "#define TARGET_API_VULKAN 1\n"); - m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str(), static_cast(GLSLSource.length()), CreationAttribs.ppCompilerOutput); + m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str(), static_cast(GLSLSource.length()), CreationAttribs.ppCompilerOutput); } - + if (m_SPIRV.empty()) { LOG_ERROR_AND_THROW("Failed to compile shader"); @@ -75,24 +77,24 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters, { DEV_CHECK_ERR(CreationAttribs.ByteCodeSize != 0, "ByteCodeSize must not be 0"); DEV_CHECK_ERR(CreationAttribs.ByteCodeSize % 4 == 0, "Byte code size (", CreationAttribs.ByteCodeSize, ") is not multiple of 4"); - m_SPIRV.resize(CreationAttribs.ByteCodeSize/4); + m_SPIRV.resize(CreationAttribs.ByteCodeSize / 4); memcpy(m_SPIRV.data(), CreationAttribs.ByteCode, CreationAttribs.ByteCodeSize); } - else + else { LOG_ERROR_AND_THROW("Shader source must be provided through one of the 'Source', 'FilePath' or 'ByteCode' members"); } // We cannot create shader module here because resource bindings are assigned when // pipeline state is created - + // Load shader resources - auto& Allocator = GetRawAllocator(); - auto* pRawMem = ALLOCATE(Allocator, "Allocator for ShaderResources", SPIRVShaderResources, 1); - bool IsHLSLVertexShader = CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL && m_Desc.ShaderType == SHADER_TYPE_VERTEX; - auto* pResources = new (pRawMem) SPIRVShaderResources(Allocator, pRenderDeviceVk, m_SPIRV, m_Desc, CreationAttribs.UseCombinedTextureSamplers ? CreationAttribs.CombinedSamplerSuffix : nullptr, IsHLSLVertexShader, m_EntryPoint); + auto& Allocator = GetRawAllocator(); + auto* pRawMem = ALLOCATE(Allocator, "Allocator for ShaderResources", SPIRVShaderResources, 1); + bool IsHLSLVertexShader = CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL && m_Desc.ShaderType == SHADER_TYPE_VERTEX; + auto* pResources = new (pRawMem) SPIRVShaderResources(Allocator, pRenderDeviceVk, m_SPIRV, m_Desc, CreationAttribs.UseCombinedTextureSamplers ? CreationAttribs.CombinedSamplerSuffix : nullptr, IsHLSLVertexShader, m_EntryPoint); m_pShaderResources.reset(pResources, STDDeleterRawMem(Allocator)); - + if (IsHLSLVertexShader) { MapHLSLVertexShaderInputs(); @@ -103,11 +105,11 @@ void ShaderVkImpl::MapHLSLVertexShaderInputs() { for (Uint32 i = 0; i < m_pShaderResources->GetNumShaderStageInputs(); ++i) { - const auto& Input = m_pShaderResources->GetShaderStageInputAttribs(i); - const char* s = Input.Semantic; + const auto& Input = m_pShaderResources->GetShaderStageInputAttribs(i); + const char* s = Input.Semantic; static const char* Prefix = "attrib"; - const char* p = Prefix; - while(*s != 0 && *p != 0 && *p == std::tolower(static_cast(*s)) ) + const char* p = Prefix; + while (*s != 0 && *p != 0 && *p == std::tolower(static_cast(*s))) { ++p; ++s; @@ -119,8 +121,8 @@ void ShaderVkImpl::MapHLSLVertexShaderInputs() continue; } - char* EndPtr = nullptr; - auto Location = static_cast(strtol(s, &EndPtr, 10)); + char* EndPtr = nullptr; + auto Location = static_cast(strtol(s, &EndPtr, 10)); if (*EndPtr != 0) { LOG_ERROR_MESSAGE("Unable to map semantic '", Input.Semantic, "' to input location: semantics must have 'ATTRIBx' format."); @@ -134,7 +136,7 @@ ShaderVkImpl::~ShaderVkImpl() { } -ShaderResourceDesc ShaderVkImpl::GetResource(Uint32 Index)const +ShaderResourceDesc ShaderVkImpl::GetResource(Uint32 Index) const { auto ResCount = GetResourceCount(); DEV_CHECK_ERR(Index < ResCount, "Resource index (", Index, ") is out of range"); @@ -142,9 +144,9 @@ ShaderResourceDesc ShaderVkImpl::GetResource(Uint32 Index)const if (Index < ResCount) { const auto& SPIRVResource = m_pShaderResources->GetResource(Index); - ResourceDesc = SPIRVResource.GetResourceDesc(); + ResourceDesc = SPIRVResource.GetResourceDesc(); } return ResourceDesc; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp index e1d3a8cd..f63504ca 100644 --- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp @@ -32,64 +32,78 @@ namespace Diligent { -SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters* pRefCounters, - const SwapChainDesc& SCDesc, - RenderDeviceVkImpl* pRenderDeviceVk, - DeviceContextVkImpl* pDeviceContextVk, - void* pNativeWndHandle) : +SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters* pRefCounters, + const SwapChainDesc& SCDesc, + RenderDeviceVkImpl* pRenderDeviceVk, + DeviceContextVkImpl* pDeviceContextVk, + void* pNativeWndHandle) : + // clang-format off TSwapChainBase {pRefCounters, pRenderDeviceVk, pDeviceContextVk, SCDesc}, m_VulkanInstance {pRenderDeviceVk->GetVulkanInstance()}, m_pBackBufferRTV {STD_ALLOCATOR_RAW_MEM(RefCntAutoPtr, GetRawAllocator(), "Allocator for vector>")}, m_SwapChainImagesInitialized {STD_ALLOCATOR_RAW_MEM(bool, GetRawAllocator(), "Allocator for vector")}, m_ImageAcquiredFenceSubmitted{STD_ALLOCATOR_RAW_MEM(bool, GetRawAllocator(), "Allocator for vector")} +// clang-format on { // Create OS-specific surface #if defined(VK_USE_PLATFORM_WIN32_KHR) VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = GetModuleHandle(NULL); - surfaceCreateInfo.hwnd = (HWND)pNativeWndHandle; + surfaceCreateInfo.hwnd = (HWND)pNativeWndHandle; + auto err = vkCreateWin32SurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface); #elif defined(VK_USE_PLATFORM_ANDROID_KHR) VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; - surfaceCreateInfo.window = (ANativeWindow*) pNativeWndHandle; + + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + surfaceCreateInfo.window = (ANativeWindow*)pNativeWndHandle; + auto err = vkCreateAndroidSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, NULL, &m_VkSurface); #elif defined(VK_USE_PLATFORM_IOS_MVK) VkIOSSurfaceCreateInfoMVK surfaceCreateInfo = {}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; surfaceCreateInfo.pView = pNativeWndHandle; + auto err = vkCreateIOSSurfaceMVK(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface); #elif defined(VK_USE_PLATFORM_MACOS_MVK) VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; surfaceCreateInfo.pView = pNativeWndHandle; + auto err = vkCreateMacOSSurfaceMVK(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, NULL, &m_VkSurface); #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {}; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.display = display; - surfaceCreatem_VkSurface = window; + surfaceCreatem_VkSurface = window; + err = vkCreateWaylandSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface); #elif defined(VK_USE_PLATFORM_XCB_KHR) VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; struct XCBInfo { xcb_connection_t* connection = nullptr; - uint32_t window = 0; + uint32_t window = 0; }; - XCBInfo& info = *reinterpret_cast(pNativeWndHandle); + XCBInfo& info = *reinterpret_cast(pNativeWndHandle); surfaceCreateInfo.connection = info.connection; - surfaceCreateInfo.window = info.window; + surfaceCreateInfo.window = info.window; + auto err = vkCreateXcbSurfaceKHR(m_VulkanInstance->GetVkInstance(), &surfaceCreateInfo, nullptr, &m_VkSurface); #endif CHECK_VK_ERROR_AND_THROW(err, "Failed to create OS-specific surface"); - const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); - auto& CmdQueueVK = pRenderDeviceVk->GetCommandQueue(0); - auto QueueFamilyIndex = CmdQueueVK.GetQueueFamilyIndex(); - if( !PhysicalDevice.CheckPresentSupport(QueueFamilyIndex, m_VkSurface) ) + const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); + auto& CmdQueueVK = pRenderDeviceVk->GetCommandQueue(0); + auto QueueFamilyIndex = CmdQueueVK.GetQueueFamilyIndex(); + if (!PhysicalDevice.CheckPresentSupport(QueueFamilyIndex, m_VkSurface)) { LOG_ERROR_AND_THROW("Selected physical device does not support present capability.\n" "There could be few ways to mitigate this problem. One is to try to find another queue that supports present, but does not support graphics and compute capabilities." @@ -99,16 +113,18 @@ SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters* pRefCounters, CreateVulkanSwapChain(); InitBuffersAndViews(); auto res = AcquireNextImage(pDeviceContextVk); - DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the newly created swap chain"); (void)res; + DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the newly created swap chain"); + (void)res; } void SwapChainVkImpl::CreateVulkanSwapChain() { - auto* pRenderDeviceVk = m_pRenderDevice.RawPtr(); - const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); - auto vkDeviceHandle = PhysicalDevice.GetVkDeviceHandle(); + auto* pRenderDeviceVk = m_pRenderDevice.RawPtr(); + const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); + auto vkDeviceHandle = PhysicalDevice.GetVkDeviceHandle(); // Get the list of VkFormats that are supported: uint32_t formatCount = 0; + auto err = vkGetPhysicalDeviceSurfaceFormatsKHR(vkDeviceHandle, m_VkSurface, &formatCount, NULL); CHECK_VK_ERROR_AND_THROW(err, "Failed to query number of supported formats"); VERIFY_EXPR(formatCount > 0); @@ -117,8 +133,9 @@ void SwapChainVkImpl::CreateVulkanSwapChain() CHECK_VK_ERROR_AND_THROW(err, "Failed to query supported format properties"); VERIFY_EXPR(formatCount == SupportedFormats.size()); m_VkColorFormat = TexFormatToVkFormat(m_SwapChainDesc.ColorBufferFormat); + VkColorSpaceKHR ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - if (formatCount == 1 && SupportedFormats[0].format == VK_FORMAT_UNDEFINED) + if (formatCount == 1 && SupportedFormats[0].format == VK_FORMAT_UNDEFINED) { // If the format list includes just one entry of VK_FORMAT_UNDEFINED, // the surface has no preferred format. Otherwise, at least one @@ -126,28 +143,30 @@ void SwapChainVkImpl::CreateVulkanSwapChain() // Do nothing } - else + else { bool FmtFound = false; - for(const auto& SrfFmt : SupportedFormats) + for (const auto& SrfFmt : SupportedFormats) { - if(SrfFmt.format == m_VkColorFormat) + if (SrfFmt.format == m_VkColorFormat) { - FmtFound = true; + FmtFound = true; ColorSpace = SrfFmt.colorSpace; break; } } - if(!FmtFound) + if (!FmtFound) { VkFormat VkReplacementColorFormat = VK_FORMAT_UNDEFINED; - switch(m_VkColorFormat) + switch (m_VkColorFormat) { + // clang-format off case VK_FORMAT_R8G8B8A8_UNORM: VkReplacementColorFormat = VK_FORMAT_B8G8R8A8_UNORM; break; case VK_FORMAT_B8G8R8A8_UNORM: VkReplacementColorFormat = VK_FORMAT_R8G8B8A8_UNORM; break; case VK_FORMAT_B8G8R8A8_SRGB: VkReplacementColorFormat = VK_FORMAT_R8G8B8A8_SRGB; break; case VK_FORMAT_R8G8B8A8_SRGB: VkReplacementColorFormat = VK_FORMAT_B8G8R8A8_SRGB; break; default: VkReplacementColorFormat = VK_FORMAT_UNDEFINED; + // clang-format on } bool ReplacementFmtFound = false; @@ -156,30 +175,32 @@ void SwapChainVkImpl::CreateVulkanSwapChain() if (SrfFmt.format == VkReplacementColorFormat) { ReplacementFmtFound = true; - ColorSpace = SrfFmt.colorSpace; + ColorSpace = SrfFmt.colorSpace; break; } } - if(ReplacementFmtFound) + if (ReplacementFmtFound) { - m_VkColorFormat = VkReplacementColorFormat; + m_VkColorFormat = VkReplacementColorFormat; auto NewColorBufferFormat = VkFormatToTexFormat(VkReplacementColorFormat); LOG_INFO_MESSAGE("Requested color buffer format ", GetTextureFormatAttribs(m_SwapChainDesc.ColorBufferFormat).Name, " is not supported by the surface and will be replaced with ", GetTextureFormatAttribs(NewColorBufferFormat).Name); m_SwapChainDesc.ColorBufferFormat = NewColorBufferFormat; } else { - LOG_WARNING_MESSAGE("Requested color buffer format ", GetTextureFormatAttribs(m_SwapChainDesc.ColorBufferFormat).Name ,"is not supported by the surface"); + LOG_WARNING_MESSAGE("Requested color buffer format ", GetTextureFormatAttribs(m_SwapChainDesc.ColorBufferFormat).Name, "is not supported by the surface"); } } } - + VkSurfaceCapabilitiesKHR surfCapabilities = {}; + err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkDeviceHandle, m_VkSurface, &surfCapabilities); CHECK_VK_ERROR_AND_THROW(err, "Failed to query physical device surface capabilities"); uint32_t presentModeCount = 0; + err = vkGetPhysicalDeviceSurfacePresentModesKHR(vkDeviceHandle, m_VkSurface, &presentModeCount, NULL); CHECK_VK_ERROR_AND_THROW(err, "Failed to query surface present mode count"); VERIFY_EXPR(presentModeCount > 0); @@ -194,27 +215,28 @@ void SwapChainVkImpl::CreateVulkanSwapChain() { // If the surface size is undefined, the size is set to // the size of the images requested. - swapchainExtent.width = std::min(std::max(m_SwapChainDesc.Width, surfCapabilities.minImageExtent.width), surfCapabilities.maxImageExtent.width); + swapchainExtent.width = std::min(std::max(m_SwapChainDesc.Width, surfCapabilities.minImageExtent.width), surfCapabilities.maxImageExtent.width); swapchainExtent.height = std::min(std::max(m_SwapChainDesc.Height, surfCapabilities.minImageExtent.height), surfCapabilities.maxImageExtent.height); } - else + else { // If the surface size is defined, the swap chain size must match swapchainExtent = surfCapabilities.currentExtent; } - swapchainExtent.width = std::max(swapchainExtent.width, 1u); + swapchainExtent.width = std::max(swapchainExtent.width, 1u); swapchainExtent.height = std::max(swapchainExtent.height, 1u); m_SwapChainDesc.Width = swapchainExtent.width; m_SwapChainDesc.Height = swapchainExtent.height; // Mailbox is the lowest latency non-tearing presentation mode VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; + bool PresentModeSupported = std::find(presentModes.begin(), presentModes.end(), swapchainPresentMode) != presentModes.end(); - if(!PresentModeSupported) + if (!PresentModeSupported) { swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; // The FIFO present mode is guaranteed by the spec to be supported - VERIFY(std::find(presentModes.begin(), presentModes.end(), swapchainPresentMode) != presentModes.end(), "FIFO present mode must be supported" ); + VERIFY(std::find(presentModes.begin(), presentModes.end(), swapchainPresentMode) != presentModes.end(), "FIFO present mode must be supported"); } // Determine the number of VkImage's to use in the swap chain. @@ -222,7 +244,7 @@ void SwapChainVkImpl::CreateVulkanSwapChain() // Asking for minImageCount images ensures that we can acquire // 1 presentable image as long as we present it before attempting // to acquire another. - if(m_SwapChainDesc.BufferCount < surfCapabilities.minImageCount) + if (m_SwapChainDesc.BufferCount < surfCapabilities.minImageCount) { LOG_INFO_MESSAGE("Requested back buffer count (", m_SwapChainDesc.BufferCount, ") is smaller than the minimal image count supported for this surface (", surfCapabilities.minImageCount, "). Resetting to ", surfCapabilities.minImageCount); m_SwapChainDesc.BufferCount = surfCapabilities.minImageCount; @@ -234,29 +256,34 @@ void SwapChainVkImpl::CreateVulkanSwapChain() } uint32_t desiredNumberOfSwapChainImages = m_SwapChainDesc.BufferCount; - VkSurfaceTransformFlagBitsKHR preTransform = - (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : - surfCapabilities.currentTransform; + VkSurfaceTransformFlagBitsKHR preTransform = + (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : + surfCapabilities.currentTransform; // Find a supported composite alpha mode - one of these is guaranteed to be set - VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - }; - for (uint32_t i = 0; i < _countof(compositeAlphaFlags); i++) { - if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { + VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = // + { + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + }; + for (uint32_t i = 0; i < _countof(compositeAlphaFlags); i++) + { + if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) + { compositeAlpha = compositeAlphaFlags[i]; break; } } auto oldSwapchain = m_VkSwapChain; - m_VkSwapChain = VK_NULL_HANDLE; + m_VkSwapChain = VK_NULL_HANDLE; + VkSwapchainCreateInfoKHR swapchain_ci = {}; + swapchain_ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_ci.pNext = NULL; swapchain_ci.surface = m_VkSurface; @@ -271,7 +298,7 @@ void SwapChainVkImpl::CreateVulkanSwapChain() swapchain_ci.oldSwapchain = oldSwapchain; swapchain_ci.clipped = VK_TRUE; swapchain_ci.imageColorSpace = ColorSpace; - + DEV_CHECK_ERR(m_SwapChainDesc.Usage != 0, "No swap chain usage flags defined"); if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_RENDER_TARGET) swapchain_ci.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; @@ -282,9 +309,9 @@ void SwapChainVkImpl::CreateVulkanSwapChain() // vkCmdClearColorImage() command requires the image to use VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout // that requires VK_IMAGE_USAGE_TRANSFER_DST_BIT to be set - swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_ci.queueFamilyIndexCount = 0; - swapchain_ci.pQueueFamilyIndices = NULL; + swapchain_ci.pQueueFamilyIndices = NULL; //uint32_t queueFamilyIndices[] = { (uint32_t)info.graphics_queue_family_index, (uint32_t)info.present_queue_family_index }; //if (info.graphics_queue_family_index != info.present_queue_family_index) { // // If the graphics and present queues are from different queue families, @@ -297,16 +324,18 @@ void SwapChainVkImpl::CreateVulkanSwapChain() //} const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); - auto vkDevice = pRenderDeviceVk->GetVkDevice(); + auto vkDevice = pRenderDeviceVk->GetVkDevice(); + err = vkCreateSwapchainKHR(vkDevice, &swapchain_ci, NULL, &m_VkSwapChain); CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan swapchain"); - if(oldSwapchain != VK_NULL_HANDLE) + if (oldSwapchain != VK_NULL_HANDLE) { vkDestroySwapchainKHR(vkDevice, oldSwapchain, NULL); } uint32_t swapchainImageCount = 0; + err = vkGetSwapchainImagesKHR(vkDevice, m_VkSwapChain, &swapchainImageCount, NULL); CHECK_VK_ERROR_AND_THROW(err, "Failed to request swap chain image count"); VERIFY_EXPR(swapchainImageCount > 0); @@ -319,19 +348,23 @@ void SwapChainVkImpl::CreateVulkanSwapChain() m_ImageAcquiredSemaphores.resize(swapchainImageCount); m_DrawCompleteSemaphores.resize(swapchainImageCount); m_ImageAcquiredFences.resize(swapchainImageCount); - for(uint32_t i = 0; i < swapchainImageCount; ++i) + for (uint32_t i = 0; i < swapchainImageCount; ++i) { VkSemaphoreCreateInfo SemaphoreCI = {}; + SemaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; SemaphoreCI.pNext = nullptr; SemaphoreCI.flags = 0; // reserved for future use + m_ImageAcquiredSemaphores[i] = LogicalDevice.CreateSemaphore(SemaphoreCI); m_DrawCompleteSemaphores[i] = LogicalDevice.CreateSemaphore(SemaphoreCI); + VkFenceCreateInfo FenceCI = {}; - FenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - FenceCI.pNext = nullptr; - FenceCI.flags = 0; + + FenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + FenceCI.pNext = nullptr; + FenceCI.flags = 0; m_ImageAcquiredFences[i] = LogicalDevice.CreateFence(FenceCI); } } @@ -340,7 +373,7 @@ SwapChainVkImpl::~SwapChainVkImpl() { if (m_VkSwapChain != VK_NULL_HANDLE) { - auto *pDeviceVkImpl = m_pRenderDevice.RawPtr(); + auto* pDeviceVkImpl = m_pRenderDevice.RawPtr(); pDeviceVkImpl->IdleGPU(); // We need to explicitly wait for all submitted Image Acquired Fences to signal. @@ -358,13 +391,13 @@ SwapChainVkImpl::~SwapChainVkImpl() void SwapChainVkImpl::InitBuffersAndViews() { - auto* pDeviceVkImpl = m_pRenderDevice.RawPtr(); - auto LogicalVkDevice = pDeviceVkImpl->GetVkDevice(); + auto* pDeviceVkImpl = m_pRenderDevice.RawPtr(); + auto LogicalVkDevice = pDeviceVkImpl->GetVkDevice(); #ifdef _DEBUG { uint32_t swapchainImageCount = 0; - auto err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, NULL); + auto err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, NULL); VERIFY_EXPR(err == VK_SUCCESS); VERIFY(swapchainImageCount == m_SwapChainDesc.BufferCount, "Unexpected swap chain buffer count"); } @@ -374,30 +407,30 @@ void SwapChainVkImpl::InitBuffersAndViews() m_SwapChainImagesInitialized.resize(m_pBackBufferRTV.size(), false); m_ImageAcquiredFenceSubmitted.resize(m_pBackBufferRTV.size(), false); - uint32_t swapchainImageCount = m_SwapChainDesc.BufferCount; + uint32_t swapchainImageCount = m_SwapChainDesc.BufferCount; std::vector swapchainImages(swapchainImageCount); - auto err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, swapchainImages.data()); + auto err = vkGetSwapchainImagesKHR(LogicalVkDevice, m_VkSwapChain, &swapchainImageCount, swapchainImages.data()); CHECK_VK_ERROR_AND_THROW(err, "Failed to get swap chain images"); VERIFY_EXPR(swapchainImageCount == swapchainImages.size()); - for (uint32_t i = 0; i < swapchainImageCount; i++) + for (uint32_t i = 0; i < swapchainImageCount; i++) { TextureDesc BackBufferDesc; BackBufferDesc.Format = m_SwapChainDesc.ColorBufferFormat; std::stringstream name_ss; name_ss << "Main back buffer " << i; - auto name = name_ss.str(); - BackBufferDesc.Name = name.c_str(); - BackBufferDesc.Type = RESOURCE_DIM_TEX_2D; - BackBufferDesc.Width = m_SwapChainDesc.Width; - BackBufferDesc.Height = m_SwapChainDesc.Height; - BackBufferDesc.Format = m_SwapChainDesc.ColorBufferFormat; + auto name = name_ss.str(); + BackBufferDesc.Name = name.c_str(); + BackBufferDesc.Type = RESOURCE_DIM_TEX_2D; + BackBufferDesc.Width = m_SwapChainDesc.Width; + BackBufferDesc.Height = m_SwapChainDesc.Height; + BackBufferDesc.Format = m_SwapChainDesc.ColorBufferFormat; BackBufferDesc.BindFlags = BIND_RENDER_TARGET; BackBufferDesc.MipLevels = 1; RefCntAutoPtr pBackBufferTex; m_pRenderDevice.RawPtr()->CreateTexture(BackBufferDesc, swapchainImages[i], RESOURCE_STATE_UNDEFINED, &pBackBufferTex); - + TextureViewDesc RTVDesc; RTVDesc.ViewType = TEXTURE_VIEW_RENDER_TARGET; RefCntAutoPtr pRTV; @@ -419,17 +452,17 @@ void SwapChainVkImpl::InitBuffersAndViews() DepthBufferDesc.ClearValue.Format = DepthBufferDesc.Format; DepthBufferDesc.ClearValue.DepthStencil.Depth = m_SwapChainDesc.DefaultDepthValue; DepthBufferDesc.ClearValue.DepthStencil.Stencil = m_SwapChainDesc.DefaultStencilValue; - DepthBufferDesc.Name = "Main depth buffer"; + DepthBufferDesc.Name = "Main depth buffer"; RefCntAutoPtr pDepthBufferTex; - m_pRenderDevice->CreateTexture(DepthBufferDesc, nullptr, static_cast(&pDepthBufferTex) ); - auto pDSV = pDepthBufferTex->GetDefaultView(TEXTURE_VIEW_DEPTH_STENCIL); + m_pRenderDevice->CreateTexture(DepthBufferDesc, nullptr, static_cast(&pDepthBufferTex)); + auto pDSV = pDepthBufferTex->GetDefaultView(TEXTURE_VIEW_DEPTH_STENCIL); m_pDepthBufferDSV = RefCntAutoPtr(pDSV, IID_TextureViewVk); } } VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk) { - auto* pDeviceVk = m_pRenderDevice.RawPtr(); + auto* pDeviceVk = m_pRenderDevice.RawPtr(); const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); // Applications should not rely on vkAcquireNextImageKHR blocking in order to @@ -459,15 +492,18 @@ VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk) if (LogicalDevice.GetFenceStatus(OldestSubmittedFence) == VK_NOT_READY) { auto res = LogicalDevice.WaitForFences(1, &OldestSubmittedFence, VK_TRUE, UINT64_MAX); - VERIFY_EXPR(res == VK_SUCCESS); (void)res; + VERIFY_EXPR(res == VK_SUCCESS); + (void)res; } LogicalDevice.ResetFence(OldestSubmittedFence); m_ImageAcquiredFenceSubmitted[OldestSubmittedImageFenceInd] = false; } - VkFence ImageAcquiredFence = m_ImageAcquiredFences [m_SemaphoreIndex]; + VkFence ImageAcquiredFence = m_ImageAcquiredFences[m_SemaphoreIndex]; VkSemaphore ImageAcquiredSemaphore = m_ImageAcquiredSemaphores[m_SemaphoreIndex]; + auto res = vkAcquireNextImageKHR(LogicalDevice.GetVkDevice(), m_VkSwapChain, UINT64_MAX, ImageAcquiredSemaphore, ImageAcquiredFence, &m_BackBufferIndex); + m_ImageAcquiredFenceSubmitted[m_SemaphoreIndex] = (res == VK_SUCCESS); if (res == VK_SUCCESS) { @@ -486,20 +522,20 @@ VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk) return res; } -IMPLEMENT_QUERY_INTERFACE( SwapChainVkImpl, IID_SwapChainVk, TSwapChainBase ) +IMPLEMENT_QUERY_INTERFACE(SwapChainVkImpl, IID_SwapChainVk, TSwapChainBase) void SwapChainVkImpl::Present(Uint32 SyncInterval) { auto pDeviceContext = m_wpDeviceContext.Lock(); - if( !pDeviceContext ) + if (!pDeviceContext) { - LOG_ERROR_MESSAGE( "Immediate context has been released" ); + LOG_ERROR_MESSAGE("Immediate context has been released"); return; } auto* pImmediateCtxVk = pDeviceContext.RawPtr(); - auto* pDeviceVk = m_pRenderDevice.RawPtr(); + auto* pDeviceVk = m_pRenderDevice.RawPtr(); if (!m_IsMinimized) { @@ -517,28 +553,30 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) if (!m_IsMinimized) { VkPresentInfoKHR PresentInfo = {}; - PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - PresentInfo.pNext = nullptr; + + PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + PresentInfo.pNext = nullptr; PresentInfo.waitSemaphoreCount = 1; // Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2) - VkSemaphore WaitSemaphore[] = { m_DrawCompleteSemaphores[m_SemaphoreIndex] }; + VkSemaphore WaitSemaphore[] = {m_DrawCompleteSemaphores[m_SemaphoreIndex]}; PresentInfo.pWaitSemaphores = WaitSemaphore; - PresentInfo.swapchainCount = 1; - PresentInfo.pSwapchains = &m_VkSwapChain; - PresentInfo.pImageIndices = &m_BackBufferIndex; - VkResult Result = VK_SUCCESS; - PresentInfo.pResults = &Result; - pDeviceVk->LockCmdQueueAndRun(0, - [&PresentInfo](ICommandQueueVk* pCmdQueueVk) + PresentInfo.swapchainCount = 1; + PresentInfo.pSwapchains = &m_VkSwapChain; + PresentInfo.pImageIndices = &m_BackBufferIndex; + VkResult Result = VK_SUCCESS; + PresentInfo.pResults = &Result; + pDeviceVk->LockCmdQueueAndRun( + 0, + [&PresentInfo](ICommandQueueVk* pCmdQueueVk) // { pCmdQueueVk->Present(PresentInfo); - } + } // ); if (Result == VK_SUBOPTIMAL_KHR || Result == VK_ERROR_OUT_OF_DATE_KHR) { RecreateVulkanSwapchain(pImmediateCtxVk); - m_SemaphoreIndex = m_SwapChainDesc.BufferCount-1; // To start with 0 index when acquire next image + m_SemaphoreIndex = m_SwapChainDesc.BufferCount - 1; // To start with 0 index when acquire next image } else { @@ -562,7 +600,8 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { RecreateVulkanSwapchain(pImmediateCtxVk); - m_SemaphoreIndex = m_SwapChainDesc.BufferCount-1; // To start with 0 index when acquire next image + m_SemaphoreIndex = m_SwapChainDesc.BufferCount - 1; // To start with 0 index when acquire next image + res = AcquireNextImage(pImmediateCtxVk); } DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next swap chain image"); @@ -579,7 +618,7 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval) void SwapChainVkImpl::WaitForImageAcquiredFences() { const auto& LogicalDevice = m_pRenderDevice.RawPtr()->GetLogicalDevice(); - for (size_t i=0; i < m_ImageAcquiredFences.size(); ++i) + for (size_t i = 0; i < m_ImageAcquiredFences.size(); ++i) { if (m_ImageAcquiredFenceSubmitted[i]) { @@ -593,12 +632,12 @@ void SwapChainVkImpl::WaitForImageAcquiredFences() void SwapChainVkImpl::RecreateVulkanSwapchain(DeviceContextVkImpl* pImmediateCtxVk) { std::vector pBackBufferRTVs(m_pBackBufferRTV.size()); - for(size_t i=0; i < m_pBackBufferRTV.size(); ++i) + for (size_t i = 0; i < m_pBackBufferRTV.size(); ++i) pBackBufferRTVs[i] = m_pBackBufferRTV[i]; UnbindRenderTargets(pImmediateCtxVk, pBackBufferRTVs.data(), static_cast(m_pBackBufferRTV.size()), m_pDepthBufferDSV); RenderDeviceVkImpl* pDeviceVk = m_pRenderDevice.RawPtr(); - + // This will release references to Vk swap chain buffers hold by // m_pBackBufferRTV[]. pDeviceVk->IdleGPU(); @@ -625,36 +664,37 @@ void SwapChainVkImpl::RecreateVulkanSwapchain(DeviceContextVkImpl* pImmediateCtx InitBuffersAndViews(); } -void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) +void SwapChainVkImpl::Resize(Uint32 NewWidth, Uint32 NewHeight) { - if( TSwapChainBase::Resize(NewWidth, NewHeight) ) + if (TSwapChainBase::Resize(NewWidth, NewHeight)) { auto pDeviceContext = m_wpDeviceContext.Lock(); - VERIFY( pDeviceContext, "Immediate context has been released" ); - if( pDeviceContext ) + VERIFY(pDeviceContext, "Immediate context has been released"); + if (pDeviceContext) { pDeviceContext->Flush(); try { - auto* pImmediateCtxVk = pDeviceContext.RawPtr(); + auto* pImmediateCtxVk = pDeviceContext.RawPtr(); // RecreateVulkanSwapchain() unbinds default FB bool bIsDefaultFBBound = pImmediateCtxVk->IsDefaultFBBound(); RecreateVulkanSwapchain(pImmediateCtxVk); auto res = AcquireNextImage(pImmediateCtxVk); - DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the just resized swap chain"); (void)res; + DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the just resized swap chain"); + (void)res; if (m_SwapChainDesc.IsPrimary && bIsDefaultFBBound) { // Set default render target and viewport - pDeviceContext->SetRenderTargets( 0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - pDeviceContext->SetViewports( 1, nullptr, 0, 0 ); + pDeviceContext->SetRenderTargets(0, nullptr, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + pDeviceContext->SetViewports(1, nullptr, 0, 0); } } - catch( const std::runtime_error & ) + catch (const std::runtime_error&) { - LOG_ERROR( "Failed to resize the swap chain" ); + LOG_ERROR("Failed to resize the swap chain"); } } } @@ -663,7 +703,7 @@ void SwapChainVkImpl::Resize( Uint32 NewWidth, Uint32 NewHeight ) } -void SwapChainVkImpl::SetFullscreenMode(const DisplayModeAttribs &DisplayMode) +void SwapChainVkImpl::SetFullscreenMode(const DisplayModeAttribs& DisplayMode) { } @@ -671,4 +711,4 @@ void SwapChainVkImpl::SetWindowedMode() { } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp index 701c01c9..a3c46174 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp @@ -29,12 +29,13 @@ namespace Diligent { -TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters* pRefCounters, - RenderDeviceVkImpl* pDevice, - const TextureViewDesc& ViewDesc, - ITexture* pTexture, - VulkanUtilities::ImageViewWrapper&& ImgView, - bool bIsDefaultView) : +TextureViewVkImpl::TextureViewVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDevice, + const TextureViewDesc& ViewDesc, + ITexture* pTexture, + VulkanUtilities::ImageViewWrapper&& ImgView, + bool bIsDefaultView) : + // clang-format off TTextureViewBase { pRefCounters, @@ -44,6 +45,7 @@ TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters* pRefCo bIsDefaultView }, m_ImageView{std::move(ImgView)} +// clang-format on { } @@ -51,7 +53,7 @@ TextureViewVkImpl::~TextureViewVkImpl() { if (m_MipLevelViews != nullptr) { - for (Uint32 MipView=0; MipView < m_Desc.NumMipLevels * 2; ++MipView) + for (Uint32 MipView = 0; MipView < m_Desc.NumMipLevels * 2; ++MipView) { m_MipLevelViews[MipView].~MipLevelViewAutoPtrType(); } @@ -59,11 +61,11 @@ TextureViewVkImpl::~TextureViewVkImpl() GetRawAllocator().Free(m_MipLevelViews); } - if(m_Desc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL || m_Desc.ViewType == TEXTURE_VIEW_RENDER_TARGET) + if (m_Desc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL || m_Desc.ViewType == TEXTURE_VIEW_RENDER_TARGET) m_pDevice->GetFramebufferCache().OnDestroyImageView(m_ImageView); m_pDevice->SafeReleaseDeviceObject(std::move(m_ImageView), m_pTexture->GetDesc().CommandQueueMask); } -IMPLEMENT_QUERY_INTERFACE( TextureViewVkImpl, IID_TextureViewVk, TTextureViewBase ) +IMPLEMENT_QUERY_INTERFACE(TextureViewVkImpl, IID_TextureViewVk, TTextureViewBase) -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 12deef67..13c090e0 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -35,11 +35,12 @@ namespace Diligent { -TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, - FixedBlockMemoryAllocator& TexViewObjAllocator, - RenderDeviceVkImpl* pRenderDeviceVk, - const TextureDesc& TexDesc, - const TextureData* pInitData /*= nullptr*/) : +TextureVkImpl ::TextureVkImpl(IReferenceCounters* pRefCounters, + FixedBlockMemoryAllocator& TexViewObjAllocator, + RenderDeviceVkImpl* pRenderDeviceVk, + const TextureDesc& TexDesc, + const TextureData* pInitData /*= nullptr*/) : + // clang-format off TTextureBase { pRefCounters, @@ -47,23 +48,25 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, pRenderDeviceVk, TexDesc } +// clang-format on { if (m_Desc.Usage == USAGE_STATIC && (pInitData == nullptr || pInitData->pSubResources == nullptr)) LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null"); - const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format); + const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format); const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice(); if (m_Desc.Usage == USAGE_STATIC || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC) { VkImageCreateInfo ImageCI = {}; + ImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; ImageCI.pNext = nullptr; ImageCI.flags = 0; - if(m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + if (m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) ImageCI.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - if(FmtAttribs.IsTypeless) - ImageCI.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; // Specifies that the image can be used to create a + if (FmtAttribs.IsTypeless) + ImageCI.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; // Specifies that the image can be used to create a // VkImageView with a different format from the image. if (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) @@ -94,24 +97,24 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, PrimaryViewType = TEXTURE_VIEW_SHADER_RESOURCE; InternalTexFmt = GetDefaultTextureViewFormat(m_Desc, PrimaryViewType); } - + ImageCI.format = TexFormatToVkFormat(InternalTexFmt); ImageCI.extent.width = m_Desc.Width; ImageCI.extent.height = (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) ? 1 : m_Desc.Height; ImageCI.extent.depth = (m_Desc.Type == RESOURCE_DIM_TEX_3D) ? m_Desc.Depth : 1; - + ImageCI.mipLevels = m_Desc.MipLevels; - if (m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || - m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || - m_Desc.Type == RESOURCE_DIM_TEX_CUBE || + if (m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY || + m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY || + m_Desc.Type == RESOURCE_DIM_TEX_CUBE || m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) ImageCI.arrayLayers = m_Desc.ArraySize; else ImageCI.arrayLayers = 1; ImageCI.samples = static_cast(m_Desc.SampleCount); - ImageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + ImageCI.tiling = VK_IMAGE_TILING_OPTIMAL; ImageCI.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; if (m_Desc.BindFlags & BIND_RENDER_TARGET) @@ -140,28 +143,30 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT; m_bCSBasedMipGenerationSupported = true; } - else + else { const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice(); - auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(ImageCI.format); (void)FmtProperties; + auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(ImageCI.format); + (void)FmtProperties; DEV_CHECK_ERR((FmtProperties.optimalTilingFeatures & (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT)) == (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT), - "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, " does not support blitting. " - "Automatic mipmap generation can't be done neither by CS nor by blitting."); + "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, + " does not support blitting. Automatic mipmap generation can't be done neither by CS nor by blitting."); DEV_CHECK_ERR((FmtProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) != 0, - "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, " does not support linear filtering. " - "Automatic mipmap generation can't be done neither by CS nor by blitting."); + "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, + " does not support linear filtering. Automatic mipmap generation can't be " + "done neither by CS nor by blitting."); } } - ImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ImageCI.queueFamilyIndexCount = 0; - ImageCI.pQueueFamilyIndices = nullptr; + ImageCI.pQueueFamilyIndices = nullptr; // initialLayout must be either VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED (11.4) - // If it is VK_IMAGE_LAYOUT_PREINITIALIZED, then the image data can be preinitialized by the host - // while using this layout, and the transition away from this layout will preserve that data. - // If it is VK_IMAGE_LAYOUT_UNDEFINED, then the contents of the data are considered to be undefined, + // If it is VK_IMAGE_LAYOUT_PREINITIALIZED, then the image data can be preinitialized by the host + // while using this layout, and the transition away from this layout will preserve that data. + // If it is VK_IMAGE_LAYOUT_UNDEFINED, then the contents of the data are considered to be undefined, // and the transition away from this layout is not guaranteed to preserve that data. ImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -170,27 +175,27 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, m_VulkanImage = LogicalDevice.CreateImage(ImageCI, m_Desc.Name); VkMemoryRequirements MemReqs = LogicalDevice.GetImageMemoryRequirements(m_VulkanImage); - + VkMemoryPropertyFlags ImageMemoryFlags = 0; if (m_Desc.Usage == USAGE_STAGING) ImageMemoryFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; else ImageMemoryFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - VERIFY( IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); + VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!"); m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs, ImageMemoryFlags); auto AlignedOffset = Align(m_MemoryAllocation.UnalignedOffset, MemReqs.alignment); VERIFY_EXPR(m_MemoryAllocation.Size >= MemReqs.size + (AlignedOffset - m_MemoryAllocation.UnalignedOffset)); auto Memory = m_MemoryAllocation.Page->GetVkMemory(); - auto err = LogicalDevice.BindImageMemory(m_VulkanImage, Memory, AlignedOffset); + auto err = LogicalDevice.BindImageMemory(m_VulkanImage, Memory, AlignedOffset); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind image memory"); - + // Vulkan validation layers do not like uninitialized memory, so if no initial data // is provided, we will clear the memory VulkanUtilities::CommandPoolWrapper CmdPool; - VkCommandBuffer vkCmdBuff; + VkCommandBuffer vkCmdBuff; pRenderDeviceVk->AllocateTransientCmdPool(CmdPool, vkCmdBuff, "Transient command pool to copy staging data to a device buffer"); VkImageAspectFlags aspectMask = 0; @@ -198,7 +203,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) { - if(bInitializeTexture) + if (bInitializeTexture) { UNSUPPORTED("Initializing depth-stencil texture is not currently supported"); // Only single aspect bit must be specified when copying texture data @@ -210,40 +215,41 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, // For either clear or copy command, dst layout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL VkImageSubresourceRange SubresRange; - SubresRange.aspectMask = aspectMask; - SubresRange.baseArrayLayer = 0; - SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - SubresRange.baseMipLevel = 0; - SubresRange.levelCount = VK_REMAINING_MIP_LEVELS; + SubresRange.aspectMask = aspectMask; + SubresRange.baseArrayLayer = 0; + SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + SubresRange.baseMipLevel = 0; + SubresRange.levelCount = VK_REMAINING_MIP_LEVELS; auto EnabledGraphicsShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages(); VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, ImageCI.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange, EnabledGraphicsShaderStages); SetState(RESOURCE_STATE_COPY_DEST); const auto CurrentLayout = GetLayout(); VERIFY_EXPR(CurrentLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - if(bInitializeTexture) + if (bInitializeTexture) { Uint32 ExpectedNumSubresources = ImageCI.mipLevels * ImageCI.arrayLayers; - if (pInitData->NumSubresources != ExpectedNumSubresources ) + if (pInitData->NumSubresources != ExpectedNumSubresources) LOG_ERROR_AND_THROW("Incorrect number of subresources in init data. ", ExpectedNumSubresources, " expected, while ", pInitData->NumSubresources, " provided"); std::vector Regions(pInitData->NumSubresources); Uint64 uploadBufferSize = 0; - Uint32 subres = 0; - for(Uint32 layer = 0; layer < ImageCI.arrayLayers; ++layer) + Uint32 subres = 0; + for (Uint32 layer = 0; layer < ImageCI.arrayLayers; ++layer) { - for(Uint32 mip = 0; mip < ImageCI.mipLevels; ++mip) + for (Uint32 mip = 0; mip < ImageCI.mipLevels; ++mip) { - const auto& SubResData = pInitData->pSubResources[subres]; (void)SubResData; + const auto& SubResData = pInitData->pSubResources[subres]; + (void)SubResData; auto& CopyRegion = Regions[subres]; auto MipInfo = GetMipLevelProperties(m_Desc, mip); CopyRegion.bufferOffset = uploadBufferSize; // offset in bytes from the start of the buffer object - // bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion - // of a larger two- or three-dimensional image, and control the addressing calculations of - // data in buffer memory. If either of these values is zero, that aspect of the buffer memory + // bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion + // of a larger two- or three-dimensional image, and control the addressing calculations of + // data in buffer memory. If either of these values is zero, that aspect of the buffer memory // is considered to be tightly packed according to the imageExtent. (18.4) CopyRegion.bufferRowLength = 0; CopyRegion.bufferImageHeight = 0; @@ -261,7 +267,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, VERIFY(SubResData.DepthStride == 0 || SubResData.DepthStride >= (MipInfo.StorageHeight / FmtAttribs.BlockHeight) * MipInfo.RowSize, "Depth stride is too small"); // bufferOffset must be a multiple of 4 (18.4) - // If the calling command's VkImage parameter is a compressed image, bufferOffset + // If the calling command's VkImage parameter is a compressed image, bufferOffset // must be a multiple of the compressed texel block size in bytes (18.4). This // is automatically guaranteed as MipWidth and MipHeight are rounded to block size uploadBufferSize += (MipInfo.MipSize + 3) & (~3); @@ -270,15 +276,15 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, } VERIFY_EXPR(subres == pInitData->NumSubresources); - VkBufferCreateInfo VkStaginBuffCI = {}; - VkStaginBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - VkStaginBuffCI.pNext = nullptr; - VkStaginBuffCI.flags = 0; - VkStaginBuffCI.size = uploadBufferSize; - VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VkStaginBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VkBufferCreateInfo VkStaginBuffCI = {}; + VkStaginBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + VkStaginBuffCI.pNext = nullptr; + VkStaginBuffCI.flags = 0; + VkStaginBuffCI.size = uploadBufferSize; + VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + VkStaginBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkStaginBuffCI.queueFamilyIndexCount = 0; - VkStaginBuffCI.pQueueFamilyIndices = nullptr; + VkStaginBuffCI.pQueueFamilyIndices = nullptr; std::string StagingBufferName = "Upload buffer for '"; StagingBufferName += m_Desc.Name; @@ -286,48 +292,48 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, VulkanUtilities::BufferWrapper StagingBuffer = LogicalDevice.CreateBuffer(VkStaginBuffCI, StagingBufferName.c_str()); VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(StagingBuffer); - VERIFY( IsPowerOfTwo(StagingBufferMemReqs.alignment), "Alignment is not power of 2!"); - // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges + VERIFY(IsPowerOfTwo(StagingBufferMemReqs.alignment), "Alignment is not power of 2!"); + // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible // to the host (10.2) auto StagingMemoryAllocation = pRenderDeviceVk->AllocateMemory(StagingBufferMemReqs, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - auto StagingBufferMemory = StagingMemoryAllocation.Page->GetVkMemory(); + auto StagingBufferMemory = StagingMemoryAllocation.Page->GetVkMemory(); auto AlignedStagingMemOffset = Align(StagingMemoryAllocation.UnalignedOffset, StagingBufferMemReqs.alignment); VERIFY_EXPR(StagingMemoryAllocation.Size >= StagingBufferMemReqs.size + (AlignedStagingMemOffset - StagingMemoryAllocation.UnalignedOffset)); - auto *StagingData = reinterpret_cast(StagingMemoryAllocation.Page->GetCPUMemory()); + auto* StagingData = reinterpret_cast(StagingMemoryAllocation.Page->GetCPUMemory()); VERIFY_EXPR(StagingData != nullptr); StagingData += AlignedStagingMemOffset; subres = 0; - for(Uint32 layer = 0; layer < ImageCI.arrayLayers; ++layer) + for (Uint32 layer = 0; layer < ImageCI.arrayLayers; ++layer) { - for(Uint32 mip = 0; mip < ImageCI.mipLevels; ++mip) + for (Uint32 mip = 0; mip < ImageCI.mipLevels; ++mip) { - const auto &SubResData = pInitData->pSubResources[subres]; - const auto &CopyRegion = Regions[subres]; + const auto& SubResData = pInitData->pSubResources[subres]; + const auto& CopyRegion = Regions[subres]; auto MipInfo = GetMipLevelProperties(m_Desc, mip); - VERIFY_EXPR(MipInfo.LogicalWidth == CopyRegion.imageExtent.width); + VERIFY_EXPR(MipInfo.LogicalWidth == CopyRegion.imageExtent.width); VERIFY_EXPR(MipInfo.LogicalHeight == CopyRegion.imageExtent.height); - VERIFY_EXPR(MipInfo.Depth == CopyRegion.imageExtent.depth); + VERIFY_EXPR(MipInfo.Depth == CopyRegion.imageExtent.depth); VERIFY(SubResData.Stride == 0 || SubResData.Stride >= MipInfo.RowSize, "Stride is too small"); // For compressed-block formats, MipInfo.RowSize is the size of one row of blocks VERIFY(SubResData.DepthStride == 0 || SubResData.DepthStride >= (MipInfo.StorageHeight / FmtAttribs.BlockHeight) * MipInfo.RowSize, "Depth stride is too small"); - for(Uint32 z=0; z < MipInfo.Depth; ++z) + for (Uint32 z = 0; z < MipInfo.Depth; ++z) { - for(Uint32 y=0; y < MipInfo.StorageHeight; y += FmtAttribs.BlockHeight) + for (Uint32 y = 0; y < MipInfo.StorageHeight; y += FmtAttribs.BlockHeight) { memcpy(StagingData + CopyRegion.bufferOffset + ((y + z * MipInfo.StorageHeight) / FmtAttribs.BlockHeight) * MipInfo.RowSize, // SubResData.Stride must be the stride of one row of compressed blocks - reinterpret_cast(SubResData.pData) + (y/FmtAttribs.BlockHeight) * SubResData.Stride + z * SubResData.DepthStride, + reinterpret_cast(SubResData.pData) + (y / FmtAttribs.BlockHeight) * SubResData.Stride + z * SubResData.DepthStride, MipInfo.RowSize); } } - + ++subres; } } @@ -341,16 +347,16 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, // Copy commands MUST be recorded outside of a render pass instance. This is OK here // as copy will be the only command in the cmd buffer vkCmdCopyBufferToImage(vkCmdBuff, StagingBuffer, m_VulkanImage, - CurrentLayout, // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) - static_cast(Regions.size()), Regions.data()); + CurrentLayout, // dstImageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) + static_cast(Regions.size()), Regions.data()); Uint32 QueueIndex = 0; - pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool)); + pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool)); // After command buffer is submitted, safe-release resources. This strategy // is little overconservative as the resources will be released after the first // command buffer submitted through the immediate context will be completed - pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingBuffer), Uint64{1} << Uint64{QueueIndex}); + pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingBuffer), Uint64{1} << Uint64{QueueIndex}); pRenderDeviceVk->SafeReleaseDeviceObject(std::move(StagingMemoryAllocation), Uint64{1} << Uint64{QueueIndex}); } else @@ -361,23 +367,23 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, Subresource.levelCount = VK_REMAINING_MIP_LEVELS; Subresource.baseArrayLayer = 0; Subresource.layerCount = VK_REMAINING_ARRAY_LAYERS; - if(aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) + if (aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { - if(FmtAttribs.ComponentType != COMPONENT_TYPE_COMPRESSED) + if (FmtAttribs.ComponentType != COMPONENT_TYPE_COMPRESSED) { VkClearColorValue ClearColor = {}; vkCmdClearColorImage(vkCmdBuff, m_VulkanImage, - CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - &ClearColor, 1, &Subresource); + CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + &ClearColor, 1, &Subresource); } } - else if(aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT || - aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) ) + else if (aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT || + aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { VkClearDepthStencilValue ClearValue = {}; vkCmdClearDepthStencilImage(vkCmdBuff, m_VulkanImage, - CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL - &ClearValue, 1, &Subresource); + CurrentLayout, // must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + &ClearValue, 1, &Subresource); } else { @@ -387,36 +393,39 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool)); } } - else if(m_Desc.Usage == USAGE_STAGING) + else if (m_Desc.Usage == USAGE_STAGING) { VkBufferCreateInfo VkStaginBuffCI = {}; + VkStaginBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; VkStaginBuffCI.pNext = nullptr; VkStaginBuffCI.flags = 0; VkStaginBuffCI.size = GetStagingDataOffset(m_Desc, m_Desc.ArraySize, 0); - DEV_CHECK_ERR( (m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_READ || - (m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_WRITE, + // clang-format off + DEV_CHECK_ERR((m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_READ || + (m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_WRITE, "Exactly one of CPU_ACCESS_READ or CPU_ACCESS_WRITE flags must be specified"); + // clang-format on VkMemoryPropertyFlags MemProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; if (m_Desc.CPUAccessFlags & CPU_ACCESS_READ) { VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; - MemProperties |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + MemProperties |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; SetState(RESOURCE_STATE_COPY_DEST); } else if (m_Desc.CPUAccessFlags & CPU_ACCESS_WRITE) { VkStaginBuffCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges + // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible // to the host (10.2) - MemProperties |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + MemProperties |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; SetState(RESOURCE_STATE_COPY_SOURCE); } else UNEXPECTED("Unexpected CPU access"); - + VkStaginBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkStaginBuffCI.queueFamilyIndexCount = 0; VkStaginBuffCI.pQueueFamilyIndices = nullptr; @@ -427,16 +436,16 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, m_StagingBuffer = LogicalDevice.CreateBuffer(VkStaginBuffCI, StagingBufferName.c_str()); VkMemoryRequirements StagingBufferMemReqs = LogicalDevice.GetBufferMemoryRequirements(m_StagingBuffer); - VERIFY( IsPowerOfTwo(StagingBufferMemReqs.alignment), "Alignment is not power of 2!"); + VERIFY(IsPowerOfTwo(StagingBufferMemReqs.alignment), "Alignment is not power of 2!"); - m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(StagingBufferMemReqs, MemProperties); - auto StagingBufferMemory = m_MemoryAllocation.Page->GetVkMemory(); + m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(StagingBufferMemReqs, MemProperties); + auto StagingBufferMemory = m_MemoryAllocation.Page->GetVkMemory(); auto AlignedStagingMemOffset = Align(m_MemoryAllocation.UnalignedOffset, StagingBufferMemReqs.alignment); VERIFY_EXPR(m_MemoryAllocation.Size >= StagingBufferMemReqs.size + (AlignedStagingMemOffset - m_MemoryAllocation.UnalignedOffset)); auto err = LogicalDevice.BindBufferMemory(m_StagingBuffer, StagingBufferMemory, AlignedStagingMemOffset); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind staging bufer memory"); - + m_StagingDataAlignedOffset = AlignedStagingMemOffset; } else @@ -459,16 +468,16 @@ Uint32 GetStagingDataOffset(const TextureDesc& TexDesc, Uint32 ArraySlice, Uint3 { auto MipInfo = GetMipLevelProperties(TexDesc, mip); // bufferOffset must be a multiple of 4 (18.4) - // If the calling command's VkImage parameter is a compressed image, bufferOffset + // If the calling command's VkImage parameter is a compressed image, bufferOffset // must be a multiple of the compressed texel block size in bytes (18.4). This // is automatically guaranteed as MipWidth and MipHeight are rounded to block size ArraySliceSize += (MipInfo.MipSize + 3) & (~3); } Offset = ArraySliceSize; - if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE || + if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE || TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) Offset *= TexDesc.ArraySize; } @@ -483,67 +492,65 @@ Uint32 GetStagingDataOffset(const TextureDesc& TexDesc, Uint32 ArraySlice, Uint3 return Offset; } -TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, - FixedBlockMemoryAllocator& TexViewObjAllocator, - RenderDeviceVkImpl* pDeviceVk, - const TextureDesc& TexDesc, - RESOURCE_STATE InitialState, - VkImage VkImageHandle) : - TTextureBase(pRefCounters, TexViewObjAllocator, pDeviceVk, TexDesc), - m_VulkanImage(VkImageHandle) +TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, + FixedBlockMemoryAllocator& TexViewObjAllocator, + RenderDeviceVkImpl* pDeviceVk, + const TextureDesc& TexDesc, + RESOURCE_STATE InitialState, + VkImage VkImageHandle) : + TTextureBase{pRefCounters, TexViewObjAllocator, pDeviceVk, TexDesc}, + m_VulkanImage{VkImageHandle} { SetState(InitialState); } -IMPLEMENT_QUERY_INTERFACE( TextureVkImpl, IID_TextureVk, TTextureBase ) +IMPLEMENT_QUERY_INTERFACE(TextureVkImpl, IID_TextureVk, TTextureBase) void TextureVkImpl::CreateViewInternal(const 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" ); - + 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; try { auto& TexViewAllocator = m_pDevice->GetTexViewObjAllocator(); - VERIFY( &TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization" ); + VERIFY(&TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization"); auto UpdatedViewDesc = ViewDesc; - CorrectTextureViewDesc( UpdatedViewDesc ); + CorrectTextureViewDesc(UpdatedViewDesc); VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(UpdatedViewDesc); - auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr) - (GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView); - VERIFY( pViewVk->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type" ); + auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr)(GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView); + VERIFY(pViewVk->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type"); if (bIsDefaultView) *ppView = pViewVk; else - pViewVk->QueryInterface(IID_TextureView, reinterpret_cast(ppView) ); + pViewVk->QueryInterface(IID_TextureView, reinterpret_cast(ppView)); - if ((UpdatedViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0 && + if ((UpdatedViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0 && m_bCSBasedMipGenerationSupported && CheckCSBasedMipGenerationSupport(TexFormatToVkFormat(pViewVk->GetDesc().Format))) { auto* pMipLevelViews = ALLOCATE(GetRawAllocator(), "Raw memory for mip level views", TextureViewVkImpl::MipLevelViewAutoPtrType, UpdatedViewDesc.NumMipLevels * 2); for (Uint32 MipLevel = 0; MipLevel < UpdatedViewDesc.NumMipLevels; ++MipLevel) { - auto CreateMipLevelView = [&](TEXTURE_VIEW_TYPE ViewType, Uint32 MipLevel, TextureViewVkImpl::MipLevelViewAutoPtrType* ppMipLevelView) - { + auto CreateMipLevelView = [&](TEXTURE_VIEW_TYPE ViewType, Uint32 MipLevel, TextureViewVkImpl::MipLevelViewAutoPtrType* ppMipLevelView) { TextureViewDesc MipLevelViewDesc = pViewVk->GetDesc(); // Always create texture array views std::stringstream name_ss; - name_ss << "Internal " << (ViewType == TEXTURE_VIEW_SHADER_RESOURCE ? "SRV" : "UAV") + name_ss << "Internal " << (ViewType == TEXTURE_VIEW_SHADER_RESOURCE ? "SRV" : "UAV") << " of mip level " << MipLevel << " of texture view '" << pViewVk->GetDesc().Name << "'"; - auto name = name_ss.str(); - MipLevelViewDesc.Name = name.c_str(); - MipLevelViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; - MipLevelViewDesc.ViewType = ViewType; + auto name = name_ss.str(); + MipLevelViewDesc.Name = name.c_str(); + MipLevelViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; + MipLevelViewDesc.ViewType = ViewType; MipLevelViewDesc.MostDetailedMip += MipLevel; - MipLevelViewDesc.NumMipLevels = 1; + MipLevelViewDesc.NumMipLevels = 1; if (ViewType == TEXTURE_VIEW_UNORDERED_ACCESS) { @@ -553,12 +560,11 @@ void TextureVkImpl::CreateViewInternal(const TextureViewDesc& ViewDesc, ITexture VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(MipLevelViewDesc); // Attach to parent view - auto pMipLevelViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, pViewVk) - (GetDevice(), MipLevelViewDesc, this, std::move(ImgView), bIsDefaultView); + auto pMipLevelViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, pViewVk)(GetDevice(), MipLevelViewDesc, this, std::move(ImgView), bIsDefaultView); new (ppMipLevelView) TextureViewVkImpl::MipLevelViewAutoPtrType(pMipLevelViewVk, STDDeleter(TexViewAllocator)); }; - CreateMipLevelView(TEXTURE_VIEW_SHADER_RESOURCE, MipLevel, &pMipLevelViews[MipLevel * 2]); + CreateMipLevelView(TEXTURE_VIEW_SHADER_RESOURCE, MipLevel, &pMipLevelViews[MipLevel * 2]); CreateMipLevelView(TEXTURE_VIEW_UNORDERED_ACCESS, MipLevel, &pMipLevelViews[MipLevel * 2 + 1]); } @@ -571,19 +577,19 @@ void TextureVkImpl::CreateViewInternal(const TextureViewDesc& ViewDesc, ITexture pViewVk->AssignMipLevelViews(pMipLevelViews); } } - catch( const std::runtime_error & ) + 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 : "", "\"" ); + 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 : "", "\""); } } -TextureVkImpl :: ~TextureVkImpl() +TextureVkImpl ::~TextureVkImpl() { // Vk object can only be destroyed when it is no longer used by the GPU // Wrappers for external texture will not be destroyed as they are created with null device pointer if (m_VulkanImage) - m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanImage), m_Desc.CommandQueueMask); + m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanImage), m_Desc.CommandQueueMask); if (m_StagingBuffer) m_pDevice->SafeReleaseDeviceObject(std::move(m_StagingBuffer), m_Desc.CommandQueueMask); m_pDevice->SafeReleaseDeviceObject(std::move(m_MemoryAllocation), m_Desc.CommandQueueMask); @@ -591,83 +597,88 @@ TextureVkImpl :: ~TextureVkImpl() VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc& ViewDesc) { + // clang-format off VERIFY(ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE || ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET || ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL || - ViewDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, "Unexpected view type"); + ViewDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, + "Unexpected view type"); + // clang-format on if (ViewDesc.Format == TEX_FORMAT_UNKNOWN) { ViewDesc.Format = m_Desc.Format; } VkImageViewCreateInfo ImageViewCI = {}; + ImageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; ImageViewCI.pNext = nullptr; ImageViewCI.flags = 0; // reserved for future use. ImageViewCI.image = m_VulkanImage; - switch(ViewDesc.TextureDim) + switch (ViewDesc.TextureDim) { case RESOURCE_DIM_TEX_1D: ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_1D; - break; + break; case RESOURCE_DIM_TEX_1D_ARRAY: ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY; - break; + break; case RESOURCE_DIM_TEX_2D: ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; - break; + break; case RESOURCE_DIM_TEX_2D_ARRAY: ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - break; + break; case RESOURCE_DIM_TEX_3D: if (ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET || ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL) { - ViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; + ViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY; ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; } else { ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_3D; - Uint32 MipDepth = std::max(Uint32{m_Desc.Depth} >> Uint32{ViewDesc.MostDetailedMip}, 1U); + Uint32 MipDepth = std::max(Uint32{m_Desc.Depth} >> Uint32{ViewDesc.MostDetailedMip}, 1U); if (ViewDesc.FirstDepthSlice != 0 || ViewDesc.NumDepthSlices != MipDepth) { LOG_ERROR("3D texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' (most detailed mip: ", Uint32{ViewDesc.MostDetailedMip}, "; mip levels: ", Uint32{ViewDesc.NumMipLevels}, "; first slice: ", ViewDesc.FirstDepthSlice, - "; num depth slices: ", ViewDesc.NumDepthSlices, ") of texture '", m_Desc.Name, "' does not references" - " all depth slices (", MipDepth, ") in the mip level. 3D texture views in Vulkan must address all depth slices." ); + "; num depth slices: ", ViewDesc.NumDepthSlices, ") of texture '", m_Desc.Name, + "' does not references all depth slices (", MipDepth, + ") in the mip level. 3D texture views in Vulkan must address all depth slices."); ViewDesc.FirstDepthSlice = 0; ViewDesc.NumDepthSlices = MipDepth; } } - break; + break; case RESOURCE_DIM_TEX_CUBE: ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - break; + break; case RESOURCE_DIM_TEX_CUBE_ARRAY: ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - break; + break; default: UNEXPECTED("Unexpcted view dimension"); } - + TEXTURE_FORMAT CorrectedViewFormat = ViewDesc.Format; if (m_Desc.BindFlags & BIND_DEPTH_STENCIL) CorrectedViewFormat = GetDefaultTextureViewFormat(CorrectedViewFormat, TEXTURE_VIEW_DEPTH_STENCIL, m_Desc.BindFlags); - ImageViewCI.format = TexFormatToVkFormat(CorrectedViewFormat); - ImageViewCI.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; - ImageViewCI.subresourceRange.baseMipLevel = ViewDesc.MostDetailedMip; - ImageViewCI.subresourceRange.levelCount = ViewDesc.NumMipLevels; - if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D_ARRAY || + ImageViewCI.format = TexFormatToVkFormat(CorrectedViewFormat); + ImageViewCI.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; + ImageViewCI.subresourceRange.baseMipLevel = ViewDesc.MostDetailedMip; + ImageViewCI.subresourceRange.levelCount = ViewDesc.NumMipLevels; + if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D_ARRAY || ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D_ARRAY || - ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE || - ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY ) + ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE || + ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY) { ImageViewCI.subresourceRange.baseArrayLayer = ViewDesc.FirstArraySlice; ImageViewCI.subresourceRange.layerCount = ViewDesc.NumArraySlices; @@ -678,11 +689,11 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc ImageViewCI.subresourceRange.layerCount = 1; } - const auto &FmtAttribs = GetTextureFormatAttribs(CorrectedViewFormat); + const auto& FmtAttribs = GetTextureFormatAttribs(CorrectedViewFormat); - if(ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL) + if (ViewDesc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL) { - // When an imageView of a depth/stencil image is used as a depth/stencil framebuffer attachment, + // When an imageView of a depth/stencil image is used as a depth/stencil framebuffer attachment, // the aspectMask is ignored and both depth and stencil image subresources are used. (11.5) if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) ImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; @@ -693,16 +704,16 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc } else { - // aspectMask must be only VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT + // aspectMask must be only VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT // if format is a color, depth-only or stencil-only format, respectively. (11.5) - if(FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH ) + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) { ImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) { - if(ViewDesc.Format == TEX_FORMAT_D32_FLOAT_S8X24_UINT || - ViewDesc.Format == TEX_FORMAT_D24_UNORM_S8_UINT) + if (ViewDesc.Format == TEX_FORMAT_D32_FLOAT_S8X24_UINT || + ViewDesc.Format == TEX_FORMAT_D24_UNORM_S8_UINT) { ImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; } @@ -711,7 +722,7 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc { ImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } - else if (ViewDesc.Format == TEX_FORMAT_X32_TYPELESS_G8X24_UINT || + else if (ViewDesc.Format == TEX_FORMAT_X32_TYPELESS_G8X24_UINT || ViewDesc.Format == TEX_FORMAT_X24_TYPELESS_G8_UINT) { ImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; @@ -722,7 +733,7 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc else ImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } - + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); std::string ViewName = "Image view for \'"; @@ -731,13 +742,13 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc return LogicalDevice.CreateImageView(ImageViewCI, ViewName.c_str()); } -bool TextureVkImpl::CheckCSBasedMipGenerationSupport(VkFormat vkFmt)const +bool TextureVkImpl::CheckCSBasedMipGenerationSupport(VkFormat vkFmt) const { VERIFY_EXPR(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS); if (m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY) { const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice(); - auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(vkFmt); + auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(vkFmt); if ((FmtProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0) { return true; @@ -752,7 +763,7 @@ void TextureVkImpl::SetLayout(VkImageLayout Layout) SetState(VkImageLayoutToResourceState(Layout)); } -VkImageLayout TextureVkImpl::GetLayout()const +VkImageLayout TextureVkImpl::GetLayout() const { return ResourceStateToVkImageLayout(GetState()); } @@ -760,14 +771,18 @@ VkImageLayout TextureVkImpl::GetLayout()const void TextureVkImpl::InvalidateStagingRange(VkDeviceSize Offset, VkDeviceSize Size) { const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + VkMappedMemoryRange InvalidateRange = {}; + InvalidateRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; InvalidateRange.pNext = nullptr; InvalidateRange.memory = m_MemoryAllocation.Page->GetVkMemory(); InvalidateRange.offset = m_StagingDataAlignedOffset + Offset; InvalidateRange.size = Size; + auto err = LogicalDevice.InvalidateMappedMemoryRanges(1, &InvalidateRange); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to invalidated mapped texture memory range"); (void)err; + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to invalidated mapped texture memory range"); + (void)err; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp index 5475f128..7497373e 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp @@ -32,49 +32,53 @@ namespace Diligent static VkDeviceSize GetDefaultAlignment(const VulkanUtilities::VulkanPhysicalDevice& PhysicalDevice) { - const auto& Props = PhysicalDevice.GetProperties(); + const auto& Props = PhysicalDevice.GetProperties(); const auto& Limits = Props.limits; return std::max(std::max(Limits.minUniformBufferOffsetAlignment, Limits.minTexelBufferOffsetAlignment), Limits.minStorageBufferOffsetAlignment); } -VulkanDynamicMemoryManager::VulkanDynamicMemoryManager(IMemoryAllocator& Allocator, - RenderDeviceVkImpl& DeviceVk, +VulkanDynamicMemoryManager::VulkanDynamicMemoryManager(IMemoryAllocator& Allocator, + RenderDeviceVkImpl& DeviceVk, Uint32 Size, Uint64 CommandQueueMask) : + // clang-format off TBase {Allocator, Size}, m_DeviceVk {DeviceVk}, m_DefaultAlignment{GetDefaultAlignment(DeviceVk.GetPhysicalDevice())}, m_CommandQueueMask{CommandQueueMask} +// clang-format on { - VERIFY( (Size & (MasterBlockAlignment-1)) == 0, "Heap size (", Size, " is not aligned by the master block alignment (", Uint32{MasterBlockAlignment}, ")"); + VERIFY((Size & (MasterBlockAlignment - 1)) == 0, "Heap size (", Size, " is not aligned by the master block alignment (", Uint32{MasterBlockAlignment}, ")"); VkBufferCreateInfo VkBuffCI = {}; + VkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; VkBuffCI.pNext = nullptr; VkBuffCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT - VkBuffCI.size = Size; - VkBuffCI.usage = - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VkBuffCI.size = Size; + VkBuffCI.usage = + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkBuffCI.queueFamilyIndexCount = 0; - VkBuffCI.pQueueFamilyIndices = nullptr; + VkBuffCI.pQueueFamilyIndices = nullptr; - const auto& LogicalDevice = DeviceVk.GetLogicalDevice(); - m_VkBuffer = LogicalDevice.CreateBuffer(VkBuffCI, "Dynamic heap buffer"); + const auto& LogicalDevice = DeviceVk.GetLogicalDevice(); + m_VkBuffer = LogicalDevice.CreateBuffer(VkBuffCI, "Dynamic heap buffer"); VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VkBuffer); const auto& PhysicalDevice = DeviceVk.GetPhysicalDevice(); VkMemoryAllocateInfo MemAlloc = {}; - MemAlloc.pNext = nullptr; - MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + + MemAlloc.pNext = nullptr; + MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; MemAlloc.allocationSize = MemReqs.size; - // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges + // VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the host cache management commands vkFlushMappedMemoryRanges // and vkInvalidateMappedMemoryRanges are NOT needed to flush host writes to the device or make device writes visible // to the host (10.2) MemAlloc.memoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); @@ -87,8 +91,10 @@ VulkanDynamicMemoryManager::VulkanDynamicMemoryManager(IMemoryAllocator& Alloc m_BufferMemory = LogicalDevice.AllocateDeviceMemory(MemAlloc, "Host-visible memory for upload buffer"); - void *Data = nullptr; - auto err = LogicalDevice.MapMemory(m_BufferMemory, + void* Data = nullptr; + + auto err = LogicalDevice.MapMemory( + m_BufferMemory, 0, // offset MemAlloc.allocationSize, 0, // flags, reserved for future use @@ -99,7 +105,7 @@ VulkanDynamicMemoryManager::VulkanDynamicMemoryManager(IMemoryAllocator& Alloc err = LogicalDevice.BindBufferMemory(m_VkBuffer, m_BufferMemory, 0 /*offset*/); CHECK_VK_ERROR_AND_THROW(err, "Failed to bind bufer memory"); - LOG_INFO_MESSAGE("GPU dynamic heap created. Total buffer size: ", FormatMemorySize(Size, 2) ); + LOG_INFO_MESSAGE("GPU dynamic heap created. Total buffer size: ", FormatMemorySize(Size, 2)); } void VulkanDynamicMemoryManager::Destroy() @@ -107,7 +113,7 @@ void VulkanDynamicMemoryManager::Destroy() if (m_VkBuffer) { m_DeviceVk.GetLogicalDevice().UnmapMemory(m_BufferMemory); - m_DeviceVk.SafeReleaseDeviceObject(std::move(m_VkBuffer), m_CommandQueueMask); + m_DeviceVk.SafeReleaseDeviceObject(std::move(m_VkBuffer), m_CommandQueueMask); m_DeviceVk.SafeReleaseDeviceObject(std::move(m_BufferMemory), m_CommandQueueMask); } m_CPUAddress = nullptr; @@ -118,9 +124,11 @@ VulkanDynamicMemoryManager::~VulkanDynamicMemoryManager() VERIFY(m_BufferMemory == VK_NULL_HANDLE && m_VkBuffer == VK_NULL_HANDLE, "Vulkan resources must be explcitly released with Destroy()"); auto Size = GetSize(); LOG_INFO_MESSAGE("Dynamic memory manager usage stats:\n" - " Total size: ", FormatMemorySize(Size, 2), + " Total size: ", + FormatMemorySize(Size, 2), ". Peak allocated size: ", FormatMemorySize(m_TotalPeakSize, 2, Size), - ". Peak utilization: ", std::fixed, std::setprecision(1), static_cast(m_TotalPeakSize) / static_cast(std::max(Size, size_t{1})) * 100.0, '%' ); + ". Peak utilization: ", + std::fixed, std::setprecision(1), static_cast(m_TotalPeakSize) / static_cast(std::max(Size, size_t{1})) * 100.0, '%'); } @@ -128,10 +136,12 @@ VulkanDynamicMemoryManager::MasterBlock VulkanDynamicMemoryManager::AllocateMast { if (Alignment == 0) Alignment = MasterBlockAlignment; - + if (SizeInBytes > GetSize()) { - LOG_ERROR("Requested dynamic allocation size ", SizeInBytes, " exceeds maximum dynamic memory size ", GetSize(), ". The app should increase dynamic heap size."); + LOG_ERROR("Requested dynamic allocation size ", SizeInBytes, + " exceeds maximum dynamic memory size ", GetSize(), + ". The app should increase dynamic heap size."); return MasterBlock{}; } @@ -139,11 +149,11 @@ VulkanDynamicMemoryManager::MasterBlock VulkanDynamicMemoryManager::AllocateMast if (!Block.IsValid()) { // Allocation failed. Try to wait for GPU to finish pending frames to release some space - auto StartIdleTime = std::chrono::high_resolution_clock::now(); - static constexpr const auto SleepPeriod = std::chrono::milliseconds(1); - static constexpr const auto MaxIdleDuration = std::chrono::duration{60.0 / 1000.0}; // 60 ms + auto StartIdleTime = std::chrono::high_resolution_clock::now(); + static constexpr const auto SleepPeriod = std::chrono::milliseconds(1); + static constexpr const auto MaxIdleDuration = std::chrono::duration{60.0 / 1000.0}; // 60 ms std::chrono::duration IdleDuration; - Uint32 SleepIterations = 0; + Uint32 SleepIterations = 0; while (!Block.IsValid() && IdleDuration < MaxIdleDuration) { m_DeviceVk.PurgeReleaseQueues(); @@ -155,7 +165,7 @@ VulkanDynamicMemoryManager::MasterBlock VulkanDynamicMemoryManager::AllocateMast } auto CurrTime = std::chrono::high_resolution_clock::now(); - IdleDuration = std::chrono::duration_cast>(CurrTime - StartIdleTime); + IdleDuration = std::chrono::duration_cast>(CurrTime - StartIdleTime); } if (!Block.IsValid()) @@ -165,22 +175,32 @@ VulkanDynamicMemoryManager::MasterBlock VulkanDynamicMemoryManager::AllocateMast Block = TBase::AllocateMasterBlock(SizeInBytes, Alignment); if (!Block.IsValid()) { - LOG_ERROR_MESSAGE("Space in dynamic heap is exausted! After idling for ", std::fixed, std::setprecision(1), IdleDuration.count()*1000.0, " ms still no space is available. Increase the size of the heap by setting EngineVkCreateInfo::DynamicHeapSize to a greater value or optimize dynamic resource usage"); + LOG_ERROR_MESSAGE("Space in dynamic heap is exausted! After idling for ", + std::fixed, std::setprecision(1), IdleDuration.count() * 1000.0, + " ms still no space is available. Increase the size of the heap by setting " + "EngineVkCreateInfo::DynamicHeapSize to a greater value or optimize dynamic resource usage"); } else { - LOG_WARNING_MESSAGE("Space in dynamic heap is almost exausted. Allocation forced idling the GPU. Increase the size of the heap by setting EngineVkCreateInfo::DynamicHeapSize to a greater value or optimize dynamic resource usage"); + LOG_WARNING_MESSAGE("Space in dynamic heap is almost exausted. Allocation forced idling the GPU. " + "Increase the size of the heap by setting EngineVkCreateInfo::DynamicHeapSize to a " + "greater value or optimize dynamic resource usage"); } } else { - if(SleepIterations == 0) + if (SleepIterations == 0) { - LOG_WARNING_MESSAGE("Space in dynamic heap is almost exausted forcing mid-frame shrinkage. Increase the size of the heap buffer by setting EngineVkCreateInfo::DynamicHeapSize to a greater value or optimize dynamic resource usage"); + LOG_WARNING_MESSAGE("Space in dynamic heap is almost exausted forcing mid-frame shrinkage. " + "Increase the size of the heap buffer by setting EngineVkCreateInfo::DynamicHeapSize to a " + "greater value or optimize dynamic resource usage"); } else { - LOG_WARNING_MESSAGE("Space in dynamic heap is almost exausted. Allocation forced wait time of ", std::fixed, std::setprecision(1), IdleDuration.count()*1000.0, " ms. Increase the size of the heap by setting EngineVkCreateInfo::DynamicHeapSize to a greater value or optimize dynamic resource usage"); + LOG_WARNING_MESSAGE("Space in dynamic heap is almost exausted. Allocation forced wait time of ", + std::fixed, std::setprecision(1), IdleDuration.count() * 1000.0, + " ms. Increase the size of the heap by setting EngineVkCreateInfo::DynamicHeapSize " + "to a greater value or optimize dynamic resource usage"); } } } @@ -199,9 +219,9 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A VERIFY_EXPR(Alignment > 0); VERIFY(IsPowerOfTwo(Alignment), "Alignment (", Alignment, ") must be power of 2"); - auto AlignedOffset = InvalidOffset; - OffsetType AlignedSize = 0; - if(SizeInBytes > m_MasterBlockSize/2) + auto AlignedOffset = InvalidOffset; + OffsetType AlignedSize = 0; + if (SizeInBytes > m_MasterBlockSize / 2) { // Allocate directly from the memory manager auto MasterBlock = m_GlobalDynamicMemMgr.AllocateMasterBlock(SizeInBytes, Alignment); @@ -221,9 +241,9 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A auto MasterBlock = m_GlobalDynamicMemMgr.AllocateMasterBlock(m_MasterBlockSize, 0); if (MasterBlock.IsValid()) { - m_CurrOffset = MasterBlock.UnalignedOffset; + m_CurrOffset = MasterBlock.UnalignedOffset; m_CurrAllocatedSize += static_cast(MasterBlock.Size); - m_AvailableSize = static_cast(MasterBlock.Size); + m_AvailableSize = static_cast(MasterBlock.Size); m_MasterBlocks.emplace_back(MasterBlock); } } @@ -231,11 +251,11 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A if (m_CurrOffset != InvalidOffset) { AlignedOffset = Align(m_CurrOffset, size_t{Alignment}); - AlignedSize = SizeInBytes + (AlignedOffset - m_CurrOffset); + AlignedSize = SizeInBytes + (AlignedOffset - m_CurrOffset); if (AlignedSize <= m_AvailableSize) { m_AvailableSize -= static_cast(AlignedSize); - m_CurrOffset += static_cast(AlignedSize); + m_CurrOffset += static_cast(AlignedSize); } else AlignedOffset = InvalidOffset; @@ -243,16 +263,16 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A } // Every device context uses its own dynamic heap, so there is no need to lock - if(AlignedOffset != InvalidOffset) + if (AlignedOffset != InvalidOffset) { m_CurrAlignedSize += static_cast(AlignedSize); - m_CurrUsedSize += SizeInBytes; - m_PeakAlignedSize = std::max(m_PeakAlignedSize, m_CurrAlignedSize); - m_PeakUsedSize = std::max(m_PeakUsedSize, m_CurrUsedSize); - m_PeakAllocatedSize = std::max(m_PeakAllocatedSize, m_CurrAllocatedSize); - - VERIFY_EXPR((AlignedOffset & (Alignment-1)) == 0); - return VulkanDynamicAllocation{ m_GlobalDynamicMemMgr, AlignedOffset, SizeInBytes }; + m_CurrUsedSize += SizeInBytes; + m_PeakAlignedSize = std::max(m_PeakAlignedSize, m_CurrAlignedSize); + m_PeakUsedSize = std::max(m_PeakUsedSize, m_CurrUsedSize); + m_PeakAllocatedSize = std::max(m_PeakAllocatedSize, m_CurrAllocatedSize); + + VERIFY_EXPR((AlignedOffset & (Alignment - 1)) == 0); + return VulkanDynamicAllocation{m_GlobalDynamicMemMgr, AlignedOffset, SizeInBytes}; } else return VulkanDynamicAllocation{}; @@ -263,12 +283,12 @@ void VulkanDynamicHeap::ReleaseMasterBlocks(RenderDeviceVkImpl& DeviceVkImpl, Ui m_GlobalDynamicMemMgr.ReleaseMasterBlocks(m_MasterBlocks, DeviceVkImpl, CmdQueueMask); m_MasterBlocks.clear(); - m_CurrOffset = InvalidOffset; - m_AvailableSize = 0; + m_CurrOffset = InvalidOffset; + m_AvailableSize = 0; - m_CurrUsedSize = 0; - m_CurrAlignedSize = 0; - m_CurrAllocatedSize = 0; + m_CurrUsedSize = 0; + m_CurrAlignedSize = 0; + m_CurrAllocatedSize = 0; } VulkanDynamicHeap::~VulkanDynamicHeap() @@ -276,14 +296,15 @@ VulkanDynamicHeap::~VulkanDynamicHeap() DEV_CHECK_ERR(m_MasterBlocks.empty(), m_MasterBlocks.size(), " master block(s) have not been returned to dynamic memory manager"); auto PeakAllocatedPages = m_PeakAllocatedSize / m_MasterBlockSize; - LOG_INFO_MESSAGE(m_HeapName, " usage stats:\n" - " Peak used/aligned/allocated size: ", FormatMemorySize(m_PeakUsedSize, 2, m_PeakAllocatedSize), " / ", - FormatMemorySize(m_PeakAlignedSize, 2, m_PeakAllocatedSize), " / ", - FormatMemorySize(m_PeakAllocatedSize, 2, m_PeakAllocatedSize), - " (", PeakAllocatedPages, (PeakAllocatedPages == 1 ? " page)" : " pages)"), - ". Peak efficiency (used/aligned): ", std::fixed, std::setprecision(1), static_cast(m_PeakUsedSize) / static_cast(std::max(m_PeakAlignedSize, 1U)) * 100.0, '%', - ". Peak utilization (used/allocated): ", std::fixed, std::setprecision(1), static_cast(m_PeakUsedSize) / static_cast(std::max(m_PeakAllocatedSize, 1U)) * 100.0, '%' - ); + LOG_INFO_MESSAGE(m_HeapName, + " usage stats:\n" + " Peak used/aligned/allocated size: ", + FormatMemorySize(m_PeakUsedSize, 2, m_PeakAllocatedSize), " / ", + FormatMemorySize(m_PeakAlignedSize, 2, m_PeakAllocatedSize), " / ", + FormatMemorySize(m_PeakAllocatedSize, 2, m_PeakAllocatedSize), + " (", PeakAllocatedPages, (PeakAllocatedPages == 1 ? " page)" : " pages)"), + ". Peak efficiency (used/aligned): ", std::fixed, std::setprecision(1), static_cast(m_PeakUsedSize) / static_cast(std::max(m_PeakAlignedSize, 1U)) * 100.0, '%', + ". Peak utilization (used/allocated): ", std::fixed, std::setprecision(1), static_cast(m_PeakUsedSize) / static_cast(std::max(m_PeakAllocatedSize, 1U)) * 100.0, '%'); } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index 9987f013..6ade4750 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -36,6 +36,7 @@ class TexFormatToVkFormatMapper public: TexFormatToVkFormatMapper() { + // clang-format off m_FmtToVkFmtMap[TEX_FORMAT_UNKNOWN] = VK_FORMAT_UNDEFINED; m_FmtToVkFmtMap[TEX_FORMAT_RGBA32_TYPELESS] = VK_FORMAT_R32G32B32A32_SFLOAT; @@ -154,9 +155,10 @@ public: m_FmtToVkFmtMap[TEX_FORMAT_BC7_TYPELESS] = VK_FORMAT_BC7_UNORM_BLOCK; m_FmtToVkFmtMap[TEX_FORMAT_BC7_UNORM] = VK_FORMAT_BC7_UNORM_BLOCK; m_FmtToVkFmtMap[TEX_FORMAT_BC7_UNORM_SRGB] = VK_FORMAT_BC7_SRGB_BLOCK; + // clang-format on } - VkFormat operator[](TEXTURE_FORMAT TexFmt)const + VkFormat operator[](TEXTURE_FORMAT TexFmt) const { VERIFY_EXPR(TexFmt < _countof(m_FmtToVkFmtMap)); return m_FmtToVkFmtMap[TexFmt]; @@ -179,6 +181,7 @@ class VkFormatToTexFormatMapper public: VkFormatToTexFormatMapper() { + // clang-format off m_VkFmtToTexFmtMap[VK_FORMAT_UNDEFINED] = TEX_FORMAT_UNKNOWN; m_VkFmtToTexFmtMap[VK_FORMAT_R4G4_UNORM_PACK8] = TEX_FORMAT_UNKNOWN; m_VkFmtToTexFmtMap[VK_FORMAT_R4G4B4A4_UNORM_PACK16] = TEX_FORMAT_UNKNOWN; @@ -431,11 +434,12 @@ public: m_VkFmtToTexFmtMapExt[VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG] = TEX_FORMAT_UNKNOWN; m_VkFmtToTexFmtMapExt[VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG] = TEX_FORMAT_UNKNOWN; m_VkFmtToTexFmtMapExt[VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG] = TEX_FORMAT_UNKNOWN; + // clang-format on } - TEXTURE_FORMAT operator[](VkFormat VkFmt)const + TEXTURE_FORMAT operator[](VkFormat VkFmt) const { - if(VkFmt < VK_FORMAT_RANGE_SIZE) + if (VkFmt < VK_FORMAT_RANGE_SIZE) { return m_VkFmtToTexFmtMap[VkFmt]; } @@ -447,7 +451,7 @@ public: } private: - TEXTURE_FORMAT m_VkFmtToTexFmtMap[VK_FORMAT_RANGE_SIZE] = {}; + TEXTURE_FORMAT m_VkFmtToTexFmtMap[VK_FORMAT_RANGE_SIZE] = {}; std::unordered_map m_VkFmtToTexFmtMapExt; }; @@ -616,14 +620,16 @@ VkFormat TypeToVkFormat(VALUE_TYPE ValType, Uint32 NumComponents, Bool bIsNormal VkPolygonMode FillModeToVkPolygonMode(FILL_MODE FillMode) { - switch(FillMode) + switch (FillMode) { - case FILL_MODE_UNDEFINED: - UNEXPECTED("Undefined fill mode"); + case FILL_MODE_UNDEFINED: + UNEXPECTED("Undefined fill mode"); return VK_POLYGON_MODE_FILL; + // clang-format off case FILL_MODE_SOLID: return VK_POLYGON_MODE_FILL; case FILL_MODE_WIREFRAME: return VK_POLYGON_MODE_LINE; + // clang-format on default: UNEXPECTED("Unexpected fill mode"); @@ -633,15 +639,17 @@ VkPolygonMode FillModeToVkPolygonMode(FILL_MODE FillMode) VkCullModeFlagBits CullModeToVkCullMode(CULL_MODE CullMode) { - switch(CullMode) + switch (CullMode) { case CULL_MODE_UNDEFINED: UNEXPECTED("Undefined cull mode"); return VK_CULL_MODE_NONE; + // clang-format off case CULL_MODE_NONE: return VK_CULL_MODE_NONE; case CULL_MODE_FRONT: return VK_CULL_MODE_FRONT_BIT; case CULL_MODE_BACK: return VK_CULL_MODE_BACK_BIT; + // clang-format on default: UNEXPECTED("Unexpected cull mode"); @@ -649,42 +657,44 @@ VkCullModeFlagBits CullModeToVkCullMode(CULL_MODE CullMode) } } -VkPipelineRasterizationStateCreateInfo RasterizerStateDesc_To_VkRasterizationStateCI(const RasterizerStateDesc &RasterizerDesc) +VkPipelineRasterizationStateCreateInfo RasterizerStateDesc_To_VkRasterizationStateCI(const RasterizerStateDesc& RasterizerDesc) { VkPipelineRasterizationStateCreateInfo RSStateCI = {}; + RSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; RSStateCI.pNext = nullptr; RSStateCI.flags = 0; // Reserved for future use. - // If depth clamping is enabled, before the incoming fragment's zf is compared to za, zf is clamped to - // [min(n,f), max(n,f)], where n and f are the minDepth and maxDepth depth range values of the viewport + // If depth clamping is enabled, before the incoming fragment's zf is compared to za, zf is clamped to + // [min(n,f), max(n,f)], where n and f are the minDepth and maxDepth depth range values of the viewport // used by this fragment, respectively (25.10) // This value is the opposite of clip enable RSStateCI.depthClampEnable = RasterizerDesc.DepthClipEnable ? VK_FALSE : VK_TRUE; - - RSStateCI.rasterizerDiscardEnable = VK_FALSE; // Whether primitives are discarded immediately before the rasterization stage. - RSStateCI.polygonMode = FillModeToVkPolygonMode(RasterizerDesc.FillMode); // 24.7.2 - RSStateCI.cullMode = CullModeToVkCullMode(RasterizerDesc.CullMode); // 24.7.1 - RSStateCI.frontFace = RasterizerDesc.FrontCounterClockwise ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; // 24.7.1 + + RSStateCI.rasterizerDiscardEnable = VK_FALSE; // Whether primitives are discarded immediately before the rasterization stage. + RSStateCI.polygonMode = FillModeToVkPolygonMode(RasterizerDesc.FillMode); // 24.7.2 + RSStateCI.cullMode = CullModeToVkCullMode(RasterizerDesc.CullMode); // 24.7.1 + RSStateCI.frontFace = RasterizerDesc.FrontCounterClockwise ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; // 24.7.1 // Depth bias (24.7.3) RSStateCI.depthBiasEnable = (RasterizerDesc.DepthBias != 0 || RasterizerDesc.SlopeScaledDepthBias != 0.f) ? VK_TRUE : VK_FALSE; - RSStateCI.depthBiasConstantFactor = - static_cast(RasterizerDesc.DepthBias); // a scalar factor applied to an implementation-dependent constant - // that relates to the usable resolution of the depth buffer + RSStateCI.depthBiasConstantFactor = + static_cast(RasterizerDesc.DepthBias); // a scalar factor applied to an implementation-dependent constant + // that relates to the usable resolution of the depth buffer RSStateCI.depthBiasClamp = RasterizerDesc.DepthBiasClamp; // maximum (or minimum) depth bias of a fragment. - RSStateCI.depthBiasSlopeFactor = + RSStateCI.depthBiasSlopeFactor = RasterizerDesc.SlopeScaledDepthBias; // a scalar factor applied to a fragment's slope in depth bias calculations. - RSStateCI.lineWidth = 1.f; // If the wide lines feature is not enabled, and no element of the pDynamicStates member of - // pDynamicState is VK_DYNAMIC_STATE_LINE_WIDTH, the lineWidth member of - // pRasterizationState must be 1.0 (9.2) + RSStateCI.lineWidth = 1.f; // If the wide lines feature is not enabled, and no element of the pDynamicStates member of + // pDynamicState is VK_DYNAMIC_STATE_LINE_WIDTH, the lineWidth member of + // pRasterizationState must be 1.0 (9.2) return RSStateCI; } VkCompareOp ComparisonFuncToVkCompareOp(COMPARISON_FUNCTION CmpFunc) { - switch(CmpFunc) + switch (CmpFunc) { + // clang-format off case COMPARISON_FUNC_UNKNOWN: UNEXPECTED("Comparison function is not specified" ); return VK_COMPARE_OP_ALWAYS; @@ -697,17 +707,19 @@ VkCompareOp ComparisonFuncToVkCompareOp(COMPARISON_FUNCTION CmpFunc) case COMPARISON_FUNC_NOT_EQUAL: return VK_COMPARE_OP_NOT_EQUAL; case COMPARISON_FUNC_GREATER_EQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL; case COMPARISON_FUNC_ALWAYS: return VK_COMPARE_OP_ALWAYS; + // clang-format on - default: - UNEXPECTED("Unknown comparison function" ); + default: + UNEXPECTED("Unknown comparison function"); return VK_COMPARE_OP_ALWAYS; } } VkStencilOp StencilOpToVkStencilOp(STENCIL_OP StencilOp) { - switch(StencilOp) + switch (StencilOp) { + // clang-format off case STENCIL_OP_UNDEFINED: UNEXPECTED("Undefined stencil operation"); return VK_STENCIL_OP_KEEP; @@ -720,6 +732,7 @@ VkStencilOp StencilOpToVkStencilOp(STENCIL_OP StencilOp) case STENCIL_OP_INVERT: return VK_STENCIL_OP_INVERT; case STENCIL_OP_INCR_WRAP: return VK_STENCIL_OP_INCREMENT_AND_WRAP; case STENCIL_OP_DECR_WRAP: return VK_STENCIL_OP_DECREMENT_AND_WRAP; + // clang-format on default: UNEXPECTED("Unknown stencil operation"); @@ -731,41 +744,42 @@ VkStencilOpState StencilOpDescToVkStencilOpState(const StencilOpDesc& desc, Uint { // Stencil state (25.9) VkStencilOpState StencilState = {}; - StencilState.failOp = StencilOpToVkStencilOp(desc.StencilFailOp); - StencilState.passOp = StencilOpToVkStencilOp(desc.StencilPassOp); - StencilState.depthFailOp = StencilOpToVkStencilOp(desc.StencilDepthFailOp); - StencilState.compareOp = ComparisonFuncToVkCompareOp(desc.StencilFunc); + StencilState.failOp = StencilOpToVkStencilOp(desc.StencilFailOp); + StencilState.passOp = StencilOpToVkStencilOp(desc.StencilPassOp); + StencilState.depthFailOp = StencilOpToVkStencilOp(desc.StencilDepthFailOp); + StencilState.compareOp = ComparisonFuncToVkCompareOp(desc.StencilFunc); // The s least significant bits of compareMask, where s is the number of bits in the stencil framebuffer attachment, - // are bitwise ANDed with both the reference and the stored stencil value, and the resulting masked values are those + // are bitwise ANDed with both the reference and the stored stencil value, and the resulting masked values are those // that participate in the comparison controlled by compareOp (25.9) StencilState.compareMask = StencilReadMask; - // The least significant s bits of writeMask, where s is the number of bits in the stencil framebuffer - // attachment, specify an integer mask. Where a 1 appears in this mask, the corresponding bit in the stencil + // The least significant s bits of writeMask, where s is the number of bits in the stencil framebuffer + // attachment, specify an integer mask. Where a 1 appears in this mask, the corresponding bit in the stencil // value in the depth / stencil attachment is written; where a 0 appears, the bit is not written (25.9) StencilState.writeMask = StencilWriteMask; - + StencilState.reference = 0; // Set dynamically return StencilState; } -VkPipelineDepthStencilStateCreateInfo DepthStencilStateDesc_To_VkDepthStencilStateCI(const DepthStencilStateDesc &DepthStencilDesc) +VkPipelineDepthStencilStateCreateInfo DepthStencilStateDesc_To_VkDepthStencilStateCI(const DepthStencilStateDesc& DepthStencilDesc) { // Depth-stencil state (25.7) VkPipelineDepthStencilStateCreateInfo DSStateCI = {}; - DSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - DSStateCI.pNext = nullptr; - DSStateCI.flags = 0; // reserved for future use - DSStateCI.depthTestEnable = DepthStencilDesc.DepthEnable ? VK_TRUE : VK_FALSE; - DSStateCI.depthWriteEnable = DepthStencilDesc.DepthWriteEnable ? VK_TRUE : VK_FALSE; - DSStateCI.depthCompareOp = ComparisonFuncToVkCompareOp(DepthStencilDesc.DepthFunc); // 25.10 - DSStateCI.depthBoundsTestEnable = VK_FALSE; // 25.8 - DSStateCI.stencilTestEnable = DepthStencilDesc.StencilEnable ? VK_TRUE : VK_FALSE; // 25.9 - DSStateCI.front = StencilOpDescToVkStencilOpState(DepthStencilDesc.FrontFace, DepthStencilDesc.StencilReadMask, DepthStencilDesc.StencilWriteMask); - DSStateCI.back = StencilOpDescToVkStencilOpState(DepthStencilDesc.BackFace, DepthStencilDesc.StencilReadMask, DepthStencilDesc.StencilWriteMask); + + DSStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + DSStateCI.pNext = nullptr; + DSStateCI.flags = 0; // reserved for future use + DSStateCI.depthTestEnable = DepthStencilDesc.DepthEnable ? VK_TRUE : VK_FALSE; + DSStateCI.depthWriteEnable = DepthStencilDesc.DepthWriteEnable ? VK_TRUE : VK_FALSE; + DSStateCI.depthCompareOp = ComparisonFuncToVkCompareOp(DepthStencilDesc.DepthFunc); // 25.10 + DSStateCI.depthBoundsTestEnable = VK_FALSE; // 25.8 + DSStateCI.stencilTestEnable = DepthStencilDesc.StencilEnable ? VK_TRUE : VK_FALSE; // 25.9 + DSStateCI.front = StencilOpDescToVkStencilOpState(DepthStencilDesc.FrontFace, DepthStencilDesc.StencilReadMask, DepthStencilDesc.StencilWriteMask); + DSStateCI.back = StencilOpDescToVkStencilOpState(DepthStencilDesc.BackFace, DepthStencilDesc.StencilReadMask, DepthStencilDesc.StencilWriteMask); // Depth Bounds Test (25.8) DSStateCI.minDepthBounds = 0; // must be between 0.0 and 1.0, inclusive DSStateCI.maxDepthBounds = 1; // must be between 0.0 and 1.0, inclusive @@ -779,26 +793,26 @@ public: BlendFactorToVkBlendFactorMapper() { // 26.1.1 - m_Map[BLEND_FACTOR_ZERO] = VK_BLEND_FACTOR_ZERO; - m_Map[BLEND_FACTOR_ONE] = VK_BLEND_FACTOR_ONE; - m_Map[BLEND_FACTOR_SRC_COLOR] = VK_BLEND_FACTOR_SRC_COLOR; - m_Map[BLEND_FACTOR_INV_SRC_COLOR] = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; - m_Map[BLEND_FACTOR_SRC_ALPHA] = VK_BLEND_FACTOR_SRC_ALPHA; - m_Map[BLEND_FACTOR_INV_SRC_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - m_Map[BLEND_FACTOR_DEST_ALPHA] = VK_BLEND_FACTOR_DST_ALPHA; - m_Map[BLEND_FACTOR_INV_DEST_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; - m_Map[BLEND_FACTOR_DEST_COLOR] = VK_BLEND_FACTOR_DST_COLOR; - m_Map[BLEND_FACTOR_INV_DEST_COLOR] = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; - m_Map[BLEND_FACTOR_SRC_ALPHA_SAT] = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; - m_Map[BLEND_FACTOR_BLEND_FACTOR] = VK_BLEND_FACTOR_CONSTANT_COLOR; + m_Map[BLEND_FACTOR_ZERO] = VK_BLEND_FACTOR_ZERO; + m_Map[BLEND_FACTOR_ONE] = VK_BLEND_FACTOR_ONE; + m_Map[BLEND_FACTOR_SRC_COLOR] = VK_BLEND_FACTOR_SRC_COLOR; + m_Map[BLEND_FACTOR_INV_SRC_COLOR] = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + m_Map[BLEND_FACTOR_SRC_ALPHA] = VK_BLEND_FACTOR_SRC_ALPHA; + m_Map[BLEND_FACTOR_INV_SRC_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + m_Map[BLEND_FACTOR_DEST_ALPHA] = VK_BLEND_FACTOR_DST_ALPHA; + m_Map[BLEND_FACTOR_INV_DEST_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + m_Map[BLEND_FACTOR_DEST_COLOR] = VK_BLEND_FACTOR_DST_COLOR; + m_Map[BLEND_FACTOR_INV_DEST_COLOR] = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + m_Map[BLEND_FACTOR_SRC_ALPHA_SAT] = VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; + m_Map[BLEND_FACTOR_BLEND_FACTOR] = VK_BLEND_FACTOR_CONSTANT_COLOR; m_Map[BLEND_FACTOR_INV_BLEND_FACTOR] = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; - m_Map[BLEND_FACTOR_SRC1_COLOR] = VK_BLEND_FACTOR_SRC1_COLOR; - m_Map[BLEND_FACTOR_INV_SRC1_COLOR] = VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; - m_Map[BLEND_FACTOR_SRC1_ALPHA] = VK_BLEND_FACTOR_SRC1_ALPHA; - m_Map[BLEND_FACTOR_INV_SRC1_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; + m_Map[BLEND_FACTOR_SRC1_COLOR] = VK_BLEND_FACTOR_SRC1_COLOR; + m_Map[BLEND_FACTOR_INV_SRC1_COLOR] = VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; + m_Map[BLEND_FACTOR_SRC1_ALPHA] = VK_BLEND_FACTOR_SRC1_ALPHA; + m_Map[BLEND_FACTOR_INV_SRC1_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; } - - VkBlendFactor operator[](BLEND_FACTOR bf)const + + VkBlendFactor operator[](BLEND_FACTOR bf) const { VERIFY_EXPR(bf > BLEND_FACTOR_UNDEFINED && bf < BLEND_FACTOR_NUM_FACTORS); return m_Map[static_cast(bf)]; @@ -815,25 +829,25 @@ public: LogicOperationToVkLogicOp() { // 26.2 - m_Map[ LOGIC_OP_CLEAR ] = VK_LOGIC_OP_CLEAR; - m_Map[ LOGIC_OP_SET ] = VK_LOGIC_OP_SET; - m_Map[ LOGIC_OP_COPY ] = VK_LOGIC_OP_COPY; - m_Map[ LOGIC_OP_COPY_INVERTED ] = VK_LOGIC_OP_COPY_INVERTED; - m_Map[ LOGIC_OP_NOOP ] = VK_LOGIC_OP_NO_OP; - m_Map[ LOGIC_OP_INVERT ] = VK_LOGIC_OP_INVERT; - m_Map[ LOGIC_OP_AND ] = VK_LOGIC_OP_AND; - m_Map[ LOGIC_OP_NAND ] = VK_LOGIC_OP_NAND; - m_Map[ LOGIC_OP_OR ] = VK_LOGIC_OP_OR; - m_Map[ LOGIC_OP_NOR ] = VK_LOGIC_OP_NOR; - m_Map[ LOGIC_OP_XOR ] = VK_LOGIC_OP_XOR; - m_Map[ LOGIC_OP_EQUIV ] = VK_LOGIC_OP_EQUIVALENT; - m_Map[ LOGIC_OP_AND_REVERSE ] = VK_LOGIC_OP_AND_REVERSE; - m_Map[ LOGIC_OP_AND_INVERTED ] = VK_LOGIC_OP_AND_INVERTED; - m_Map[ LOGIC_OP_OR_REVERSE ] = VK_LOGIC_OP_OR_REVERSE; - m_Map[ LOGIC_OP_OR_INVERTED ] = VK_LOGIC_OP_OR_INVERTED; + m_Map[LOGIC_OP_CLEAR] = VK_LOGIC_OP_CLEAR; + m_Map[LOGIC_OP_SET] = VK_LOGIC_OP_SET; + m_Map[LOGIC_OP_COPY] = VK_LOGIC_OP_COPY; + m_Map[LOGIC_OP_COPY_INVERTED] = VK_LOGIC_OP_COPY_INVERTED; + m_Map[LOGIC_OP_NOOP] = VK_LOGIC_OP_NO_OP; + m_Map[LOGIC_OP_INVERT] = VK_LOGIC_OP_INVERT; + m_Map[LOGIC_OP_AND] = VK_LOGIC_OP_AND; + m_Map[LOGIC_OP_NAND] = VK_LOGIC_OP_NAND; + m_Map[LOGIC_OP_OR] = VK_LOGIC_OP_OR; + m_Map[LOGIC_OP_NOR] = VK_LOGIC_OP_NOR; + m_Map[LOGIC_OP_XOR] = VK_LOGIC_OP_XOR; + m_Map[LOGIC_OP_EQUIV] = VK_LOGIC_OP_EQUIVALENT; + m_Map[LOGIC_OP_AND_REVERSE] = VK_LOGIC_OP_AND_REVERSE; + m_Map[LOGIC_OP_AND_INVERTED] = VK_LOGIC_OP_AND_INVERTED; + m_Map[LOGIC_OP_OR_REVERSE] = VK_LOGIC_OP_OR_REVERSE; + m_Map[LOGIC_OP_OR_INVERTED] = VK_LOGIC_OP_OR_INVERTED; } - VkLogicOp operator[](LOGIC_OPERATION op)const + VkLogicOp operator[](LOGIC_OPERATION op) const { VERIFY_EXPR(op >= LOGIC_OP_CLEAR && op < LOGIC_OP_NUM_OPERATIONS); return m_Map[static_cast(op)]; @@ -849,14 +863,14 @@ public: BlendOperationToVkBlendOp() { // 26.1.3 - m_Map[ BLEND_OPERATION_ADD ] = VK_BLEND_OP_ADD; - m_Map[ BLEND_OPERATION_SUBTRACT ] = VK_BLEND_OP_SUBTRACT; - m_Map[ BLEND_OPERATION_REV_SUBTRACT ] = VK_BLEND_OP_REVERSE_SUBTRACT; - m_Map[ BLEND_OPERATION_MIN ] = VK_BLEND_OP_MIN; - m_Map[ BLEND_OPERATION_MAX ] = VK_BLEND_OP_MAX; + m_Map[BLEND_OPERATION_ADD] = VK_BLEND_OP_ADD; + m_Map[BLEND_OPERATION_SUBTRACT] = VK_BLEND_OP_SUBTRACT; + m_Map[BLEND_OPERATION_REV_SUBTRACT] = VK_BLEND_OP_REVERSE_SUBTRACT; + m_Map[BLEND_OPERATION_MIN] = VK_BLEND_OP_MIN; + m_Map[BLEND_OPERATION_MAX] = VK_BLEND_OP_MAX; } - VkBlendOp operator[](BLEND_OPERATION op)const + VkBlendOp operator[](BLEND_OPERATION op) const { VERIFY_EXPR(op > BLEND_OPERATION_UNDEFINED && op < BLEND_OPERATION_NUM_OPERATIONS); return m_Map[static_cast(op)]; @@ -866,11 +880,12 @@ private: std::array m_Map = {}; }; -VkPipelineColorBlendAttachmentState RenderTargetBlendDescToVkColorBlendAttachmentState(const RenderTargetBlendDesc &RTBlendDesc) +VkPipelineColorBlendAttachmentState RenderTargetBlendDescToVkColorBlendAttachmentState(const RenderTargetBlendDesc& RTBlendDesc) { static const BlendFactorToVkBlendFactorMapper BFtoVKBF; - static const BlendOperationToVkBlendOp BOtoVKBO; - VkPipelineColorBlendAttachmentState AttachmentBlendState = {}; + static const BlendOperationToVkBlendOp BOtoVKBO; + VkPipelineColorBlendAttachmentState AttachmentBlendState = {}; + AttachmentBlendState.blendEnable = RTBlendDesc.BlendEnable; AttachmentBlendState.srcColorBlendFactor = BFtoVKBF[RTBlendDesc.SrcBlend]; AttachmentBlendState.dstColorBlendFactor = BFtoVKBF[RTBlendDesc.DestBlend]; @@ -878,47 +893,47 @@ VkPipelineColorBlendAttachmentState RenderTargetBlendDescToVkColorBlendAttachmen AttachmentBlendState.srcAlphaBlendFactor = BFtoVKBF[RTBlendDesc.SrcBlendAlpha]; AttachmentBlendState.dstAlphaBlendFactor = BFtoVKBF[RTBlendDesc.DestBlendAlpha]; AttachmentBlendState.alphaBlendOp = BOtoVKBO[RTBlendDesc.BlendOpAlpha]; - AttachmentBlendState.colorWriteMask = - ((RTBlendDesc.RenderTargetWriteMask & COLOR_MASK_RED) ? VK_COLOR_COMPONENT_R_BIT : 0) | + AttachmentBlendState.colorWriteMask = + ((RTBlendDesc.RenderTargetWriteMask & COLOR_MASK_RED) ? VK_COLOR_COMPONENT_R_BIT : 0) | ((RTBlendDesc.RenderTargetWriteMask & COLOR_MASK_GREEN) ? VK_COLOR_COMPONENT_G_BIT : 0) | - ((RTBlendDesc.RenderTargetWriteMask & COLOR_MASK_BLUE) ? VK_COLOR_COMPONENT_B_BIT : 0) | + ((RTBlendDesc.RenderTargetWriteMask & COLOR_MASK_BLUE) ? VK_COLOR_COMPONENT_B_BIT : 0) | ((RTBlendDesc.RenderTargetWriteMask & COLOR_MASK_ALPHA) ? VK_COLOR_COMPONENT_A_BIT : 0); return AttachmentBlendState; } -void BlendStateDesc_To_VkBlendStateCI(const BlendStateDesc &BSDesc, - VkPipelineColorBlendStateCreateInfo &ColorBlendStateCI, - std::vector &ColorBlendAttachments) +void BlendStateDesc_To_VkBlendStateCI(const BlendStateDesc& BSDesc, + VkPipelineColorBlendStateCreateInfo& ColorBlendStateCI, + std::vector& ColorBlendAttachments) { // Color blend state (26.1) static const LogicOperationToVkLogicOp LogicOpToVkLogicOp; - ColorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - ColorBlendStateCI.pNext = nullptr; - ColorBlendStateCI.flags = 0; // reserved for future use - ColorBlendStateCI.logicOpEnable = BSDesc.RenderTargets[0].LogicOperationEnable; // 26.2 - ColorBlendStateCI.logicOp = LogicOpToVkLogicOp[BSDesc.RenderTargets[0].LogicOp]; + ColorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + ColorBlendStateCI.pNext = nullptr; + ColorBlendStateCI.flags = 0; // reserved for future use + ColorBlendStateCI.logicOpEnable = BSDesc.RenderTargets[0].LogicOperationEnable; // 26.2 + ColorBlendStateCI.logicOp = LogicOpToVkLogicOp[BSDesc.RenderTargets[0].LogicOp]; ColorBlendStateCI.blendConstants[0] = 0.f; // We use dynamic blend constants ColorBlendStateCI.blendConstants[1] = 0.f; ColorBlendStateCI.blendConstants[2] = 0.f; ColorBlendStateCI.blendConstants[3] = 0.f; // attachmentCount must equal the colorAttachmentCount for the subpass in which this pipeline is used. - for(uint32_t attachment = 0; attachment < ColorBlendStateCI.attachmentCount; ++attachment) + for (uint32_t attachment = 0; attachment < ColorBlendStateCI.attachmentCount; ++attachment) { - const auto& RTBlendState = BSDesc.IndependentBlendEnable ? BSDesc.RenderTargets[attachment] : BSDesc.RenderTargets[0]; + const auto& RTBlendState = BSDesc.IndependentBlendEnable ? BSDesc.RenderTargets[attachment] : BSDesc.RenderTargets[0]; ColorBlendAttachments[attachment] = RenderTargetBlendDescToVkColorBlendAttachmentState(RTBlendState); } } VkVertexInputRate LayoutElemFrequencyToVkInputRate(LayoutElement::FREQUENCY frequency) { - switch(frequency) + switch (frequency) { - case LayoutElement::FREQUENCY_UNDEFINED: + case LayoutElement::FREQUENCY_UNDEFINED: UNEXPECTED("Undefined layout element frequency"); return VK_VERTEX_INPUT_RATE_VERTEX; - - case LayoutElement::FREQUENCY_PER_VERTEX: return VK_VERTEX_INPUT_RATE_VERTEX; + + case LayoutElement::FREQUENCY_PER_VERTEX: return VK_VERTEX_INPUT_RATE_VERTEX; case LayoutElement::FREQUENCY_PER_INSTANCE: return VK_VERTEX_INPUT_RATE_INSTANCE; default: @@ -927,56 +942,56 @@ VkVertexInputRate LayoutElemFrequencyToVkInputRate(LayoutElement::FREQUENCY freq } } -void InputLayoutDesc_To_VkVertexInputStateCI(const InputLayoutDesc& LayoutDesc, - VkPipelineVertexInputStateCreateInfo &VertexInputStateCI, - std::array& BindingDescriptions, +void InputLayoutDesc_To_VkVertexInputStateCI(const InputLayoutDesc& LayoutDesc, + VkPipelineVertexInputStateCreateInfo& VertexInputStateCI, + std::array& BindingDescriptions, std::array& AttributeDescription) { // Vertex input description (20.2) - VertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - VertexInputStateCI.pNext = nullptr; - VertexInputStateCI.flags = 0; // reserved for future use. - VertexInputStateCI.vertexBindingDescriptionCount = 0; - VertexInputStateCI.pVertexBindingDescriptions = BindingDescriptions.data(); + VertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + VertexInputStateCI.pNext = nullptr; + VertexInputStateCI.flags = 0; // reserved for future use. + VertexInputStateCI.vertexBindingDescriptionCount = 0; + VertexInputStateCI.pVertexBindingDescriptions = BindingDescriptions.data(); VertexInputStateCI.vertexAttributeDescriptionCount = LayoutDesc.NumElements; - VertexInputStateCI.pVertexAttributeDescriptions = AttributeDescription.data(); + VertexInputStateCI.pVertexAttributeDescriptions = AttributeDescription.data(); std::array BufferSlot2BindingDescInd; BufferSlot2BindingDescInd.fill(-1); - for(Uint32 elem=0; elem < LayoutDesc.NumElements; ++elem) + for (Uint32 elem = 0; elem < LayoutDesc.NumElements; ++elem) { - auto &LayoutElem = LayoutDesc.LayoutElements[elem]; - auto &BindingDescInd = BufferSlot2BindingDescInd[LayoutElem.BufferSlot]; - if(BindingDescInd < 0) + auto& LayoutElem = LayoutDesc.LayoutElements[elem]; + auto& BindingDescInd = BufferSlot2BindingDescInd[LayoutElem.BufferSlot]; + if (BindingDescInd < 0) { - BindingDescInd = VertexInputStateCI.vertexBindingDescriptionCount++; - auto &BindingDesc = BindingDescriptions[BindingDescInd]; - BindingDesc.binding = LayoutElem.BufferSlot; - BindingDesc.stride = LayoutElem.Stride; + BindingDescInd = VertexInputStateCI.vertexBindingDescriptionCount++; + auto& BindingDesc = BindingDescriptions[BindingDescInd]; + BindingDesc.binding = LayoutElem.BufferSlot; + BindingDesc.stride = LayoutElem.Stride; BindingDesc.inputRate = LayoutElemFrequencyToVkInputRate(LayoutElem.Frequency); } - const auto &BindingDesc = BindingDescriptions[BindingDescInd]; + const auto& BindingDesc = BindingDescriptions[BindingDescInd]; VERIFY(BindingDesc.binding == LayoutElem.BufferSlot, "Inconsistent buffer slot"); VERIFY(BindingDesc.stride == LayoutElem.Stride, "Inconsistent strides"); VERIFY(BindingDesc.inputRate == LayoutElemFrequencyToVkInputRate(LayoutElem.Frequency), "Incosistent layout element frequency"); - auto &AttribDesc = AttributeDescription[elem]; - AttribDesc.binding = BindingDesc.binding; + auto& AttribDesc = AttributeDescription[elem]; + AttribDesc.binding = BindingDesc.binding; AttribDesc.location = LayoutElem.InputIndex; - AttribDesc.format = TypeToVkFormat(LayoutElem.ValueType, LayoutElem.NumComponents, LayoutElem.IsNormalized); - AttribDesc.offset = LayoutElem.RelativeOffset; + AttribDesc.format = TypeToVkFormat(LayoutElem.ValueType, LayoutElem.NumComponents, LayoutElem.IsNormalized); + AttribDesc.offset = LayoutElem.RelativeOffset; } } -void PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(PRIMITIVE_TOPOLOGY PrimTopology, - VkPrimitiveTopology &VkPrimTopology, - uint32_t &PatchControlPoints) +void PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(PRIMITIVE_TOPOLOGY PrimTopology, + VkPrimitiveTopology& VkPrimTopology, + uint32_t& PatchControlPoints) { PatchControlPoints = 0; - switch(PrimTopology) + switch (PrimTopology) { - case PRIMITIVE_TOPOLOGY_UNDEFINED: - UNEXPECTED("Undefined primitive topology"); + case PRIMITIVE_TOPOLOGY_UNDEFINED: + UNEXPECTED("Undefined primitive topology"); VkPrimTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; return; @@ -998,7 +1013,7 @@ void PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(PRIMITIVE_TOPOLOGY default: VERIFY_EXPR(PrimTopology >= PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST && PrimTopology < PRIMITIVE_TOPOLOGY_NUM_TOPOLOGIES); - VkPrimTopology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; + VkPrimTopology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; PatchControlPoints = static_cast(PrimTopology) - static_cast(PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST) + 1; return; } @@ -1006,9 +1021,9 @@ void PrimitiveTopology_To_VkPrimitiveTopologyAndPatchCPCount(PRIMITIVE_TOPOLOGY VkFilter FilterTypeToVkFilter(FILTER_TYPE FilterType) { - switch(FilterType) + switch (FilterType) { - case FILTER_TYPE_UNKNOWN: + case FILTER_TYPE_UNKNOWN: UNEXPECTED("Unknown filter type"); return VK_FILTER_NEAREST; @@ -1024,7 +1039,7 @@ VkFilter FilterTypeToVkFilter(FILTER_TYPE FilterType) case FILTER_TYPE_COMPARISON_ANISOTROPIC: case FILTER_TYPE_MINIMUM_LINEAR: case FILTER_TYPE_MINIMUM_ANISOTROPIC: - case FILTER_TYPE_MAXIMUM_LINEAR: + case FILTER_TYPE_MAXIMUM_LINEAR: case FILTER_TYPE_MAXIMUM_ANISOTROPIC: return VK_FILTER_LINEAR; @@ -1066,17 +1081,19 @@ VkSamplerMipmapMode FilterTypeToVkMipmapMode(FILTER_TYPE FilterType) VkSamplerAddressMode AddressModeToVkAddressMode(TEXTURE_ADDRESS_MODE AddressMode) { - switch(AddressMode) + switch (AddressMode) { case TEXTURE_ADDRESS_UNKNOWN: UNEXPECTED("Unknown address mode"); return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + // clang-format off case TEXTURE_ADDRESS_WRAP: return VK_SAMPLER_ADDRESS_MODE_REPEAT; case TEXTURE_ADDRESS_MIRROR: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; case TEXTURE_ADDRESS_CLAMP: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; case TEXTURE_ADDRESS_BORDER: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; case TEXTURE_ADDRESS_MIRROR_ONCE: return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; + // clang-format on default: UNEXPECTED("Unexpected address mode"); @@ -1121,9 +1138,10 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) //VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX static_assert(RESOURCE_STATE_MAX_BIT == 0x8000, "This function must be updated to handle new resource state flag"); - VERIFY((StateFlag & (StateFlag-1)) == 0, "Only single bit must be set"); - switch(StateFlag) + VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set"); + switch (StateFlag) { + // clang-format off case RESOURCE_STATE_UNDEFINED: return 0; case RESOURCE_STATE_VERTEX_BUFFER: return VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; case RESOURCE_STATE_CONSTANT_BUFFER: return VK_ACCESS_UNIFORM_READ_BIT; @@ -1140,6 +1158,7 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) case RESOURCE_STATE_RESOLVE_DEST: return VK_ACCESS_MEMORY_READ_BIT; case RESOURCE_STATE_RESOLVE_SOURCE: return VK_ACCESS_MEMORY_WRITE_BIT; case RESOURCE_STATE_PRESENT: return VK_ACCESS_MEMORY_READ_BIT; + // clang-format on default: UNEXPECTED("Unexpected resource state flag"); @@ -1152,46 +1171,48 @@ class StateFlagBitPosToVkAccessFlags public: StateFlagBitPosToVkAccessFlags() { - static_assert( (1 << MaxFlagBitPos) == RESOURCE_STATE_MAX_BIT, "This function must be updated to handle new resource state flag"); - for (Uint32 bit=0; bit < MaxFlagBitPos; ++bit) + static_assert((1 << MaxFlagBitPos) == RESOURCE_STATE_MAX_BIT, "This function must be updated to handle new resource state flag"); + for (Uint32 bit = 0; bit < MaxFlagBitPos; ++bit) { - FlagBitPosToVkAccessFlagsMap[bit] = ResourceStateFlagToVkAccessFlags(static_cast(1<(1 << bit)); } } - VkAccessFlags operator()(Uint32 BitPos)const + VkAccessFlags operator()(Uint32 BitPos) const { VERIFY(BitPos <= MaxFlagBitPos, "Resource state flag bit position (", BitPos, ") exceeds max bit position (", Uint32{MaxFlagBitPos}, ")"); return FlagBitPosToVkAccessFlagsMap[BitPos]; } private: - static constexpr const Uint32 MaxFlagBitPos = 15; + static constexpr const Uint32 MaxFlagBitPos = 15; std::array FlagBitPosToVkAccessFlagsMap; }; VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags) { - VERIFY(Uint32{StateFlags} < (RESOURCE_STATE_MAX_BIT<<1), "Resource state flags are out of range"); + VERIFY(Uint32{StateFlags} < (RESOURCE_STATE_MAX_BIT << 1), "Resource state flags are out of range"); static const StateFlagBitPosToVkAccessFlags BitPosToAccessFlags; + VkAccessFlags AccessFlags = 0; - Uint32 Bits = StateFlags; - while(Bits != 0) + Uint32 Bits = StateFlags; + while (Bits != 0) { auto lsb = PlatformMisc::GetLSB(Bits); AccessFlags |= BitPosToAccessFlags(lsb); - Bits &= ~(1<(1<(1 << bit)); } } - RESOURCE_STATE operator()(Uint32 BitPos)const + RESOURCE_STATE operator()(Uint32 BitPos) const { VERIFY(BitPos <= MaxFlagBitPos, "Resource state flag bit position (", BitPos, ") exceeds max bit position (", Uint32{MaxFlagBitPos}, ")"); return FlagBitPosToResourceState[BitPos]; } private: - static constexpr const Uint32 MaxFlagBitPos = 20; + static constexpr const Uint32 MaxFlagBitPos = 20; std::array FlagBitPosToResourceState; }; @@ -1252,12 +1274,12 @@ private: RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags) { static const VkAccessFlagBitPosToResourceState BitPosToState; - Uint32 State = 0; + Uint32 State = 0; while (AccessFlags != 0) { auto lsb = PlatformMisc::GetLSB(AccessFlags); State |= BitPosToState(lsb); - AccessFlags &= ~(1<(State); } @@ -1266,7 +1288,7 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags) VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) { - if(StateFlag == RESOURCE_STATE_UNKNOWN) + if (StateFlag == RESOURCE_STATE_UNKNOWN) { return VK_IMAGE_LAYOUT_UNDEFINED; } @@ -1278,9 +1300,10 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) //VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, static_assert(RESOURCE_STATE_MAX_BIT == 0x8000, "This function must be updated to handle new resource state flag"); - VERIFY((StateFlag & (StateFlag-1)) == 0, "Only single bit must be set"); - switch(StateFlag) + VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set"); + switch (StateFlag) { + // clang-format off case RESOURCE_STATE_UNDEFINED: return VK_IMAGE_LAYOUT_UNDEFINED; case RESOURCE_STATE_VERTEX_BUFFER: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; case RESOURCE_STATE_CONSTANT_BUFFER: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; @@ -1297,6 +1320,7 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) case RESOURCE_STATE_RESOLVE_DEST: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; case RESOURCE_STATE_RESOLVE_SOURCE: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; case RESOURCE_STATE_PRESENT: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + // clang-format on default: UNEXPECTED("Unexpected resource state flag (", StateFlag, ")"); @@ -1307,8 +1331,9 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout) { static_assert(RESOURCE_STATE_MAX_BIT == 0x8000, "This function must be updated to handle new resource state flag"); - switch(Layout) + switch (Layout) { + // clang-format off case VK_IMAGE_LAYOUT_UNDEFINED: return RESOURCE_STATE_UNDEFINED; case VK_IMAGE_LAYOUT_GENERAL: return RESOURCE_STATE_UNORDERED_ACCESS; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return RESOURCE_STATE_RENDER_TARGET; @@ -1326,7 +1351,8 @@ RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout) default: UNEXPECTED("Unknown image layout (", Layout, ")"); return RESOURCE_STATE_UNDEFINED; + // clang-format on } } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp index b1858405..0316ec05 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp @@ -31,9 +31,11 @@ namespace Diligent VulkanUploadHeap::VulkanUploadHeap(RenderDeviceVkImpl& RenderDevice, std::string HeapName, VkDeviceSize PageSize) : + // clang-format off m_RenderDevice {RenderDevice }, m_HeapName {std::move(HeapName)}, m_PageSize {PageSize } +// clang-format on { } @@ -41,13 +43,15 @@ VulkanUploadHeap::~VulkanUploadHeap() { DEV_CHECK_ERR(m_Pages.empty(), "Upload heap '", m_HeapName, "' not all pages are released"); auto PeakAllocatedPages = m_PeakAllocatedSize / m_PageSize; - LOG_INFO_MESSAGE(m_HeapName, " peak used/allocated frame size: ", FormatMemorySize(m_PeakFrameSize, 2, m_PeakAllocatedSize), " / ", FormatMemorySize(m_PeakAllocatedSize, 2), - " (", PeakAllocatedPages, (PeakAllocatedPages == 1 ? " page)" : " pages)") ); + LOG_INFO_MESSAGE(m_HeapName, " peak used/allocated frame size: ", FormatMemorySize(m_PeakFrameSize, 2, m_PeakAllocatedSize), + " / ", FormatMemorySize(m_PeakAllocatedSize, 2), + " (", PeakAllocatedPages, (PeakAllocatedPages == 1 ? " page)" : " pages)")); } -VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize SizeInBytes)const +VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize SizeInBytes) const { VkBufferCreateInfo StagingBufferCI = {}; + StagingBufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; StagingBufferCI.pNext = nullptr; StagingBufferCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT @@ -57,25 +61,26 @@ VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize Si StagingBufferCI.queueFamilyIndexCount = 0; StagingBufferCI.pQueueFamilyIndices = nullptr; - const auto& LogicalDevice = m_RenderDevice.GetLogicalDevice(); - const auto& PhysicalDevice = m_RenderDevice.GetPhysicalDevice(); - auto& GlobalMemoryMgr = m_RenderDevice.GetGlobalMemoryManager(); + const auto& LogicalDevice = m_RenderDevice.GetLogicalDevice(); + const auto& PhysicalDevice = m_RenderDevice.GetPhysicalDevice(); + auto& GlobalMemoryMgr = m_RenderDevice.GetGlobalMemoryManager(); - auto NewBuffer = LogicalDevice.CreateBuffer(StagingBufferCI, "Upload buffer"); - auto MemReqs = LogicalDevice.GetBufferMemoryRequirements(NewBuffer); + auto NewBuffer = LogicalDevice.CreateBuffer(StagingBufferCI, "Upload buffer"); + auto MemReqs = LogicalDevice.GetBufferMemoryRequirements(NewBuffer); auto MemoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); DEV_CHECK_ERR(MemoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex, - "Vulkan spec requires that for a VkBuffer not created with the VK_BUFFER_CREATE_SPARSE_BINDING_BIT " - "bit set, or for a VkImage that was created with a VK_IMAGE_TILING_LINEAR value in the tiling member " - "of the VkImageCreateInfo structure passed to vkCreateImage, the memoryTypeBits member always contains " - "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has both the " - "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit AND the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set. (11.6)"); + "Vulkan spec requires that for a VkBuffer not created with the VK_BUFFER_CREATE_SPARSE_BINDING_BIT " + "bit set, or for a VkImage that was created with a VK_IMAGE_TILING_LINEAR value in the tiling member " + "of the VkImageCreateInfo structure passed to vkCreateImage, the memoryTypeBits member always contains " + "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has both the " + "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit AND the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set. (11.6)"); auto MemAllocation = GlobalMemoryMgr.Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, true); - auto AlignedOffset = (MemAllocation.UnalignedOffset + (MemReqs.alignment-1)) & ~(MemReqs.alignment-1); - auto err = LogicalDevice.BindBufferMemory(NewBuffer, MemAllocation.Page->GetVkMemory(), AlignedOffset); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to bind buffer memory"); (void)err; + auto AlignedOffset = (MemAllocation.UnalignedOffset + (MemReqs.alignment - 1)) & ~(MemReqs.alignment - 1); + auto err = LogicalDevice.BindBufferMemory(NewBuffer, MemAllocation.Page->GetVkMemory(), AlignedOffset); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to bind buffer memory"); + (void)err; auto CPUAddress = reinterpret_cast(MemAllocation.Page->GetCPUMemory()) + AlignedOffset; return UploadPageInfo{std::move(MemAllocation), std::move(NewBuffer), CPUAddress}; @@ -86,34 +91,34 @@ VulkanUploadAllocation VulkanUploadHeap::Allocate(size_t SizeInBytes, size_t Ali VERIFY(IsPowerOfTwo(Alignment), "Alignment (", Alignment, ") must be power of two"); VulkanUploadAllocation Allocation; - if(SizeInBytes >= m_PageSize/2) + if (SizeInBytes >= m_PageSize / 2) { // Allocate large chunk directly from the memory manager - auto NewPage = CreateNewPage(SizeInBytes); + auto NewPage = CreateNewPage(SizeInBytes); Allocation.vkBuffer = NewPage.Buffer; Allocation.CPUAddress = NewPage.CPUAddress; Allocation.Size = SizeInBytes; VERIFY(Alignment < SizeInBytes, "Alignment must be smaller than the page size"); Allocation.AlignedOffset = 0; - m_CurrAllocatedSize += NewPage.MemAllocation.Size; + m_CurrAllocatedSize += NewPage.MemAllocation.Size; m_Pages.emplace_back(std::move(NewPage)); } else { auto AlignmentOffset = Align(m_CurrPage.CurrOffset, Alignment) - m_CurrPage.CurrOffset; - if(m_CurrPage.AvailableSize < SizeInBytes + AlignmentOffset) + if (m_CurrPage.AvailableSize < SizeInBytes + AlignmentOffset) { // Allocate new page auto NewPage = CreateNewPage(m_PageSize); m_CurrPage.Reset(NewPage, m_PageSize); m_CurrAllocatedSize += NewPage.MemAllocation.Size; m_Pages.emplace_back(std::move(NewPage)); - VERIFY_EXPR((m_CurrPage.CurrOffset & (Alignment-1)) == 0); + VERIFY_EXPR((m_CurrPage.CurrOffset & (Alignment - 1)) == 0); AlignmentOffset = 0; } m_CurrPage.Advance(AlignmentOffset); - VERIFY_EXPR((m_CurrPage.CurrOffset & (Alignment-1)) == 0); + VERIFY_EXPR((m_CurrPage.CurrOffset & (Alignment - 1)) == 0); Allocation.vkBuffer = m_CurrPage.vkBuffer; Allocation.CPUAddress = m_CurrPage.CurrCPUAddress; Allocation.Size = SizeInBytes; @@ -124,7 +129,7 @@ VulkanUploadAllocation VulkanUploadHeap::Allocate(size_t SizeInBytes, size_t Ali m_PeakFrameSize = std::max(m_CurrFrameSize, m_PeakFrameSize); m_PeakAllocatedSize = std::max(m_CurrAllocatedSize, m_PeakAllocatedSize); - VERIFY_EXPR((Allocation.AlignedOffset & (Alignment-1)) == 0); + VERIFY_EXPR((Allocation.AlignedOffset & (Alignment - 1)) == 0); return Allocation; } @@ -135,14 +140,14 @@ void VulkanUploadHeap::ReleaseAllocatedPages(Uint64 CmdQueueMask) for (auto& Page : m_Pages) { m_RenderDevice.SafeReleaseDeviceObject(std::move(Page.MemAllocation), CmdQueueMask); - m_RenderDevice.SafeReleaseDeviceObject(std::move(Page.Buffer), CmdQueueMask); + m_RenderDevice.SafeReleaseDeviceObject(std::move(Page.Buffer), CmdQueueMask); } m_Pages.clear(); - m_CurrPage = CurrPageInfo{}; + m_CurrPage = CurrPageInfo{}; m_CurrFrameSize = 0; m_CurrAllocatedSize = 0; } -} +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp index 7e842c7a..49602446 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp @@ -27,7 +27,7 @@ namespace VulkanUtilities { -static VkPipelineStageFlags PipelineStageFromAccessFlags( VkAccessFlags AccessFlags, +static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags AccessFlags, const VkPipelineStageFlags EnabledGraphicsShaderStages) { // 6.1.3 @@ -35,11 +35,11 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags( VkAccessFlags while (AccessFlags != 0) { - VkAccessFlagBits AccessFlag = static_cast( AccessFlags & (~(AccessFlags-1))); - VERIFY_EXPR( AccessFlag != 0 && (AccessFlag & (AccessFlag-1)) == 0 ); + VkAccessFlagBits AccessFlag = static_cast(AccessFlags & (~(AccessFlags - 1))); + VERIFY_EXPR(AccessFlag != 0 && (AccessFlag & (AccessFlag - 1)) == 0); AccessFlags &= ~AccessFlag; - // An application MUST NOT specify an access flag in a synchronization command if it does not include a + // An application MUST NOT specify an access flag in a synchronization command if it does not include a // pipeline stage in the corresponding stage mask that is able to perform accesses of that type. // A table that lists, for each access flag, which pipeline stages can perform that type of access is given in 6.1.3. switch (AccessFlag) @@ -47,88 +47,88 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags( VkAccessFlags // Read access to an indirect command structure read as part of an indirect drawing or dispatch command case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: Stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - break; + break; // Read access to an index buffer as part of an indexed drawing command, bound by vkCmdBindIndexBuffer case VK_ACCESS_INDEX_READ_BIT: Stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - break; + break; // Read access to a vertex buffer as part of a drawing command, bound by vkCmdBindVertexBuffers case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: Stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - break; + break; // Read access to a uniform buffer case VK_ACCESS_UNIFORM_READ_BIT: Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - break; + break; // Read access to an input attachment within a render pass during fragment shading case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: Stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; + break; // Read access to a storage buffer, uniform texel buffer, storage texel buffer, sampled image, or storage image case VK_ACCESS_SHADER_READ_BIT: Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - break; + break; // Write access to a storage buffer, storage texel buffer, or storage image case VK_ACCESS_SHADER_WRITE_BIT: Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - break; + break; // Read access to a color attachment, such as via blending, logic operations, or via certain subpass load operations case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: Stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; + break; // Write access to a color or resolve attachment during a render pass or via certain subpass load and store operations case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: Stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; + break; // Read access to a depth/stencil attachment, via depth or stencil operations or via certain subpass load operations case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: Stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; + break; // Write access to a depth/stencil attachment, via depth or stencil operations or via certain subpass load and store operations case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: Stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; + break; // Read access to an image or buffer in a copy operation case VK_ACCESS_TRANSFER_READ_BIT: Stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; + break; // Write access to an image or buffer in a clear or copy operation case VK_ACCESS_TRANSFER_WRITE_BIT: Stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; - break; + break; // Read access by a host operation. Accesses of this type are not performed through a resource, but directly on memory case VK_ACCESS_HOST_READ_BIT: Stages |= VK_PIPELINE_STAGE_HOST_BIT; - break; + break; // Write access by a host operation. Accesses of this type are not performed through a resource, but directly on memory case VK_ACCESS_HOST_WRITE_BIT: Stages |= VK_PIPELINE_STAGE_HOST_BIT; - break; + break; - // Read access via non-specific entities. When included in a destination access mask, makes all available writes + // Read access via non-specific entities. When included in a destination access mask, makes all available writes // visible to all future read accesses on entities known to the Vulkan device case VK_ACCESS_MEMORY_READ_BIT: - break; + break; - // Write access via non-specific entities. hen included in a source access mask, all writes that are performed - // by entities known to the Vulkan device are made available. When included in a destination access mask, makes + // Write access via non-specific entities. hen included in a source access mask, all writes that are performed + // by entities known to the Vulkan device are made available. When included in a destination access mask, makes // all available writes visible to all future write accesses on entities known to the Vulkan device. case VK_ACCESS_MEMORY_WRITE_BIT: - break; + break; default: UNEXPECTED("Unknown memory access flag"); @@ -141,59 +141,59 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags( VkAccessFlags static VkPipelineStageFlags AccessMaskFromImageLayout(VkImageLayout Layout, bool IsDstMask // false - source mask // true - destination mask - ) +) { VkPipelineStageFlags AccessMask = 0; - switch (Layout) + switch (Layout) { - // does not support device access. This layout must only be used as the initialLayout member - // of VkImageCreateInfo or VkAttachmentDescription, or as the oldLayout in an image transition. + // does not support device access. This layout must only be used as the initialLayout member + // of VkImageCreateInfo or VkAttachmentDescription, or as the oldLayout in an image transition. // When transitioning out of this layout, the contents of the memory are not guaranteed to be preserved (11.4) case VK_IMAGE_LAYOUT_UNDEFINED: if (IsDstMask) { UNEXPECTED("The new layout used in a transition must not be VK_IMAGE_LAYOUT_UNDEFINED. " - "This layout must only be used as the initialLayout member of VkImageCreateInfo " + "This layout must only be used as the initialLayout member of VkImageCreateInfo " "or VkAttachmentDescription, or as the oldLayout in an image transition. (11.4)"); } - break; + break; // supports all types of device access case VK_IMAGE_LAYOUT_GENERAL: // VK_IMAGE_LAYOUT_GENERAL must be used for image load/store operations (13.1.1, 13.2.4) AccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - break; + break; // must only be used as a color or resolve attachment in a VkFramebuffer (11.4) case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: AccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - break; + break; // must only be used as a depth/stencil attachment in a VkFramebuffer (11.4) case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: AccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - break; + break; // must only be used as a read-only depth/stencil attachment in a VkFramebuffer and/or as a read-only image in a shader (11.4) case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: AccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - break; + break; - // must only be used as a read-only image in a shader (which can be read as a sampled image, + // must only be used as a read-only image in a shader (which can be read as a sampled image, // combined image/sampler and/or input attachment) (11.4) case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: AccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - break; + break; // must only be used as a source image of a transfer command (11.4) case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: AccessMask = VK_ACCESS_TRANSFER_READ_BIT; - break; + break; // must only be used as a destination image of a transfer command (11.4) case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: AccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - break; + break; // does not support device access. This layout must only be used as the initialLayout member // of VkImageCreateInfo or VkAttachmentDescription, or as the oldLayout in an image transition. @@ -205,27 +205,27 @@ static VkPipelineStageFlags AccessMaskFromImageLayout(VkImageLayout Layout, } else { - UNEXPECTED("The new layout used in a transition must not be VK_IMAGE_LAYOUT_PREINITIALIZED. " - "This layout must only be used as the initialLayout member of VkImageCreateInfo " + UNEXPECTED("The new layout used in a transition must not be VK_IMAGE_LAYOUT_PREINITIALIZED. " + "This layout must only be used as the initialLayout member of VkImageCreateInfo " "or VkAttachmentDescription, or as the oldLayout in an image transition. (11.4)"); } - break; + break; case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: AccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - break; + break; case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: AccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - break; + break; case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: AccessMask = VK_ACCESS_MEMORY_READ_BIT; - break; + break; default: UNEXPECTED("Unexpected image layout"); - break; + break; } return AccessMask; @@ -237,24 +237,24 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange, VkPipelineStageFlags EnabledGraphicsShaderStages, - VkPipelineStageFlags SrcStages, + VkPipelineStageFlags SrcStages, VkPipelineStageFlags DestStages) { VERIFY_EXPR(CmdBuffer != VK_NULL_HANDLE); VkImageMemoryBarrier ImgBarrier = {}; - ImgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - ImgBarrier.pNext = nullptr; - ImgBarrier.srcAccessMask = 0; - ImgBarrier.dstAccessMask = 0; - ImgBarrier.oldLayout = OldLayout; - ImgBarrier.newLayout = NewLayout; - ImgBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // source queue family for a queue family ownership transfer. - ImgBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // destination queue family for a queue family ownership transfer. - ImgBarrier.image = Image; - ImgBarrier.subresourceRange = SubresRange; - ImgBarrier.srcAccessMask = AccessMaskFromImageLayout(OldLayout, false); - ImgBarrier.dstAccessMask = AccessMaskFromImageLayout(NewLayout, true); + ImgBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + ImgBarrier.pNext = nullptr; + ImgBarrier.srcAccessMask = 0; + ImgBarrier.dstAccessMask = 0; + ImgBarrier.oldLayout = OldLayout; + ImgBarrier.newLayout = NewLayout; + ImgBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // source queue family for a queue family ownership transfer. + ImgBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // destination queue family for a queue family ownership transfer. + ImgBarrier.image = Image; + ImgBarrier.subresourceRange = SubresRange; + ImgBarrier.srcAccessMask = AccessMaskFromImageLayout(OldLayout, false); + ImgBarrier.dstAccessMask = AccessMaskFromImageLayout(NewLayout, true); if (SrcStages == 0) { @@ -264,11 +264,11 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C } else if (ImgBarrier.srcAccessMask != 0) { - SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask, EnabledGraphicsShaderStages); + SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask, EnabledGraphicsShaderStages); } else { - // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage + // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage // mask will effectively not wait for any prior commands to complete. (6.1.2) SrcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; } @@ -286,64 +286,64 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C } else { - // An execution dependency with only VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT in the destination - // stage mask will only prevent that stage from executing in subsequently submitted commands. - // As this stage does not perform any actual execution, this is not observable - in effect, + // An execution dependency with only VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT in the destination + // stage mask will only prevent that stage from executing in subsequently submitted commands. + // As this stage does not perform any actual execution, this is not observable - in effect, // it does not delay processing of subsequent commands. (6.1.2) DestStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; } } - // Including a particular pipeline stage in the first synchronization scope of a command implicitly - // includes logically earlier pipeline stages in the synchronization scope. Similarly, the second + // Including a particular pipeline stage in the first synchronization scope of a command implicitly + // includes logically earlier pipeline stages in the synchronization scope. Similarly, the second // synchronization scope includes logically later pipeline stages. - // However, note that access scopes are not affected in this way - only the precise stages specified + // However, note that access scopes are not affected in this way - only the precise stages specified // are considered part of each access scope. (6.1.2) vkCmdPipelineBarrier(CmdBuffer, - SrcStages, // must not be 0 - DestStages, // must not be 0 - 0, // a bitmask specifying how execution and memory dependencies are formed - 0, // memoryBarrierCount - nullptr, // pMemoryBarriers - 0, // bufferMemoryBarrierCount - nullptr, // pBufferMemoryBarriers - 1, - &ImgBarrier); - // Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not - // have any access flag included in its srcAccessMask member if that bit is not supported by + SrcStages, // must not be 0 + DestStages, // must not be 0 + 0, // a bitmask specifying how execution and memory dependencies are formed + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 0, // bufferMemoryBarrierCount + nullptr, // pBufferMemoryBarriers + 1, + &ImgBarrier); + // Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not + // have any access flag included in its srcAccessMask member if that bit is not supported by // any of the pipeline stages in srcStageMask. - // Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not - // have any access flag included in its dstAccessMask member if that bit is not supported by any + // Each element of pMemoryBarriers, pBufferMemoryBarriers and pImageMemoryBarriers must not + // have any access flag included in its dstAccessMask member if that bit is not supported by any // of the pipeline stages in dstStageMask (6.6) } void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer, - VkBuffer Buffer, + VkBuffer Buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags EnabledGraphicsShaderStages, - VkPipelineStageFlags SrcStages, + VkPipelineStageFlags SrcStages, VkPipelineStageFlags DestStages) { VkBufferMemoryBarrier BuffBarrier = {}; - BuffBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - BuffBarrier.pNext = nullptr; - BuffBarrier.srcAccessMask = srcAccessMask; - BuffBarrier.dstAccessMask = dstAccessMask; - BuffBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - BuffBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - BuffBarrier.buffer = Buffer; - BuffBarrier.offset = 0; - BuffBarrier.size = VK_WHOLE_SIZE; + BuffBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + BuffBarrier.pNext = nullptr; + BuffBarrier.srcAccessMask = srcAccessMask; + BuffBarrier.dstAccessMask = dstAccessMask; + BuffBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + BuffBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + BuffBarrier.buffer = Buffer; + BuffBarrier.offset = 0; + BuffBarrier.size = VK_WHOLE_SIZE; if (SrcStages == 0) { if (BuffBarrier.srcAccessMask != 0) SrcStages = PipelineStageFromAccessFlags(BuffBarrier.srcAccessMask, EnabledGraphicsShaderStages); else { - // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage + // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage // mask will effectively not wait for any prior commands to complete. (6.1.2) SrcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; } @@ -356,20 +356,19 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer, } vkCmdPipelineBarrier(CmdBuffer, - SrcStages, // must not be 0 - DestStages, // must not be 0 - 0, // a bitmask specifying how execution and memory dependencies are formed - 0, // memoryBarrierCount - nullptr, // pMemoryBarriers - 1, // bufferMemoryBarrierCount - &BuffBarrier, // pBufferMemoryBarriers - 0, - nullptr); + SrcStages, // must not be 0 + DestStages, // must not be 0 + 0, // a bitmask specifying how execution and memory dependencies are formed + 0, // memoryBarrierCount + nullptr, // pMemoryBarriers + 1, // bufferMemoryBarrierCount + &BuffBarrier, // pBufferMemoryBarriers + 0, + nullptr); } void VulkanCommandBuffer::FlushBarriers() { - } -} +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp index df90bd6e..5b19da72 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp @@ -30,91 +30,101 @@ namespace VulkanUtilities { - VulkanCommandBufferPool::VulkanCommandBufferPool(std::shared_ptr LogicalDevice, - uint32_t queueFamilyIndex, - VkCommandPoolCreateFlags flags) : - m_LogicalDevice{std::move(LogicalDevice)} - { - VkCommandPoolCreateInfo CmdPoolCI = {}; - CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - CmdPoolCI.pNext = nullptr; - CmdPoolCI.queueFamilyIndex = queueFamilyIndex; - CmdPoolCI.flags = flags; - m_CmdPool = m_LogicalDevice->CreateCommandPool(CmdPoolCI); - DEV_CHECK_ERR(m_CmdPool != VK_NULL_HANDLE, "Failed to create vulkan command pool"); + +VulkanCommandBufferPool::VulkanCommandBufferPool(std::shared_ptr LogicalDevice, + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags) : + m_LogicalDevice{std::move(LogicalDevice)} +{ + VkCommandPoolCreateInfo CmdPoolCI = {}; + + CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + CmdPoolCI.pNext = nullptr; + CmdPoolCI.queueFamilyIndex = queueFamilyIndex; + CmdPoolCI.flags = flags; + + m_CmdPool = m_LogicalDevice->CreateCommandPool(CmdPoolCI); + DEV_CHECK_ERR(m_CmdPool != VK_NULL_HANDLE, "Failed to create vulkan command pool"); #ifdef DEVELOPMENT - m_BuffCounter = 0; + m_BuffCounter = 0; #endif - } +} - VulkanCommandBufferPool::~VulkanCommandBufferPool() - { - m_CmdPool.Release(); - DEV_CHECK_ERR(m_BuffCounter == 0, m_BuffCounter, " command buffer(s) have not been returned to the pool. If there are outstanding references to these buffers in release queues, FreeCommandBuffer() will crash when attempting to return a buffer to the pool."); - } +VulkanCommandBufferPool::~VulkanCommandBufferPool() +{ + m_CmdPool.Release(); + DEV_CHECK_ERR(m_BuffCounter == 0, m_BuffCounter, " command buffer(s) have not been returned to the pool. If there are outstanding references to these buffers in release queues, FreeCommandBuffer() will crash when attempting to return a buffer to the pool."); +} + +VkCommandBuffer VulkanCommandBufferPool::GetCommandBuffer(const char* DebugName) +{ + VkCommandBuffer CmdBuffer = VK_NULL_HANDLE; - VkCommandBuffer VulkanCommandBufferPool::GetCommandBuffer(const char* DebugName) { - VkCommandBuffer CmdBuffer = VK_NULL_HANDLE; + std::lock_guard Lock{m_Mutex}; + if (!m_CmdBuffers.empty()) { - std::lock_guard Lock{m_Mutex}; - - if (!m_CmdBuffers.empty()) - { - CmdBuffer = m_CmdBuffers.front(); - auto err = vkResetCommandBuffer(CmdBuffer, - 0 // VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT - specifies that most or all memory resources currently - // owned by the command buffer should be returned to the parent command pool. - ); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset command buffer"); (void)err; - m_CmdBuffers.pop_front(); - } + CmdBuffer = m_CmdBuffers.front(); + auto err = vkResetCommandBuffer( + CmdBuffer, + 0 // VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT - specifies that most or all memory resources currently + // owned by the command buffer should be returned to the parent command pool. + ); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset command buffer"); + (void)err; + m_CmdBuffers.pop_front(); } + } - // If no cmd buffers were ready to be reused, create a new one - if (CmdBuffer == VK_NULL_HANDLE) - { - VkCommandBufferAllocateInfo BuffAllocInfo = {}; - BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - BuffAllocInfo.pNext = nullptr; - BuffAllocInfo.commandPool = m_CmdPool; - BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - BuffAllocInfo.commandBufferCount = 1; - - CmdBuffer = m_LogicalDevice->AllocateVkCommandBuffer(BuffAllocInfo); - DEV_CHECK_ERR(CmdBuffer != VK_NULL_HANDLE, "Failed to allocate vulkan command buffer"); - } + // If no cmd buffers were ready to be reused, create a new one + if (CmdBuffer == VK_NULL_HANDLE) + { + VkCommandBufferAllocateInfo BuffAllocInfo = {}; + + BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + BuffAllocInfo.pNext = nullptr; + BuffAllocInfo.commandPool = m_CmdPool; + BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + BuffAllocInfo.commandBufferCount = 1; + + CmdBuffer = m_LogicalDevice->AllocateVkCommandBuffer(BuffAllocInfo); + DEV_CHECK_ERR(CmdBuffer != VK_NULL_HANDLE, "Failed to allocate vulkan command buffer"); + } + + VkCommandBufferBeginInfo CmdBuffBeginInfo = {}; - VkCommandBufferBeginInfo CmdBuffBeginInfo = {}; - CmdBuffBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - CmdBuffBeginInfo.pNext = nullptr; - CmdBuffBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; // Each recording of the command buffer will only be - // submitted once, and the command buffer will be reset - // and recorded again between each submission. - CmdBuffBeginInfo.pInheritanceInfo = nullptr; // Ignored for a primary command buffer - auto err = vkBeginCommandBuffer(CmdBuffer, &CmdBuffBeginInfo); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to begin command buffer"); (void)err; + CmdBuffBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + CmdBuffBeginInfo.pNext = nullptr; + CmdBuffBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; // Each recording of the command buffer will only be + // submitted once, and the command buffer will be reset + // and recorded again between each submission. + CmdBuffBeginInfo.pInheritanceInfo = nullptr; // Ignored for a primary command buffer + + auto err = vkBeginCommandBuffer(CmdBuffer, &CmdBuffBeginInfo); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to begin command buffer"); + (void)err; #ifdef DEVELOPMENT - ++m_BuffCounter; + ++m_BuffCounter; #endif - return CmdBuffer; - } + return CmdBuffer; +} - void VulkanCommandBufferPool::FreeCommandBuffer(VkCommandBuffer&& CmdBuffer) - { - std::lock_guard Lock{m_Mutex}; - m_CmdBuffers.emplace_back(CmdBuffer); - CmdBuffer = VK_NULL_HANDLE; +void VulkanCommandBufferPool::FreeCommandBuffer(VkCommandBuffer&& CmdBuffer) +{ + std::lock_guard Lock{m_Mutex}; + m_CmdBuffers.emplace_back(CmdBuffer); + CmdBuffer = VK_NULL_HANDLE; #ifdef DEVELOPMENT - --m_BuffCounter; + --m_BuffCounter; #endif - } +} - CommandPoolWrapper&& VulkanCommandBufferPool::Release() - { - m_LogicalDevice.reset(); - m_CmdBuffers.clear(); - return std::move(m_CmdPool); - } +CommandPoolWrapper&& VulkanCommandBufferPool::Release() +{ + m_LogicalDevice.reset(); + m_CmdBuffers.clear(); + return std::move(m_CmdPool); } + +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp index a5a71d01..c4781196 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp @@ -17,615 +17,639 @@ namespace VulkanUtilities { - static PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr; - static PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr; - static PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr; - static PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT = nullptr; - static PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT = nullptr; - static PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT = nullptr; - static PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT = nullptr; - static PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr; - static PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr; - static PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT = nullptr; - - static VkDebugUtilsMessengerEXT DbgMessenger = VK_NULL_HANDLE; - - VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* callbackData, - void* userData) - { - std::stringstream debugMessage; - // Ignore some validation messages - if ((messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) - { - { - // UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw: - // vkCmdClearAttachments() issued on command buffer object 0x... prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw. - static const char* ClearCmdBeforeDrawIdName = "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw"; - constexpr int32_t DeprecatedClearCmdBeforeDrawIdNumber = 64; // Starting with sdk version 1.1.85, messageIdNumber is 0 for all messages - if ((callbackData->pMessageIdName != nullptr && strcmp(callbackData->pMessageIdName, ClearCmdBeforeDrawIdName) == 0) || callbackData->messageIdNumber == DeprecatedClearCmdBeforeDrawIdNumber) - return VK_FALSE; - } - } - - Diligent::DebugMessageSeverity MsgSeverity = Diligent::DebugMessageSeverity::Info; - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) - { - MsgSeverity = Diligent::DebugMessageSeverity::Info; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) - { - MsgSeverity = Diligent::DebugMessageSeverity::Info; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) - { - MsgSeverity = Diligent::DebugMessageSeverity::Warning; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) - { - MsgSeverity = Diligent::DebugMessageSeverity::Error; - } - else - { - MsgSeverity = Diligent::DebugMessageSeverity::Info; - } - - debugMessage << "Vulkan debug message ("; - if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) - { - debugMessage << "general"; - if (messageType & (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) - debugMessage << ", "; - } - if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) - { - debugMessage << "validation"; - if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) - debugMessage << ", "; - } - if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) - debugMessage << "performance"; - debugMessage << "): "; - - // callbackData->messageIdNumber is deprecated and starting with version 1.1.85 it is always 0 - debugMessage << (callbackData->pMessageIdName != nullptr ? callbackData->pMessageIdName : ""); - if (callbackData->pMessage != nullptr) - { - debugMessage << std::endl << " " << callbackData->pMessage; - } - - if (callbackData->objectCount > 0) - { - for (uint32_t obj = 0; obj < callbackData->objectCount; ++obj) - { - const auto& Object = callbackData->pObjects[obj]; - debugMessage << std::endl << " Object[" << obj << "] (" << VkObjectTypeToString(Object.objectType) - << "): Handle " << std::hex << "0x" << Object.objectHandle; - if (Object.pObjectName != nullptr) - { - debugMessage << ", Name: '" << Object.pObjectName << '\''; - } - } - } +static PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT = nullptr; +static PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT = nullptr; +static PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT = nullptr; +static PFN_vkSetDebugUtilsObjectTagEXT SetDebugUtilsObjectTagEXT = nullptr; +static PFN_vkQueueBeginDebugUtilsLabelEXT QueueBeginDebugUtilsLabelEXT = nullptr; +static PFN_vkQueueEndDebugUtilsLabelEXT QueueEndDebugUtilsLabelEXT = nullptr; +static PFN_vkQueueInsertDebugUtilsLabelEXT QueueInsertDebugUtilsLabelEXT = nullptr; +static PFN_vkCmdBeginDebugUtilsLabelEXT CmdBeginDebugUtilsLabelEXT = nullptr; +static PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT = nullptr; +static PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT = nullptr; + +static VkDebugUtilsMessengerEXT DbgMessenger = VK_NULL_HANDLE; + +VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* callbackData, + void* userData) +{ + std::stringstream debugMessage; - if (callbackData->cmdBufLabelCount > 0) + // Ignore some validation messages + if ((messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) + { { - for (uint32_t l = 0; l < callbackData->cmdBufLabelCount; ++l) - { - const auto& Label = callbackData->pCmdBufLabels[l]; - debugMessage << std::endl << " Label[" << l << "]"; - if (Label.pLabelName != nullptr) - { - debugMessage << " - " << Label.pLabelName; - } - debugMessage << " {"; - debugMessage << std::fixed << std::setw(4) << Label.color[0] << ", " - << std::fixed << std::setw(4) << Label.color[1] << ", " - << std::fixed << std::setw(4) << Label.color[2] << ", " - << std::fixed << std::setw(4) << Label.color[3] << "}"; - } + // UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw: + // vkCmdClearAttachments() issued on command buffer object 0x... prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw. + static const char* ClearCmdBeforeDrawIdName = "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw"; + constexpr int32_t DeprecatedClearCmdBeforeDrawIdNumber = 64; // Starting with sdk version 1.1.85, messageIdNumber is 0 for all messages + if ((callbackData->pMessageIdName != nullptr && strcmp(callbackData->pMessageIdName, ClearCmdBeforeDrawIdName) == 0) || callbackData->messageIdNumber == DeprecatedClearCmdBeforeDrawIdNumber) + return VK_FALSE; } - - LOG_DEBUG_MESSAGE(MsgSeverity, debugMessage.str().c_str()); - - // The return value of this callback controls wether the Vulkan call that caused - // the validation message will be aborted or not - // We return VK_FALSE as we DON'T want Vulkan calls that cause a validation message - // (and return a VkResult) to abort - return VK_FALSE; } - - void SetupDebugging(VkInstance instance, - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - void* pUserData) + Diligent::DebugMessageSeverity MsgSeverity = Diligent::DebugMessageSeverity::Info; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { - CreateDebugUtilsMessengerEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); - DestroyDebugUtilsMessengerEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT")); - VERIFY_EXPR(CreateDebugUtilsMessengerEXT != nullptr && DestroyDebugUtilsMessengerEXT != nullptr); - - VkDebugUtilsMessengerCreateInfoEXT DbgMessenger_CI = {}; - DbgMessenger_CI.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - DbgMessenger_CI.pNext = NULL; - DbgMessenger_CI.flags = 0; - DbgMessenger_CI.messageSeverity = messageSeverity; - DbgMessenger_CI.messageType = messageType; - DbgMessenger_CI.pfnUserCallback = DebugMessengerCallback; - DbgMessenger_CI.pUserData = pUserData; - VkResult err = CreateDebugUtilsMessengerEXT(instance, &DbgMessenger_CI, nullptr, &DbgMessenger); - VERIFY(err == VK_SUCCESS, "Failed to create debug utils messenger"); (void)err; - - // Load function pointers - SetDebugUtilsObjectNameEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT")); - VERIFY_EXPR(SetDebugUtilsObjectNameEXT != nullptr); - SetDebugUtilsObjectTagEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectTagEXT")); - VERIFY_EXPR(SetDebugUtilsObjectTagEXT != nullptr); - - QueueBeginDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT")); - VERIFY_EXPR(QueueBeginDebugUtilsLabelEXT != nullptr); - QueueEndDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT")); - VERIFY_EXPR(QueueEndDebugUtilsLabelEXT != nullptr); - QueueInsertDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkQueueInsertDebugUtilsLabelEXT")); - VERIFY_EXPR(QueueInsertDebugUtilsLabelEXT != nullptr); - - CmdBeginDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT")); - VERIFY_EXPR(CmdBeginDebugUtilsLabelEXT != nullptr); - CmdEndDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT")); - VERIFY_EXPR(CmdEndDebugUtilsLabelEXT != nullptr); - CmdInsertDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT")); - VERIFY_EXPR(CmdInsertDebugUtilsLabelEXT != nullptr); + MsgSeverity = Diligent::DebugMessageSeverity::Info; } - - void FreeDebugging(VkInstance instance) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { - if (DbgMessenger != VK_NULL_HANDLE) - { - DestroyDebugUtilsMessengerEXT(instance, DbgMessenger, nullptr); - } + MsgSeverity = Diligent::DebugMessageSeverity::Info; } - - void BeginCmdQueueLabelRegion(VkQueue cmdQueue, const char* pLabelName, const float* color) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { - VkDebugUtilsLabelEXT Label = {}; - Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - Label.pNext = nullptr; - Label.pLabelName = pLabelName; - for(int i=0; i < 4; ++i) - Label.color[i] = color[i]; - QueueBeginDebugUtilsLabelEXT(cmdQueue, &Label); + MsgSeverity = Diligent::DebugMessageSeverity::Warning; } - - void InsertCmdQueueLabel(VkQueue cmdQueue, const char* pLabelName, const float* color) + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { - VkDebugUtilsLabelEXT Label = {}; - Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - Label.pNext = nullptr; - Label.pLabelName = pLabelName; - for(int i=0; i < 4; ++i) - Label.color[i] = color[i]; - QueueInsertDebugUtilsLabelEXT(cmdQueue, &Label); + MsgSeverity = Diligent::DebugMessageSeverity::Error; } - - void EndCmdQueueLabelRegion(VkQueue cmdQueue) + else { - QueueEndDebugUtilsLabelEXT(cmdQueue); + MsgSeverity = Diligent::DebugMessageSeverity::Info; } - - // Start a new label region - void BeginCmdBufferLabelRegion(VkCommandBuffer cmdBuffer, const char* pLabelName, const float* color) + debugMessage << "Vulkan debug message ("; + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { - VkDebugUtilsLabelEXT Label = {}; - Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - Label.pNext = nullptr; - Label.pLabelName = pLabelName; - for(int i=0; i < 4; ++i) - Label.color[i] = color[i]; - CmdBeginDebugUtilsLabelEXT(cmdBuffer, &Label); + debugMessage << "general"; + if (messageType & (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) + debugMessage << ", "; } - - // End the label region - void EndCmdBufferLabelRegion(VkCommandBuffer cmdBuffer) + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { - CmdEndDebugUtilsLabelEXT(cmdBuffer); + debugMessage << "validation"; + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + debugMessage << ", "; } + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + debugMessage << "performance"; + debugMessage << "): "; - // Start a single label - void InsertCmdBufferLabel(VkCommandBuffer cmdBuffer, const char* pLabelName, const float* color) + // callbackData->messageIdNumber is deprecated and starting with version 1.1.85 it is always 0 + debugMessage << (callbackData->pMessageIdName != nullptr ? callbackData->pMessageIdName : ""); + if (callbackData->pMessage != nullptr) { - VkDebugUtilsLabelEXT Label = {}; - Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - Label.pNext = nullptr; - Label.pLabelName = pLabelName; - for(int i=0; i < 4; ++i) - Label.color[i] = color[i]; - CmdInsertDebugUtilsLabelEXT(cmdBuffer, &Label); + debugMessage << std::endl + << " " << callbackData->pMessage; } - - void SetObjectName(VkDevice device, uint64_t objectHandle, VkObjectType objectType, const char *name) + if (callbackData->objectCount > 0) { - // Check for valid function pointer (may not be present if not running in a debugging application) - if (SetDebugUtilsObjectNameEXT != nullptr && name != nullptr && *name != 0) + for (uint32_t obj = 0; obj < callbackData->objectCount; ++obj) { - VkDebugUtilsObjectNameInfoEXT ObjectNameInfo = {}; - ObjectNameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - ObjectNameInfo.pNext = nullptr; - ObjectNameInfo.objectType = objectType; - ObjectNameInfo.objectHandle = objectHandle; - ObjectNameInfo.pObjectName = name; - VkResult res = SetDebugUtilsObjectNameEXT(device, &ObjectNameInfo); - VERIFY_EXPR(res == VK_SUCCESS); (void)res; + const auto& Object = callbackData->pObjects[obj]; + debugMessage << std::endl + << " Object[" << obj << "] (" << VkObjectTypeToString(Object.objectType) + << "): Handle " << std::hex << "0x" << Object.objectHandle; + if (Object.pObjectName != nullptr) + { + debugMessage << ", Name: '" << Object.pObjectName << '\''; + } } } - void SetObjectTag(VkDevice device, uint64_t objectHandle, VkObjectType objectType, uint64_t name, size_t tagSize, const void* tag) + if (callbackData->cmdBufLabelCount > 0) { - // Check for valid function pointer (may not be present if not running in a debugging application) - if (SetDebugUtilsObjectTagEXT) + for (uint32_t l = 0; l < callbackData->cmdBufLabelCount; ++l) { - VkDebugUtilsObjectTagInfoEXT tagInfo = {}; - tagInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT; - tagInfo.pNext = nullptr; - tagInfo.objectType = objectType; - tagInfo.objectHandle = objectHandle; - tagInfo.tagName = name; - tagInfo.tagSize = tagSize; - tagInfo.pTag = tag; - SetDebugUtilsObjectTagEXT(device, &tagInfo); + const auto& Label = callbackData->pCmdBufLabels[l]; + debugMessage << std::endl + << " Label[" << l << "]"; + if (Label.pLabelName != nullptr) + { + debugMessage << " - " << Label.pLabelName; + } + debugMessage << " {"; + debugMessage << std::fixed << std::setw(4) << Label.color[0] << ", " + << std::fixed << std::setw(4) << Label.color[1] << ", " + << std::fixed << std::setw(4) << Label.color[2] << ", " + << std::fixed << std::setw(4) << Label.color[3] << "}"; } } - void SetCommandPoolName(VkDevice device, VkCommandPool cmdPool, const char * name) - { - SetObjectName(device, (uint64_t)cmdPool, VK_OBJECT_TYPE_COMMAND_POOL, name); - } + LOG_DEBUG_MESSAGE(MsgSeverity, debugMessage.str().c_str()); - void SetCommandBufferName(VkDevice device, VkCommandBuffer cmdBuffer, const char * name) - { - SetObjectName(device, (uint64_t)cmdBuffer, VK_OBJECT_TYPE_COMMAND_BUFFER, name); - } + // The return value of this callback controls wether the Vulkan call that caused + // the validation message will be aborted or not + // We return VK_FALSE as we DON'T want Vulkan calls that cause a validation message + // (and return a VkResult) to abort + return VK_FALSE; +} - void SetQueueName(VkDevice device, VkQueue queue, const char * name) - { - SetObjectName(device, (uint64_t)queue, VK_OBJECT_TYPE_QUEUE, name); - } - void SetImageName(VkDevice device, VkImage image, const char * name) - { - SetObjectName(device, (uint64_t)image, VK_OBJECT_TYPE_IMAGE, name); - } +void SetupDebugging(VkInstance instance, + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + void* pUserData) +{ + CreateDebugUtilsMessengerEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); + DestroyDebugUtilsMessengerEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT")); + VERIFY_EXPR(CreateDebugUtilsMessengerEXT != nullptr && DestroyDebugUtilsMessengerEXT != nullptr); + + VkDebugUtilsMessengerCreateInfoEXT DbgMessenger_CI = {}; + + DbgMessenger_CI.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + DbgMessenger_CI.pNext = NULL; + DbgMessenger_CI.flags = 0; + DbgMessenger_CI.messageSeverity = messageSeverity; + DbgMessenger_CI.messageType = messageType; + DbgMessenger_CI.pfnUserCallback = DebugMessengerCallback; + DbgMessenger_CI.pUserData = pUserData; + + VkResult err = CreateDebugUtilsMessengerEXT(instance, &DbgMessenger_CI, nullptr, &DbgMessenger); + VERIFY(err == VK_SUCCESS, "Failed to create debug utils messenger"); + (void)err; + + // Load function pointers + SetDebugUtilsObjectNameEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectNameEXT")); + VERIFY_EXPR(SetDebugUtilsObjectNameEXT != nullptr); + SetDebugUtilsObjectTagEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkSetDebugUtilsObjectTagEXT")); + VERIFY_EXPR(SetDebugUtilsObjectTagEXT != nullptr); + + QueueBeginDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkQueueBeginDebugUtilsLabelEXT")); + VERIFY_EXPR(QueueBeginDebugUtilsLabelEXT != nullptr); + QueueEndDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkQueueEndDebugUtilsLabelEXT")); + VERIFY_EXPR(QueueEndDebugUtilsLabelEXT != nullptr); + QueueInsertDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkQueueInsertDebugUtilsLabelEXT")); + VERIFY_EXPR(QueueInsertDebugUtilsLabelEXT != nullptr); + + CmdBeginDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBeginDebugUtilsLabelEXT")); + VERIFY_EXPR(CmdBeginDebugUtilsLabelEXT != nullptr); + CmdEndDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdEndDebugUtilsLabelEXT")); + VERIFY_EXPR(CmdEndDebugUtilsLabelEXT != nullptr); + CmdInsertDebugUtilsLabelEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdInsertDebugUtilsLabelEXT")); + VERIFY_EXPR(CmdInsertDebugUtilsLabelEXT != nullptr); +} - void SetImageViewName(VkDevice device, VkImageView imageView, const char * name) +void FreeDebugging(VkInstance instance) +{ + if (DbgMessenger != VK_NULL_HANDLE) { - SetObjectName(device, (uint64_t)imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); + DestroyDebugUtilsMessengerEXT(instance, DbgMessenger, nullptr); } +} - void SetSamplerName(VkDevice device, VkSampler sampler, const char * name) - { - SetObjectName(device, (uint64_t)sampler, VK_OBJECT_TYPE_SAMPLER, name); - } +void BeginCmdQueueLabelRegion(VkQueue cmdQueue, const char* pLabelName, const float* color) +{ + VkDebugUtilsLabelEXT Label = {}; + + Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + Label.pNext = nullptr; + Label.pLabelName = pLabelName; + for (int i = 0; i < 4; ++i) + Label.color[i] = color[i]; + QueueBeginDebugUtilsLabelEXT(cmdQueue, &Label); +} - void SetBufferName(VkDevice device, VkBuffer buffer, const char * name) - { - SetObjectName(device, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER, name); - } +void InsertCmdQueueLabel(VkQueue cmdQueue, const char* pLabelName, const float* color) +{ + VkDebugUtilsLabelEXT Label = {}; + + Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + Label.pNext = nullptr; + Label.pLabelName = pLabelName; + for (int i = 0; i < 4; ++i) + Label.color[i] = color[i]; + QueueInsertDebugUtilsLabelEXT(cmdQueue, &Label); +} - void SetBufferViewName(VkDevice device, VkBufferView bufferView, const char * name) - { - SetObjectName(device, (uint64_t)bufferView, VK_OBJECT_TYPE_BUFFER_VIEW, name); - } +void EndCmdQueueLabelRegion(VkQueue cmdQueue) +{ + QueueEndDebugUtilsLabelEXT(cmdQueue); +} - void SetDeviceMemoryName(VkDevice device, VkDeviceMemory memory, const char * name) - { - SetObjectName(device, (uint64_t)memory, VK_OBJECT_TYPE_DEVICE_MEMORY, name); - } - void SetShaderModuleName(VkDevice device, VkShaderModule shaderModule, const char * name) - { - SetObjectName(device, (uint64_t)shaderModule, VK_OBJECT_TYPE_SHADER_MODULE, name); - } +// Start a new label region +void BeginCmdBufferLabelRegion(VkCommandBuffer cmdBuffer, const char* pLabelName, const float* color) +{ + VkDebugUtilsLabelEXT Label = {}; + + Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + Label.pNext = nullptr; + Label.pLabelName = pLabelName; + for (int i = 0; i < 4; ++i) + Label.color[i] = color[i]; + CmdBeginDebugUtilsLabelEXT(cmdBuffer, &Label); +} - void SetPipelineName(VkDevice device, VkPipeline pipeline, const char * name) - { - SetObjectName(device, (uint64_t)pipeline, VK_OBJECT_TYPE_PIPELINE, name); - } +// End the label region +void EndCmdBufferLabelRegion(VkCommandBuffer cmdBuffer) +{ + CmdEndDebugUtilsLabelEXT(cmdBuffer); +} - void SetPipelineLayoutName(VkDevice device, VkPipelineLayout pipelineLayout, const char * name) - { - SetObjectName(device, (uint64_t)pipelineLayout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, name); - } +// Start a single label +void InsertCmdBufferLabel(VkCommandBuffer cmdBuffer, const char* pLabelName, const float* color) +{ + VkDebugUtilsLabelEXT Label = {}; + + Label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + Label.pNext = nullptr; + Label.pLabelName = pLabelName; + for (int i = 0; i < 4; ++i) + Label.color[i] = color[i]; + CmdInsertDebugUtilsLabelEXT(cmdBuffer, &Label); +} - void SetRenderPassName(VkDevice device, VkRenderPass renderPass, const char * name) - { - SetObjectName(device, (uint64_t)renderPass, VK_OBJECT_TYPE_RENDER_PASS, name); - } - void SetFramebufferName(VkDevice device, VkFramebuffer framebuffer, const char * name) +void SetObjectName(VkDevice device, uint64_t objectHandle, VkObjectType objectType, const char* name) +{ + // Check for valid function pointer (may not be present if not running in a debugging application) + if (SetDebugUtilsObjectNameEXT != nullptr && name != nullptr && *name != 0) { - SetObjectName(device, (uint64_t)framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER, name); - } + VkDebugUtilsObjectNameInfoEXT ObjectNameInfo = {}; - void SetDescriptorSetLayoutName(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char * name) - { - SetObjectName(device, (uint64_t)descriptorSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, name); - } + ObjectNameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + ObjectNameInfo.pNext = nullptr; + ObjectNameInfo.objectType = objectType; + ObjectNameInfo.objectHandle = objectHandle; + ObjectNameInfo.pObjectName = name; - void SetDescriptorSetName(VkDevice device, VkDescriptorSet descriptorSet, const char * name) - { - SetObjectName(device, (uint64_t)descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, name); + VkResult res = SetDebugUtilsObjectNameEXT(device, &ObjectNameInfo); + VERIFY_EXPR(res == VK_SUCCESS); + (void)res; } +} - void SetDescriptorPoolName(VkDevice device, VkDescriptorPool descriptorPool, const char * name) +void SetObjectTag(VkDevice device, uint64_t objectHandle, VkObjectType objectType, uint64_t name, size_t tagSize, const void* tag) +{ + // Check for valid function pointer (may not be present if not running in a debugging application) + if (SetDebugUtilsObjectTagEXT) { - SetObjectName(device, (uint64_t)descriptorPool, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name); - } + VkDebugUtilsObjectTagInfoEXT tagInfo = {}; - void SetSemaphoreName(VkDevice device, VkSemaphore semaphore, const char * name) - { - SetObjectName(device, (uint64_t)semaphore, VK_OBJECT_TYPE_SEMAPHORE, name); + tagInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT; + tagInfo.pNext = nullptr; + tagInfo.objectType = objectType; + tagInfo.objectHandle = objectHandle; + tagInfo.tagName = name; + tagInfo.tagSize = tagSize; + tagInfo.pTag = tag; + SetDebugUtilsObjectTagEXT(device, &tagInfo); } +} - void SetFenceName(VkDevice device, VkFence fence, const char * name) - { - SetObjectName(device, (uint64_t)fence, VK_OBJECT_TYPE_FENCE, name); - } +void SetCommandPoolName(VkDevice device, VkCommandPool cmdPool, const char* name) +{ + SetObjectName(device, (uint64_t)cmdPool, VK_OBJECT_TYPE_COMMAND_POOL, name); +} - void SetEventName(VkDevice device, VkEvent _event, const char * name) - { - SetObjectName(device, (uint64_t)_event, VK_OBJECT_TYPE_EVENT, name); - } +void SetCommandBufferName(VkDevice device, VkCommandBuffer cmdBuffer, const char* name) +{ + SetObjectName(device, (uint64_t)cmdBuffer, VK_OBJECT_TYPE_COMMAND_BUFFER, name); +} +void SetQueueName(VkDevice device, VkQueue queue, const char* name) +{ + SetObjectName(device, (uint64_t)queue, VK_OBJECT_TYPE_QUEUE, name); +} +void SetImageName(VkDevice device, VkImage image, const char* name) +{ + SetObjectName(device, (uint64_t)image, VK_OBJECT_TYPE_IMAGE, name); +} +void SetImageViewName(VkDevice device, VkImageView imageView, const char* name) +{ + SetObjectName(device, (uint64_t)imageView, VK_OBJECT_TYPE_IMAGE_VIEW, name); +} - void SetVulkanObjectName(VkDevice device, VkCommandPool cmdPool, const char * name) - { - SetCommandPoolName(device, cmdPool, name); - } +void SetSamplerName(VkDevice device, VkSampler sampler, const char* name) +{ + SetObjectName(device, (uint64_t)sampler, VK_OBJECT_TYPE_SAMPLER, name); +} - void SetVulkanObjectName(VkDevice device, VkCommandBuffer cmdBuffer, const char * name) - { - SetCommandBufferName(device, cmdBuffer, name); - } +void SetBufferName(VkDevice device, VkBuffer buffer, const char* name) +{ + SetObjectName(device, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER, name); +} - void SetVulkanObjectName(VkDevice device, VkQueue queue, const char * name) - { - SetQueueName(device, queue, name); - } +void SetBufferViewName(VkDevice device, VkBufferView bufferView, const char* name) +{ + SetObjectName(device, (uint64_t)bufferView, VK_OBJECT_TYPE_BUFFER_VIEW, name); +} - void SetVulkanObjectName(VkDevice device, VkImage image, const char * name) - { - SetImageName(device, image, name); - } +void SetDeviceMemoryName(VkDevice device, VkDeviceMemory memory, const char* name) +{ + SetObjectName(device, (uint64_t)memory, VK_OBJECT_TYPE_DEVICE_MEMORY, name); +} - void SetVulkanObjectName(VkDevice device, VkImageView imageView, const char * name) - { - SetImageViewName(device, imageView, name); - } +void SetShaderModuleName(VkDevice device, VkShaderModule shaderModule, const char* name) +{ + SetObjectName(device, (uint64_t)shaderModule, VK_OBJECT_TYPE_SHADER_MODULE, name); +} - void SetVulkanObjectName(VkDevice device, VkSampler sampler, const char * name) - { - SetSamplerName(device, sampler, name); - } +void SetPipelineName(VkDevice device, VkPipeline pipeline, const char* name) +{ + SetObjectName(device, (uint64_t)pipeline, VK_OBJECT_TYPE_PIPELINE, name); +} - void SetVulkanObjectName(VkDevice device, VkBuffer buffer, const char * name) - { - SetBufferName(device, buffer, name); - } +void SetPipelineLayoutName(VkDevice device, VkPipelineLayout pipelineLayout, const char* name) +{ + SetObjectName(device, (uint64_t)pipelineLayout, VK_OBJECT_TYPE_PIPELINE_LAYOUT, name); +} - void SetVulkanObjectName(VkDevice device, VkBufferView bufferView, const char * name) - { - SetBufferViewName(device, bufferView, name); - } +void SetRenderPassName(VkDevice device, VkRenderPass renderPass, const char* name) +{ + SetObjectName(device, (uint64_t)renderPass, VK_OBJECT_TYPE_RENDER_PASS, name); +} - void SetVulkanObjectName(VkDevice device, VkDeviceMemory memory, const char * name) - { - SetDeviceMemoryName(device, memory, name); - } +void SetFramebufferName(VkDevice device, VkFramebuffer framebuffer, const char* name) +{ + SetObjectName(device, (uint64_t)framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER, name); +} - void SetVulkanObjectName(VkDevice device, VkShaderModule shaderModule, const char * name) - { - SetShaderModuleName(device, shaderModule, name); - } +void SetDescriptorSetLayoutName(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* name) +{ + SetObjectName(device, (uint64_t)descriptorSetLayout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, name); +} - void SetVulkanObjectName(VkDevice device, VkPipeline pipeline, const char * name) - { - SetPipelineName(device, pipeline, name); - } +void SetDescriptorSetName(VkDevice device, VkDescriptorSet descriptorSet, const char* name) +{ + SetObjectName(device, (uint64_t)descriptorSet, VK_OBJECT_TYPE_DESCRIPTOR_SET, name); +} - void SetVulkanObjectName(VkDevice device, VkPipelineLayout pipelineLayout, const char * name) - { - SetPipelineLayoutName(device, pipelineLayout, name); - } +void SetDescriptorPoolName(VkDevice device, VkDescriptorPool descriptorPool, const char* name) +{ + SetObjectName(device, (uint64_t)descriptorPool, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name); +} - void SetVulkanObjectName(VkDevice device, VkRenderPass renderPass, const char * name) - { - SetRenderPassName(device, renderPass, name); - } +void SetSemaphoreName(VkDevice device, VkSemaphore semaphore, const char* name) +{ + SetObjectName(device, (uint64_t)semaphore, VK_OBJECT_TYPE_SEMAPHORE, name); +} - void SetVulkanObjectName(VkDevice device, VkFramebuffer framebuffer, const char * name) - { - SetFramebufferName(device, framebuffer, name); - } +void SetFenceName(VkDevice device, VkFence fence, const char* name) +{ + SetObjectName(device, (uint64_t)fence, VK_OBJECT_TYPE_FENCE, name); +} - void SetVulkanObjectName(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char * name) - { - SetDescriptorSetLayoutName(device, descriptorSetLayout, name); - } +void SetEventName(VkDevice device, VkEvent _event, const char* name) +{ + SetObjectName(device, (uint64_t)_event, VK_OBJECT_TYPE_EVENT, name); +} - void SetVulkanObjectName(VkDevice device, VkDescriptorSet descriptorSet, const char * name) - { - SetDescriptorSetName(device, descriptorSet, name); - } - void SetVulkanObjectName(VkDevice device, VkDescriptorPool descriptorPool, const char * name) - { - SetDescriptorPoolName(device, descriptorPool, name); - } - void SetVulkanObjectName(VkDevice device, VkSemaphore semaphore, const char * name) - { - SetSemaphoreName(device, semaphore, name); - } - void SetVulkanObjectName(VkDevice device, VkFence fence, const char * name) - { - SetFenceName(device, fence, name); - } +void SetVulkanObjectName(VkDevice device, VkCommandPool cmdPool, const char* name) +{ + SetCommandPoolName(device, cmdPool, name); +} - void SetVulkanObjectName(VkDevice device, VkEvent _event, const char * name) - { - SetEventName(device, _event, name); - } - +void SetVulkanObjectName(VkDevice device, VkCommandBuffer cmdBuffer, const char* name) +{ + SetCommandBufferName(device, cmdBuffer, name); +} + +void SetVulkanObjectName(VkDevice device, VkQueue queue, const char* name) +{ + SetQueueName(device, queue, name); +} + +void SetVulkanObjectName(VkDevice device, VkImage image, const char* name) +{ + SetImageName(device, image, name); +} + +void SetVulkanObjectName(VkDevice device, VkImageView imageView, const char* name) +{ + SetImageViewName(device, imageView, name); +} + +void SetVulkanObjectName(VkDevice device, VkSampler sampler, const char* name) +{ + SetSamplerName(device, sampler, name); +} + +void SetVulkanObjectName(VkDevice device, VkBuffer buffer, const char* name) +{ + SetBufferName(device, buffer, name); +} + +void SetVulkanObjectName(VkDevice device, VkBufferView bufferView, const char* name) +{ + SetBufferViewName(device, bufferView, name); +} + +void SetVulkanObjectName(VkDevice device, VkDeviceMemory memory, const char* name) +{ + SetDeviceMemoryName(device, memory, name); +} + +void SetVulkanObjectName(VkDevice device, VkShaderModule shaderModule, const char* name) +{ + SetShaderModuleName(device, shaderModule, name); +} + +void SetVulkanObjectName(VkDevice device, VkPipeline pipeline, const char* name) +{ + SetPipelineName(device, pipeline, name); +} + +void SetVulkanObjectName(VkDevice device, VkPipelineLayout pipelineLayout, const char* name) +{ + SetPipelineLayoutName(device, pipelineLayout, name); +} + +void SetVulkanObjectName(VkDevice device, VkRenderPass renderPass, const char* name) +{ + SetRenderPassName(device, renderPass, name); +} + +void SetVulkanObjectName(VkDevice device, VkFramebuffer framebuffer, const char* name) +{ + SetFramebufferName(device, framebuffer, name); +} + +void SetVulkanObjectName(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const char* name) +{ + SetDescriptorSetLayoutName(device, descriptorSetLayout, name); +} + +void SetVulkanObjectName(VkDevice device, VkDescriptorSet descriptorSet, const char* name) +{ + SetDescriptorSetName(device, descriptorSet, name); +} + +void SetVulkanObjectName(VkDevice device, VkDescriptorPool descriptorPool, const char* name) +{ + SetDescriptorPoolName(device, descriptorPool, name); +} +void SetVulkanObjectName(VkDevice device, VkSemaphore semaphore, const char* name) +{ + SetSemaphoreName(device, semaphore, name); +} - const char* VkResultToString(VkResult errorCode) +void SetVulkanObjectName(VkDevice device, VkFence fence, const char* name) +{ + SetFenceName(device, fence, name); +} + +void SetVulkanObjectName(VkDevice device, VkEvent _event, const char* name) +{ + SetEventName(device, _event, name); +} + + + +const char* VkResultToString(VkResult errorCode) +{ + switch (errorCode) { - switch (errorCode) - { + // clang-format off #define STR(r) case VK_ ##r: return #r - STR(NOT_READY); - STR(TIMEOUT); - STR(EVENT_SET); - STR(EVENT_RESET); - STR(INCOMPLETE); - STR(ERROR_OUT_OF_HOST_MEMORY); - STR(ERROR_OUT_OF_DEVICE_MEMORY); - STR(ERROR_INITIALIZATION_FAILED); - STR(ERROR_DEVICE_LOST); - STR(ERROR_MEMORY_MAP_FAILED); - STR(ERROR_LAYER_NOT_PRESENT); - STR(ERROR_EXTENSION_NOT_PRESENT); - STR(ERROR_FEATURE_NOT_PRESENT); - STR(ERROR_INCOMPATIBLE_DRIVER); - STR(ERROR_TOO_MANY_OBJECTS); - STR(ERROR_FORMAT_NOT_SUPPORTED); - STR(ERROR_SURFACE_LOST_KHR); - STR(ERROR_NATIVE_WINDOW_IN_USE_KHR); - STR(SUBOPTIMAL_KHR); - STR(ERROR_OUT_OF_DATE_KHR); - STR(ERROR_INCOMPATIBLE_DISPLAY_KHR); - STR(ERROR_VALIDATION_FAILED_EXT); - STR(ERROR_INVALID_SHADER_NV); + STR(NOT_READY); + STR(TIMEOUT); + STR(EVENT_SET); + STR(EVENT_RESET); + STR(INCOMPLETE); + STR(ERROR_OUT_OF_HOST_MEMORY); + STR(ERROR_OUT_OF_DEVICE_MEMORY); + STR(ERROR_INITIALIZATION_FAILED); + STR(ERROR_DEVICE_LOST); + STR(ERROR_MEMORY_MAP_FAILED); + STR(ERROR_LAYER_NOT_PRESENT); + STR(ERROR_EXTENSION_NOT_PRESENT); + STR(ERROR_FEATURE_NOT_PRESENT); + STR(ERROR_INCOMPATIBLE_DRIVER); + STR(ERROR_TOO_MANY_OBJECTS); + STR(ERROR_FORMAT_NOT_SUPPORTED); + STR(ERROR_SURFACE_LOST_KHR); + STR(ERROR_NATIVE_WINDOW_IN_USE_KHR); + STR(SUBOPTIMAL_KHR); + STR(ERROR_OUT_OF_DATE_KHR); + STR(ERROR_INCOMPATIBLE_DISPLAY_KHR); + STR(ERROR_VALIDATION_FAILED_EXT); + STR(ERROR_INVALID_SHADER_NV); #undef STR + // clang-format on default: return "UNKNOWN_ERROR"; - } } +} - const char* VkAccessFlagBitToString(VkAccessFlagBits Bit) +const char* VkAccessFlagBitToString(VkAccessFlagBits Bit) +{ + VERIFY(Bit != 0 && (Bit & (Bit - 1)) == 0, "Single bit is expected"); + switch (Bit) { - VERIFY(Bit != 0 && (Bit & (Bit-1)) == 0, "Single bit is expected"); - switch(Bit) - { + // clang-format off #define ACCESS_FLAG_BIT_TO_STRING(ACCESS_FLAG_BIT)case ACCESS_FLAG_BIT: return #ACCESS_FLAG_BIT; - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_INDIRECT_COMMAND_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_INDEX_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_UNIFORM_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_SHADER_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_SHADER_WRITE_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_TRANSFER_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_TRANSFER_WRITE_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_HOST_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_HOST_WRITE_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_MEMORY_READ_BIT) - ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_MEMORY_WRITE_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_INDIRECT_COMMAND_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_INDEX_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_UNIFORM_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_SHADER_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_SHADER_WRITE_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_TRANSFER_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_TRANSFER_WRITE_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_HOST_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_HOST_WRITE_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_MEMORY_READ_BIT) + ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_MEMORY_WRITE_BIT) #undef ACCESS_FLAG_BIT_TO_STRING - default: UNEXPECTED("Unexpected bit"); return ""; - } + default: UNEXPECTED("Unexpected bit"); return ""; + // clang-format on } +} - const char* VkImageLayoutToString(VkImageLayout Layout) +const char* VkImageLayoutToString(VkImageLayout Layout) +{ + switch (Layout) { - switch(Layout) - { + // clang-format off #define IMAGE_LAYOUT_TO_STRING(LAYOUT)case LAYOUT: return #LAYOUT; - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_UNDEFINED) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_GENERAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_PREINITIALIZED) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) - IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_UNDEFINED) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_GENERAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_PREINITIALIZED) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) + IMAGE_LAYOUT_TO_STRING(VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) #undef IMAGE_LAYOUT_TO_STRING - default: UNEXPECTED("Unknown layout"); return ""; - } + default: UNEXPECTED("Unknown layout"); return ""; + // clang-format on } +} - std::string VkAccessFlagsToString(VkAccessFlags Flags) +std::string VkAccessFlagsToString(VkAccessFlags Flags) +{ + std::string FlagsString; + while (Flags != 0) { - std::string FlagsString; - while(Flags != 0) - { - auto Bit = Flags & ~(Flags - 1); - if (!FlagsString.empty()) - FlagsString += ", "; - FlagsString += VkAccessFlagBitToString( static_cast(Bit) ); - Flags = Flags & (Flags - 1); - } - return std::move(FlagsString); + auto Bit = Flags & ~(Flags - 1); + if (!FlagsString.empty()) + FlagsString += ", "; + FlagsString += VkAccessFlagBitToString(static_cast(Bit)); + Flags = Flags & (Flags - 1); } + return std::move(FlagsString); +} - const char* VkObjectTypeToString(VkObjectType ObjectType) - { - switch(ObjectType) - { - case VK_OBJECT_TYPE_UNKNOWN: return "unknown"; - case VK_OBJECT_TYPE_INSTANCE: return "instance"; - case VK_OBJECT_TYPE_PHYSICAL_DEVICE: return "physical device"; - case VK_OBJECT_TYPE_DEVICE: return "device"; - case VK_OBJECT_TYPE_QUEUE: return "queue"; - case VK_OBJECT_TYPE_SEMAPHORE: return "semaphore"; - case VK_OBJECT_TYPE_COMMAND_BUFFER: return "cmd buffer"; - case VK_OBJECT_TYPE_FENCE: return "fence"; - case VK_OBJECT_TYPE_DEVICE_MEMORY: return "memory"; - case VK_OBJECT_TYPE_BUFFER: return "buffer"; - case VK_OBJECT_TYPE_IMAGE: return "image"; - case VK_OBJECT_TYPE_EVENT: return "event"; - case VK_OBJECT_TYPE_QUERY_POOL: return "query pool"; - case VK_OBJECT_TYPE_BUFFER_VIEW: return "buffer view"; - case VK_OBJECT_TYPE_IMAGE_VIEW: return "image view"; - case VK_OBJECT_TYPE_SHADER_MODULE: return "shader module"; - case VK_OBJECT_TYPE_PIPELINE_CACHE: return "pipeline cache"; - case VK_OBJECT_TYPE_PIPELINE_LAYOUT: return "pipeline layout"; - case VK_OBJECT_TYPE_RENDER_PASS: return "render pass"; - case VK_OBJECT_TYPE_PIPELINE: return "pipeline"; - case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: return "descriptor set layout"; - case VK_OBJECT_TYPE_SAMPLER: return "sampler"; - case VK_OBJECT_TYPE_DESCRIPTOR_POOL: return "descriptor pool"; - case VK_OBJECT_TYPE_DESCRIPTOR_SET: return "descriptor set"; - case VK_OBJECT_TYPE_FRAMEBUFFER: return "framebuffer"; - case VK_OBJECT_TYPE_COMMAND_POOL: return "command pool"; - case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: return "sampler ycbcr conversion"; - case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: return "descriptor update template"; - case VK_OBJECT_TYPE_SURFACE_KHR: return "surface KHR"; - case VK_OBJECT_TYPE_SWAPCHAIN_KHR: return "swapchain KHR"; - case VK_OBJECT_TYPE_DISPLAY_KHR: return "display KHR"; - case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: return "display mode KHR"; - case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: return "debug report callback"; - case VK_OBJECT_TYPE_OBJECT_TABLE_NVX: return "object tabke NVX"; - case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX: return "indirect cmd layout NVX"; - case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: return "debug utils messenger"; - case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: return "validation cache"; - case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX: return "acceleration structure NVX"; - default: return "unknown"; - } +const char* VkObjectTypeToString(VkObjectType ObjectType) +{ + switch (ObjectType) + { + // clang-format off + case VK_OBJECT_TYPE_UNKNOWN: return "unknown"; + case VK_OBJECT_TYPE_INSTANCE: return "instance"; + case VK_OBJECT_TYPE_PHYSICAL_DEVICE: return "physical device"; + case VK_OBJECT_TYPE_DEVICE: return "device"; + case VK_OBJECT_TYPE_QUEUE: return "queue"; + case VK_OBJECT_TYPE_SEMAPHORE: return "semaphore"; + case VK_OBJECT_TYPE_COMMAND_BUFFER: return "cmd buffer"; + case VK_OBJECT_TYPE_FENCE: return "fence"; + case VK_OBJECT_TYPE_DEVICE_MEMORY: return "memory"; + case VK_OBJECT_TYPE_BUFFER: return "buffer"; + case VK_OBJECT_TYPE_IMAGE: return "image"; + case VK_OBJECT_TYPE_EVENT: return "event"; + case VK_OBJECT_TYPE_QUERY_POOL: return "query pool"; + case VK_OBJECT_TYPE_BUFFER_VIEW: return "buffer view"; + case VK_OBJECT_TYPE_IMAGE_VIEW: return "image view"; + case VK_OBJECT_TYPE_SHADER_MODULE: return "shader module"; + case VK_OBJECT_TYPE_PIPELINE_CACHE: return "pipeline cache"; + case VK_OBJECT_TYPE_PIPELINE_LAYOUT: return "pipeline layout"; + case VK_OBJECT_TYPE_RENDER_PASS: return "render pass"; + case VK_OBJECT_TYPE_PIPELINE: return "pipeline"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: return "descriptor set layout"; + case VK_OBJECT_TYPE_SAMPLER: return "sampler"; + case VK_OBJECT_TYPE_DESCRIPTOR_POOL: return "descriptor pool"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET: return "descriptor set"; + case VK_OBJECT_TYPE_FRAMEBUFFER: return "framebuffer"; + case VK_OBJECT_TYPE_COMMAND_POOL: return "command pool"; + case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: return "sampler ycbcr conversion"; + case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: return "descriptor update template"; + case VK_OBJECT_TYPE_SURFACE_KHR: return "surface KHR"; + case VK_OBJECT_TYPE_SWAPCHAIN_KHR: return "swapchain KHR"; + case VK_OBJECT_TYPE_DISPLAY_KHR: return "display KHR"; + case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: return "display mode KHR"; + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: return "debug report callback"; + case VK_OBJECT_TYPE_OBJECT_TABLE_NVX: return "object tabke NVX"; + case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX: return "indirect cmd layout NVX"; + case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: return "debug utils messenger"; + case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: return "validation cache"; + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX: return "acceleration structure NVX"; + default: return "unknown"; + // clang-format on } } + +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp index 6d153fd7..c527d497 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp @@ -28,44 +28,48 @@ namespace VulkanUtilities { - VulkanFencePool::VulkanFencePool(std::shared_ptr LogicalDevice)noexcept : - m_LogicalDevice{std::move(LogicalDevice)} - {} - VulkanFencePool::~VulkanFencePool() - { +VulkanFencePool::VulkanFencePool(std::shared_ptr LogicalDevice) noexcept : + m_LogicalDevice{std::move(LogicalDevice)} +{} + +VulkanFencePool::~VulkanFencePool() +{ #ifdef DEVELOPMENT - for (const auto& fence : m_Fences) - { - DEV_CHECK_ERR(m_LogicalDevice->GetFenceStatus(fence) == VK_SUCCESS, "Destroying a fence that has not been signaled"); - } -#endif - m_Fences.clear(); + for (const auto& fence : m_Fences) + { + DEV_CHECK_ERR(m_LogicalDevice->GetFenceStatus(fence) == VK_SUCCESS, "Destroying a fence that has not been signaled"); } +#endif + m_Fences.clear(); +} - FenceWrapper VulkanFencePool::GetFence() +FenceWrapper VulkanFencePool::GetFence() +{ + FenceWrapper Fence; + if (!m_Fences.empty()) { - FenceWrapper Fence; - if(!m_Fences.empty()) - { - Fence = std::move(m_Fences.back()); - m_LogicalDevice->ResetFence(Fence); - m_Fences.pop_back(); - } - else - { - VkFenceCreateInfo FenceCI = {}; - FenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - FenceCI.pNext = nullptr; - FenceCI.flags = 0; // Available flag: VK_FENCE_CREATE_SIGNALED_BIT - Fence = m_LogicalDevice->CreateFence(FenceCI); - } - return Fence; + Fence = std::move(m_Fences.back()); + m_LogicalDevice->ResetFence(Fence); + m_Fences.pop_back(); } - - void VulkanFencePool::DisposeFence(FenceWrapper&& Fence) + else { - DEV_CHECK_ERR(m_LogicalDevice->GetFenceStatus(Fence) == VK_SUCCESS, "Disposing a fence that has not been signaled"); - m_Fences.emplace_back(std::move(Fence)); + VkFenceCreateInfo FenceCI = {}; + + FenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + FenceCI.pNext = nullptr; + FenceCI.flags = 0; // Available flag: VK_FENCE_CREATE_SIGNALED_BIT + + Fence = m_LogicalDevice->CreateFence(FenceCI); } + return Fence; } + +void VulkanFencePool::DisposeFence(FenceWrapper&& Fence) +{ + DEV_CHECK_ERR(m_LogicalDevice->GetFenceStatus(Fence) == VK_SUCCESS, "Disposing a fence that has not been signaled"); + m_Fences.emplace_back(std::move(Fence)); +} + +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index 03baf0fa..ebad66bf 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -28,252 +28,260 @@ #include "VulkanUtilities/VulkanDebug.h" #if !NO_GLSLANG -#include "SPIRVUtils.h" +# include "SPIRVUtils.h" #endif #include "PlatformDefinitions.h" namespace VulkanUtilities { - bool VulkanInstance::IsLayerAvailable(const char* LayerName)const - { - for (const auto& Layer : m_Layers) - if (strcmp(Layer.layerName, LayerName) == 0) - return true; - return false; - } +bool VulkanInstance::IsLayerAvailable(const char* LayerName) const +{ + for (const auto& Layer : m_Layers) + if (strcmp(Layer.layerName, LayerName) == 0) + return true; - bool VulkanInstance::IsExtensionAvailable(const char* ExtensionName)const - { - for (const auto& Extension : m_Extensions) - if (strcmp(Extension.extensionName, ExtensionName) == 0) - return true; + return false; +} - return false; - } +bool VulkanInstance::IsExtensionAvailable(const char* ExtensionName) const +{ + for (const auto& Extension : m_Extensions) + if (strcmp(Extension.extensionName, ExtensionName) == 0) + return true; + + return false; +} + +std::shared_ptr VulkanInstance::Create(bool EnableValidation, + uint32_t GlobalExtensionCount, + const char* const* ppGlobalExtensionNames, + VkAllocationCallbacks* pVkAllocator) +{ + auto Instance = new VulkanInstance{EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator}; + return std::shared_ptr{Instance}; +} - std::shared_ptr VulkanInstance::Create(bool EnableValidation, - uint32_t GlobalExtensionCount, - const char* const* ppGlobalExtensionNames, - VkAllocationCallbacks* pVkAllocator) +VulkanInstance::VulkanInstance(bool EnableValidation, + uint32_t GlobalExtensionCount, + const char* const* ppGlobalExtensionNames, + VkAllocationCallbacks* pVkAllocator) : + m_pVkAllocator{pVkAllocator} +{ { - auto Instance = new VulkanInstance{EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator}; - return std::shared_ptr{Instance}; + // Enumerate available layers + uint32_t LayerCount = 0; + + auto res = vkEnumerateInstanceLayerProperties(&LayerCount, nullptr); + CHECK_VK_ERROR_AND_THROW(res, "Failed to query layer count"); + m_Layers.resize(LayerCount); + vkEnumerateInstanceLayerProperties(&LayerCount, m_Layers.data()); + CHECK_VK_ERROR_AND_THROW(res, "Failed to enumerate extensions"); + VERIFY_EXPR(LayerCount == m_Layers.size()); } - VulkanInstance::VulkanInstance(bool EnableValidation, - uint32_t GlobalExtensionCount, - const char* const* ppGlobalExtensionNames, - VkAllocationCallbacks* pVkAllocator) : - m_pVkAllocator{pVkAllocator} { - { - // Enumerate available layers - uint32_t LayerCount = 0; - auto res = vkEnumerateInstanceLayerProperties(&LayerCount, nullptr); - CHECK_VK_ERROR_AND_THROW(res, "Failed to query layer count"); - m_Layers.resize(LayerCount); - vkEnumerateInstanceLayerProperties(&LayerCount, m_Layers.data()); - CHECK_VK_ERROR_AND_THROW(res, "Failed to enumerate extensions"); - VERIFY_EXPR(LayerCount == m_Layers.size()); - } + // Enumerate available extensions + uint32_t ExtensionCount = 0; - { - // Enumerate available extensions - uint32_t ExtensionCount = 0; - auto res = vkEnumerateInstanceExtensionProperties(nullptr, &ExtensionCount, nullptr); - CHECK_VK_ERROR_AND_THROW(res, "Failed to query extension count"); - m_Extensions.resize(ExtensionCount); - vkEnumerateInstanceExtensionProperties(nullptr, &ExtensionCount, m_Extensions.data()); - CHECK_VK_ERROR_AND_THROW(res, "Failed to enumerate extensions"); - VERIFY_EXPR(ExtensionCount == m_Extensions.size()); - } + auto res = vkEnumerateInstanceExtensionProperties(nullptr, &ExtensionCount, nullptr); + CHECK_VK_ERROR_AND_THROW(res, "Failed to query extension count"); + m_Extensions.resize(ExtensionCount); + vkEnumerateInstanceExtensionProperties(nullptr, &ExtensionCount, m_Extensions.data()); + CHECK_VK_ERROR_AND_THROW(res, "Failed to enumerate extensions"); + VERIFY_EXPR(ExtensionCount == m_Extensions.size()); + } - std::vector GlobalExtensions = - { - VK_KHR_SURFACE_EXTENSION_NAME, + std::vector GlobalExtensions = + { + VK_KHR_SURFACE_EXTENSION_NAME, - // Enable surface extensions depending on OS + // Enable surface extensions depending on OS #if defined(VK_USE_PLATFORM_WIN32_KHR) - VK_KHR_WIN32_SURFACE_EXTENSION_NAME + VK_KHR_WIN32_SURFACE_EXTENSION_NAME #elif defined(VK_USE_PLATFORM_ANDROID_KHR) - VK_KHR_ANDROID_SURFACE_EXTENSION_NAME + VK_KHR_ANDROID_SURFACE_EXTENSION_NAME #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) - VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME #elif defined(VK_USE_PLATFORM_XCB_KHR) - VK_KHR_XCB_SURFACE_EXTENSION_NAME + VK_KHR_XCB_SURFACE_EXTENSION_NAME #elif defined(VK_USE_PLATFORM_IOS_MVK) - VK_MVK_IOS_SURFACE_EXTENSION_NAME + VK_MVK_IOS_SURFACE_EXTENSION_NAME #elif defined(VK_USE_PLATFORM_MACOS_MVK) - VK_MVK_MACOS_SURFACE_EXTENSION_NAME + VK_MVK_MACOS_SURFACE_EXTENSION_NAME #endif - }; + }; - if (ppGlobalExtensionNames != nullptr) + if (ppGlobalExtensionNames != nullptr) + { + for (uint32_t ext = 0; ext < GlobalExtensionCount; ++ext) + GlobalExtensions.push_back(ppGlobalExtensionNames[ext]); + } + else + { + if (GlobalExtensionCount != 0) + LOG_ERROR_MESSAGE("Global extensions pointer is null while extensions count is ", GlobalExtensionCount, + ". Please initialize 'ppGlobalExtensionNames' member of EngineVkCreateInfo struct."); + } + + for (const auto* ExtName : GlobalExtensions) + { + if (!IsExtensionAvailable(ExtName)) + LOG_ERROR_AND_THROW("Required extension ", ExtName, " is not available"); + } + + if (EnableValidation) + { + m_DebugUtilsEnabled = IsExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + if (m_DebugUtilsEnabled) { - for (uint32_t ext = 0; ext < GlobalExtensionCount; ++ext) - GlobalExtensions.push_back(ppGlobalExtensionNames[ext]); + GlobalExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } else { - if (GlobalExtensionCount != 0) - LOG_ERROR_MESSAGE("Global extensions pointer is null while extensions count is ", GlobalExtensionCount, ". " - "Please initialize 'ppGlobalExtensionNames' member of EngineVkCreateInfo struct."); + LOG_WARNING_MESSAGE("Extension ", VK_EXT_DEBUG_UTILS_EXTENSION_NAME, " is not available."); } + } - for(const auto* ExtName : GlobalExtensions) - { - if (!IsExtensionAvailable(ExtName)) - LOG_ERROR_AND_THROW("Required extension ", ExtName, " is not available"); - } + VkApplicationInfo appInfo = {}; - if (EnableValidation) - { - m_DebugUtilsEnabled = IsExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - if (m_DebugUtilsEnabled) - { - GlobalExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - else - { - LOG_WARNING_MESSAGE("Extension ", VK_EXT_DEBUG_UTILS_EXTENSION_NAME, " is not available."); - } - } + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pNext = nullptr; // Pointer to an extension-specific structure. + appInfo.pApplicationName = nullptr; + appInfo.applicationVersion = 0; // Developer-supplied version number of the application + appInfo.pEngineName = "Diligent Engine"; + appInfo.engineVersion = 0; // Developer-supplied version number of the engine used to create the application. + appInfo.apiVersion = VK_API_VERSION_1_0; + + VkInstanceCreateInfo InstanceCreateInfo = {}; - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pNext = nullptr; // Pointer to an extension-specific structure. - appInfo.pApplicationName = nullptr; - appInfo.applicationVersion = 0; // Developer-supplied version number of the application - appInfo.pEngineName = "Diligent Engine"; - appInfo.engineVersion = 0;// Developer-supplied version number of the engine used to create the application. - appInfo.apiVersion = VK_API_VERSION_1_0; - - VkInstanceCreateInfo InstanceCreateInfo = {}; - InstanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - InstanceCreateInfo.pNext = nullptr; // Pointer to an extension-specific structure. - InstanceCreateInfo.flags = 0; // Reserved for future use. - InstanceCreateInfo.pApplicationInfo = &appInfo; - InstanceCreateInfo.enabledExtensionCount = static_cast(GlobalExtensions.size()); - InstanceCreateInfo.ppEnabledExtensionNames = GlobalExtensions.empty() ? nullptr : GlobalExtensions.data(); - - if (EnableValidation) + InstanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + InstanceCreateInfo.pNext = nullptr; // Pointer to an extension-specific structure. + InstanceCreateInfo.flags = 0; // Reserved for future use. + InstanceCreateInfo.pApplicationInfo = &appInfo; + InstanceCreateInfo.enabledExtensionCount = static_cast(GlobalExtensions.size()); + InstanceCreateInfo.ppEnabledExtensionNames = GlobalExtensions.empty() ? nullptr : GlobalExtensions.data(); + + if (EnableValidation) + { + bool ValidationLayersPresent = true; + for (size_t l = 0; l < _countof(VulkanUtilities::ValidationLayerNames); ++l) { - bool ValidationLayersPresent = true; - for (size_t l = 0; l < _countof(VulkanUtilities::ValidationLayerNames); ++l) + auto* pLayerName = VulkanUtilities::ValidationLayerNames[l]; + if (!IsLayerAvailable(pLayerName)) { - auto* pLayerName = VulkanUtilities::ValidationLayerNames[l]; - if (!IsLayerAvailable(pLayerName)) - { - ValidationLayersPresent = false; - LOG_ERROR_MESSAGE("Failed to find ", pLayerName, " layer. Validation will be disabled"); - } - } - if (ValidationLayersPresent) - { - InstanceCreateInfo.enabledLayerCount = static_cast(_countof(VulkanUtilities::ValidationLayerNames)); - InstanceCreateInfo.ppEnabledLayerNames = VulkanUtilities::ValidationLayerNames; + ValidationLayersPresent = false; + LOG_ERROR_MESSAGE("Failed to find ", pLayerName, " layer. Validation will be disabled"); } } - auto res = vkCreateInstance(&InstanceCreateInfo, m_pVkAllocator, &m_VkInstance); - CHECK_VK_ERROR_AND_THROW(res, "Failed to create Vulkan instance"); - - // If requested, we enable the default validation layers for debugging - if (m_DebugUtilsEnabled) + if (ValidationLayersPresent) { - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - VkDebugUtilsMessageTypeFlagsEXT messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - VulkanUtilities::SetupDebugging(m_VkInstance, messageSeverity, messageType, nullptr); + InstanceCreateInfo.enabledLayerCount = static_cast(_countof(VulkanUtilities::ValidationLayerNames)); + InstanceCreateInfo.ppEnabledLayerNames = VulkanUtilities::ValidationLayerNames; } + } + auto res = vkCreateInstance(&InstanceCreateInfo, m_pVkAllocator, &m_VkInstance); + CHECK_VK_ERROR_AND_THROW(res, "Failed to create Vulkan instance"); - // Enumerate physical devices - { - // Physical device - uint32_t PhysicalDeviceCount = 0; - // Get the number of available physical devices - auto err = vkEnumeratePhysicalDevices(m_VkInstance, &PhysicalDeviceCount, nullptr); - CHECK_VK_ERROR(err, "Failed to get physical device count"); - if (PhysicalDeviceCount == 0) - LOG_ERROR_AND_THROW("No physical devices found on the system"); - - // Enumerate devices - m_PhysicalDevices.resize(PhysicalDeviceCount); - err = vkEnumeratePhysicalDevices(m_VkInstance, &PhysicalDeviceCount, m_PhysicalDevices.data()); - CHECK_VK_ERROR(err, "Failed to enumerate physical devices"); - VERIFY_EXPR(m_PhysicalDevices.size() == PhysicalDeviceCount); - } -#if !NO_GLSLANG - Diligent::InitializeGlslang(); -#endif + // If requested, we enable the default validation layers for debugging + if (m_DebugUtilsEnabled) + { + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + VkDebugUtilsMessageTypeFlagsEXT messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + VulkanUtilities::SetupDebugging(m_VkInstance, messageSeverity, messageType, nullptr); } - VulkanInstance::~VulkanInstance() + // Enumerate physical devices { - if (m_DebugUtilsEnabled) - { - VulkanUtilities::FreeDebugging(m_VkInstance); - } - vkDestroyInstance(m_VkInstance, m_pVkAllocator); + // Physical device + uint32_t PhysicalDeviceCount = 0; + // Get the number of available physical devices + auto err = vkEnumeratePhysicalDevices(m_VkInstance, &PhysicalDeviceCount, nullptr); + CHECK_VK_ERROR(err, "Failed to get physical device count"); + if (PhysicalDeviceCount == 0) + LOG_ERROR_AND_THROW("No physical devices found on the system"); + // Enumerate devices + m_PhysicalDevices.resize(PhysicalDeviceCount); + err = vkEnumeratePhysicalDevices(m_VkInstance, &PhysicalDeviceCount, m_PhysicalDevices.data()); + CHECK_VK_ERROR(err, "Failed to enumerate physical devices"); + VERIFY_EXPR(m_PhysicalDevices.size() == PhysicalDeviceCount); + } #if !NO_GLSLANG - Diligent::FinalizeGlslang(); + Diligent::InitializeGlslang(); #endif +} + +VulkanInstance::~VulkanInstance() +{ + if (m_DebugUtilsEnabled) + { + VulkanUtilities::FreeDebugging(m_VkInstance); } + vkDestroyInstance(m_VkInstance, m_pVkAllocator); - VkPhysicalDevice VulkanInstance::SelectPhysicalDevice()const +#if !NO_GLSLANG + Diligent::FinalizeGlslang(); +#endif +} + +VkPhysicalDevice VulkanInstance::SelectPhysicalDevice() const +{ + VkPhysicalDevice SelectedPhysicalDevice = VK_NULL_HANDLE; + + // Select a device that exposes a queue family that suppors both compute and graphics operations + // Prefer discrete GPU + for (auto Device : m_PhysicalDevices) { - VkPhysicalDevice SelectedPhysicalDevice = VK_NULL_HANDLE; + VkPhysicalDeviceProperties DeviceProps; + vkGetPhysicalDeviceProperties(Device, &DeviceProps); + + uint32_t QueueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr); + VERIFY_EXPR(QueueFamilyCount > 0); + std::vector QueueFamilyProperties(QueueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilyProperties.data()); + VERIFY_EXPR(QueueFamilyCount == QueueFamilyProperties.size()); - // Select a device that exposes a queue family that suppors both compute and graphics operations - // Prefer discrete GPU - for (auto Device : m_PhysicalDevices) + // If an implementation exposes any queue family that supports graphics operations, + // at least one queue family of at least one physical device exposed by the implementation + // must support both graphics and compute operations. + bool GraphicsAndComputeQueueSupported = false; + for (const auto& QueueFamilyProps : QueueFamilyProperties) { - VkPhysicalDeviceProperties DeviceProps; - vkGetPhysicalDeviceProperties(Device, &DeviceProps); - - uint32_t QueueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr); - VERIFY_EXPR(QueueFamilyCount > 0); - std::vector QueueFamilyProperties(QueueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilyProperties.data()); - VERIFY_EXPR(QueueFamilyCount == QueueFamilyProperties.size()); - - // If an implementation exposes any queue family that supports graphics operations, - // at least one queue family of at least one physical device exposed by the implementation - // must support both graphics and compute operations. - bool GraphicsAndComputeQueueSupported = false; - for(const auto &QueueFamilyProps : QueueFamilyProperties) + if ((QueueFamilyProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && + (QueueFamilyProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) { - if ((QueueFamilyProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && - (QueueFamilyProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) - { - GraphicsAndComputeQueueSupported = true; - break; - } - } - if (GraphicsAndComputeQueueSupported) - { - SelectedPhysicalDevice = Device; - if (DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - break; + GraphicsAndComputeQueueSupported = true; + break; } } - - if (SelectedPhysicalDevice != VK_NULL_HANDLE) + if (GraphicsAndComputeQueueSupported) { - VkPhysicalDeviceProperties SelectedDeviceProps; - vkGetPhysicalDeviceProperties(SelectedPhysicalDevice, &SelectedDeviceProps); - LOG_INFO_MESSAGE("Using physical device '", SelectedDeviceProps.deviceName, '\''); - } - else - { - LOG_ERROR_MESSAGE("Failed to find suitable physical device"); + SelectedPhysicalDevice = Device; + if (DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + break; } + } - return SelectedPhysicalDevice; + if (SelectedPhysicalDevice != VK_NULL_HANDLE) + { + VkPhysicalDeviceProperties SelectedDeviceProps; + vkGetPhysicalDeviceProperties(SelectedPhysicalDevice, &SelectedDeviceProps); + LOG_INFO_MESSAGE("Using physical device '", SelectedDeviceProps.deviceName, '\''); } + else + { + LOG_ERROR_MESSAGE("Failed to find suitable physical device"); + } + + return SelectedPhysicalDevice; } + +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp index b2a8b0c9..d43ac776 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp @@ -29,443 +29,452 @@ namespace VulkanUtilities { - std::shared_ptr VulkanLogicalDevice::Create(VkPhysicalDevice vkPhysicalDevice, - const VkDeviceCreateInfo& DeviceCI, - const VkAllocationCallbacks* vkAllocator) - { - auto* LogicalDevice = new VulkanLogicalDevice{vkPhysicalDevice, DeviceCI, vkAllocator}; - return std::shared_ptr{LogicalDevice}; - } - - VulkanLogicalDevice::~VulkanLogicalDevice() - { - vkDestroyDevice(m_VkDevice, m_VkAllocator); - } - - VulkanLogicalDevice::VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice, - const VkDeviceCreateInfo& DeviceCI, - const VkAllocationCallbacks* vkAllocator) : - m_VkAllocator{vkAllocator} - { - auto res = vkCreateDevice(vkPhysicalDevice, &DeviceCI, vkAllocator, &m_VkDevice); - CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device"); - - m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - if (DeviceCI.pEnabledFeatures->geometryShader) - m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; - if (DeviceCI.pEnabledFeatures->tessellationShader) - m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; - } - - VkQueue VulkanLogicalDevice::GetQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) - { - VkQueue vkQueue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_VkDevice, - queueFamilyIndex, // Index of the queue family to which the queue belongs - 0, // Index within this queue family of the queue to retrieve - &vkQueue); - VERIFY_EXPR(vkQueue != VK_NULL_HANDLE); - return vkQueue; - } - - void VulkanLogicalDevice::WaitIdle()const - { - auto err = vkDeviceWaitIdle(m_VkDevice); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to idle device"); (void)err; - } - - template - VulkanObjectWrapper VulkanLogicalDevice::CreateVulkanObject(VkCreateObjectFuncType VkCreateObject, - const VkObjectCreateInfoType& CreateInfo, - const char* DebugName, - const char* ObjectType)const - { - if (DebugName == nullptr) - DebugName = ""; - - VkObjectType VkObject = VK_NULL_HANDLE; - auto err = VkCreateObject(m_VkDevice, &CreateInfo, m_VkAllocator, &VkObject); - CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan ", ObjectType, " '", DebugName, '\''); - - if (DebugName != nullptr && *DebugName != 0) - SetVulkanObjectName(m_VkDevice, VkObject, DebugName); - - return VulkanObjectWrapper{ GetSharedPtr(), std::move(VkObject) }; - } - - CommandPoolWrapper VulkanLogicalDevice::CreateCommandPool(const VkCommandPoolCreateInfo &CmdPoolCI, - const char* DebugName) const - { - VERIFY_EXPR(CmdPoolCI.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO); - return CreateVulkanObject(vkCreateCommandPool, CmdPoolCI, DebugName, "command pool"); - } - - BufferWrapper VulkanLogicalDevice::CreateBuffer(const VkBufferCreateInfo& BufferCI, - const char* DebugName)const - { - VERIFY_EXPR(BufferCI.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO); - return CreateVulkanObject(vkCreateBuffer, BufferCI, DebugName, "buffer"); - } - - BufferViewWrapper VulkanLogicalDevice::CreateBufferView(const VkBufferViewCreateInfo &BuffViewCI, - const char* DebugName)const - { - VERIFY_EXPR(BuffViewCI.sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO); - return CreateVulkanObject(vkCreateBufferView, BuffViewCI, DebugName, "buffer view"); - } - - ImageWrapper VulkanLogicalDevice::CreateImage(const VkImageCreateInfo &ImageCI, - const char* DebugName)const - { - VERIFY_EXPR(ImageCI.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); - return CreateVulkanObject(vkCreateImage, ImageCI, DebugName, "image"); - } - - ImageViewWrapper VulkanLogicalDevice::CreateImageView(const VkImageViewCreateInfo &ImageViewCI, - const char* DebugName)const - { - VERIFY_EXPR(ImageViewCI.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); - return CreateVulkanObject(vkCreateImageView, ImageViewCI, DebugName, "image view"); - } - - SamplerWrapper VulkanLogicalDevice::CreateSampler(const VkSamplerCreateInfo &SamplerCI, const char* DebugName)const - { - VERIFY_EXPR(SamplerCI.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); - return CreateVulkanObject(vkCreateSampler, SamplerCI, DebugName, "sampler"); - } - - FenceWrapper VulkanLogicalDevice::CreateFence(const VkFenceCreateInfo &FenceCI, const char* DebugName)const - { - VERIFY_EXPR(FenceCI.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO); - return CreateVulkanObject(vkCreateFence, FenceCI, DebugName, "fence"); - } - - RenderPassWrapper VulkanLogicalDevice::CreateRenderPass(const VkRenderPassCreateInfo &RenderPassCI, const char* DebugName)const - { - VERIFY_EXPR(RenderPassCI.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); - return CreateVulkanObject(vkCreateRenderPass, RenderPassCI, DebugName, "render pass"); - } - - DeviceMemoryWrapper VulkanLogicalDevice::AllocateDeviceMemory(const VkMemoryAllocateInfo& AllocInfo, - const char* DebugName)const - { - VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); - - if (DebugName == nullptr) - DebugName = ""; - - VkDeviceMemory vkDeviceMem = VK_NULL_HANDLE; - - auto err = vkAllocateMemory(m_VkDevice, &AllocInfo, m_VkAllocator, &vkDeviceMem); - CHECK_VK_ERROR_AND_THROW(err, "Failed to allocate device memory '", DebugName, '\''); - - if (DebugName != nullptr && *DebugName != 0) - SetDeviceMemoryName(m_VkDevice, vkDeviceMem, DebugName); - - return DeviceMemoryWrapper{ GetSharedPtr(), std::move(vkDeviceMem) }; - } - - PipelineWrapper VulkanLogicalDevice::CreateComputePipeline(const VkComputePipelineCreateInfo &PipelineCI, - VkPipelineCache cache, - const char* DebugName)const - { - VERIFY_EXPR(PipelineCI.sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO); - - if (DebugName == nullptr) - DebugName = ""; - - VkPipeline vkPipeline = VK_NULL_HANDLE; - auto err = vkCreateComputePipelines(m_VkDevice, cache, 1, &PipelineCI, m_VkAllocator, &vkPipeline); - CHECK_VK_ERROR_AND_THROW(err, "Failed to create compute pipeline '", DebugName, '\''); - - if (DebugName != nullptr && *DebugName != 0) - SetPipelineName(m_VkDevice, vkPipeline, DebugName); - - return PipelineWrapper{ GetSharedPtr(), std::move(vkPipeline) }; - } - - PipelineWrapper VulkanLogicalDevice::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& PipelineCI, - VkPipelineCache cache, - const char* DebugName)const - { - VERIFY_EXPR(PipelineCI.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO); - - if (DebugName == nullptr) - DebugName = ""; - - VkPipeline vkPipeline = VK_NULL_HANDLE; - auto err = vkCreateGraphicsPipelines(m_VkDevice, cache, 1, &PipelineCI, m_VkAllocator, &vkPipeline); - CHECK_VK_ERROR_AND_THROW(err, "Failed to create graphics pipeline '", DebugName, '\''); - - if (DebugName != nullptr && *DebugName != 0) - SetPipelineName(m_VkDevice, vkPipeline, DebugName); - - return PipelineWrapper{ GetSharedPtr(), std::move(vkPipeline) }; - } - - ShaderModuleWrapper VulkanLogicalDevice::CreateShaderModule(const VkShaderModuleCreateInfo& ShaderModuleCI, const char* DebugName)const - { - VERIFY_EXPR(ShaderModuleCI.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); - return CreateVulkanObject(vkCreateShaderModule, ShaderModuleCI, DebugName, "shader module"); - } - - PipelineLayoutWrapper VulkanLogicalDevice::CreatePipelineLayout(const VkPipelineLayoutCreateInfo &PipelineLayoutCI, const char* DebugName)const - { - VERIFY_EXPR(PipelineLayoutCI.sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO); - return CreateVulkanObject(vkCreatePipelineLayout, PipelineLayoutCI, DebugName, "pipeline layout"); - } - - FramebufferWrapper VulkanLogicalDevice::CreateFramebuffer(const VkFramebufferCreateInfo &FramebufferCI, const char* DebugName)const - { - VERIFY_EXPR(FramebufferCI.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO); - return CreateVulkanObject(vkCreateFramebuffer, FramebufferCI, DebugName, "framebuffer"); - } - - DescriptorPoolWrapper VulkanLogicalDevice::CreateDescriptorPool(const VkDescriptorPoolCreateInfo &DescrPoolCI, const char* DebugName)const - { - VERIFY_EXPR(DescrPoolCI.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO); - return CreateVulkanObject(vkCreateDescriptorPool, DescrPoolCI, DebugName, "descriptor pool"); - } - - DescriptorSetLayoutWrapper VulkanLogicalDevice::CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo &LayoutCI, const char* DebugName)const - { - VERIFY_EXPR(LayoutCI.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO); - return CreateVulkanObject(vkCreateDescriptorSetLayout, LayoutCI, DebugName, "descriptor set layout"); - } - - SemaphoreWrapper VulkanLogicalDevice::CreateSemaphore(const VkSemaphoreCreateInfo &SemaphoreCI, const char* DebugName)const - { - VERIFY_EXPR(SemaphoreCI.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); - return CreateVulkanObject(vkCreateSemaphore, SemaphoreCI, DebugName, "semaphore"); - } - - VkCommandBuffer VulkanLogicalDevice::AllocateVkCommandBuffer(const VkCommandBufferAllocateInfo& AllocInfo, const char* DebugName)const - { - VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO); - - if (DebugName == nullptr) - DebugName = ""; - - VkCommandBuffer CmdBuff = VK_NULL_HANDLE; - auto err = vkAllocateCommandBuffers(m_VkDevice, &AllocInfo, &CmdBuff); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to allocate command buffer '", DebugName, '\''); (void)err; - - if (DebugName != nullptr && *DebugName != 0) - SetCommandBufferName(m_VkDevice, CmdBuff, DebugName); - - return CmdBuff; - } - - VkDescriptorSet VulkanLogicalDevice::AllocateVkDescriptorSet(const VkDescriptorSetAllocateInfo& AllocInfo, const char* DebugName)const - { - VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO); - VERIFY_EXPR(AllocInfo.descriptorSetCount == 1); - - if (DebugName == nullptr) - DebugName = ""; - - VkDescriptorSet DescrSet = VK_NULL_HANDLE; - auto err = vkAllocateDescriptorSets(m_VkDevice, &AllocInfo, &DescrSet); - if(err != VK_SUCCESS) - return VK_NULL_HANDLE; - - if (DebugName != nullptr && *DebugName != 0) - SetDescriptorSetName(m_VkDevice, DescrSet, DebugName); - - return DescrSet; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(CommandPoolWrapper &&CmdPool)const - { - vkDestroyCommandPool(m_VkDevice, CmdPool.m_VkObject, m_VkAllocator); - CmdPool.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(BufferWrapper&& Buffer)const - { - vkDestroyBuffer(m_VkDevice, Buffer.m_VkObject, m_VkAllocator); - Buffer.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(BufferViewWrapper&& BufferView)const - { - vkDestroyBufferView(m_VkDevice, BufferView.m_VkObject, m_VkAllocator); - BufferView.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(ImageWrapper&& Image)const - { - vkDestroyImage(m_VkDevice, Image.m_VkObject, m_VkAllocator); - Image.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(ImageViewWrapper&& ImageView)const - { - vkDestroyImageView(m_VkDevice, ImageView.m_VkObject, m_VkAllocator); - ImageView.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(SamplerWrapper&& Sampler)const - { - vkDestroySampler(m_VkDevice, Sampler.m_VkObject, m_VkAllocator); - Sampler.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(FenceWrapper&& Fence)const - { - vkDestroyFence(m_VkDevice, Fence.m_VkObject, m_VkAllocator); - Fence.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(RenderPassWrapper&& RenderPass)const - { - vkDestroyRenderPass(m_VkDevice, RenderPass.m_VkObject, m_VkAllocator); - RenderPass.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(DeviceMemoryWrapper&& Memory)const - { - vkFreeMemory(m_VkDevice, Memory.m_VkObject, m_VkAllocator); - Memory.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(PipelineWrapper&& Pipeline)const - { - vkDestroyPipeline(m_VkDevice, Pipeline.m_VkObject, m_VkAllocator); - Pipeline.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(ShaderModuleWrapper&& ShaderModule)const - { - vkDestroyShaderModule(m_VkDevice, ShaderModule.m_VkObject, m_VkAllocator); - ShaderModule.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(PipelineLayoutWrapper&& PipelineLayout)const - { - vkDestroyPipelineLayout(m_VkDevice, PipelineLayout.m_VkObject, m_VkAllocator); - PipelineLayout.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(FramebufferWrapper&& Framebuffer)const - { - vkDestroyFramebuffer(m_VkDevice, Framebuffer.m_VkObject, m_VkAllocator); - Framebuffer.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(DescriptorPoolWrapper&& DescriptorPool)const - { - vkDestroyDescriptorPool(m_VkDevice, DescriptorPool.m_VkObject, m_VkAllocator); - DescriptorPool.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(DescriptorSetLayoutWrapper&& DescriptorSetLayout)const - { - vkDestroyDescriptorSetLayout(m_VkDevice, DescriptorSetLayout.m_VkObject, m_VkAllocator); - DescriptorSetLayout.m_VkObject = VK_NULL_HANDLE; - } - - void VulkanLogicalDevice::ReleaseVulkanObject(SemaphoreWrapper&& Semaphore)const - { - vkDestroySemaphore(m_VkDevice, Semaphore.m_VkObject, m_VkAllocator); - Semaphore.m_VkObject = VK_NULL_HANDLE; - } - - - void VulkanLogicalDevice::FreeDescriptorSet(VkDescriptorPool Pool, VkDescriptorSet Set)const - { - VERIFY_EXPR(Pool != VK_NULL_HANDLE && Set != VK_NULL_HANDLE); - vkFreeDescriptorSets(m_VkDevice, Pool, 1, &Set); - } - - - - - VkMemoryRequirements VulkanLogicalDevice::GetBufferMemoryRequirements(VkBuffer vkBuffer)const - { - VkMemoryRequirements MemReqs = {}; - vkGetBufferMemoryRequirements(m_VkDevice, vkBuffer, &MemReqs); - return MemReqs; - } - - VkMemoryRequirements VulkanLogicalDevice::GetImageMemoryRequirements(VkImage vkImage)const - { - VkMemoryRequirements MemReqs = {}; - vkGetImageMemoryRequirements(m_VkDevice, vkImage, &MemReqs); - return MemReqs; - } - - VkResult VulkanLogicalDevice::BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)const - { - return vkBindBufferMemory(m_VkDevice, buffer, memory, memoryOffset); - } - - VkResult VulkanLogicalDevice::BindImageMemory(VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset)const - { - return vkBindImageMemory(m_VkDevice, image, memory, memoryOffset); - } - - VkResult VulkanLogicalDevice::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData)const - { - return vkMapMemory(m_VkDevice, memory, offset, size, flags, ppData); - } - - void VulkanLogicalDevice::UnmapMemory(VkDeviceMemory memory)const - { - vkUnmapMemory(m_VkDevice, memory); - } - - VkResult VulkanLogicalDevice::InvalidateMappedMemoryRanges(uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges)const - { - return vkInvalidateMappedMemoryRanges(m_VkDevice, memoryRangeCount, pMemoryRanges); - } - - VkResult VulkanLogicalDevice::FlushMappedMemoryRanges(uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges)const - { - return vkFlushMappedMemoryRanges(m_VkDevice, memoryRangeCount, pMemoryRanges); - } - - VkResult VulkanLogicalDevice::GetFenceStatus(VkFence fence)const - { - return vkGetFenceStatus(m_VkDevice, fence); - } - - VkResult VulkanLogicalDevice::ResetFence(VkFence fence)const - { - auto err = vkResetFences(m_VkDevice, 1, &fence); - DEV_CHECK_ERR(err == VK_SUCCESS, "vkResetFences() failed"); - return err; - } - - VkResult VulkanLogicalDevice::WaitForFences(uint32_t fenceCount, - const VkFence* pFences, - VkBool32 waitAll, - uint64_t timeout) const - { - return vkWaitForFences(m_VkDevice, fenceCount, pFences, waitAll, timeout); - } - - void VulkanLogicalDevice::UpdateDescriptorSets(uint32_t descriptorWriteCount, - const VkWriteDescriptorSet* pDescriptorWrites, - uint32_t descriptorCopyCount, - const VkCopyDescriptorSet* pDescriptorCopies)const - { - vkUpdateDescriptorSets(m_VkDevice, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); - } - - VkResult VulkanLogicalDevice::ResetCommandPool(VkCommandPool vkCmdPool, - VkCommandPoolResetFlags flags)const - { - auto err = vkResetCommandPool(m_VkDevice, vkCmdPool, flags); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset command pool"); - return err; - } - - VkResult VulkanLogicalDevice::ResetDescriptorPool(VkDescriptorPool vkDescriptorPool, - VkDescriptorPoolResetFlags flags)const - { - auto err = vkResetDescriptorPool(m_VkDevice, vkDescriptorPool, flags); - DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset descriptor pool"); - return err; - } + +std::shared_ptr VulkanLogicalDevice::Create(VkPhysicalDevice vkPhysicalDevice, + const VkDeviceCreateInfo& DeviceCI, + const VkAllocationCallbacks* vkAllocator) +{ + auto* LogicalDevice = new VulkanLogicalDevice{vkPhysicalDevice, DeviceCI, vkAllocator}; + return std::shared_ptr{LogicalDevice}; +} + +VulkanLogicalDevice::~VulkanLogicalDevice() +{ + vkDestroyDevice(m_VkDevice, m_VkAllocator); +} + +VulkanLogicalDevice::VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice, + const VkDeviceCreateInfo& DeviceCI, + const VkAllocationCallbacks* vkAllocator) : + m_VkAllocator{vkAllocator} +{ + auto res = vkCreateDevice(vkPhysicalDevice, &DeviceCI, vkAllocator, &m_VkDevice); + CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device"); + + m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + if (DeviceCI.pEnabledFeatures->geometryShader) + m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; + if (DeviceCI.pEnabledFeatures->tessellationShader) + m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; +} + +VkQueue VulkanLogicalDevice::GetQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) +{ + VkQueue vkQueue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_VkDevice, + queueFamilyIndex, // Index of the queue family to which the queue belongs + 0, // Index within this queue family of the queue to retrieve + &vkQueue); + VERIFY_EXPR(vkQueue != VK_NULL_HANDLE); + return vkQueue; +} + +void VulkanLogicalDevice::WaitIdle() const +{ + auto err = vkDeviceWaitIdle(m_VkDevice); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to idle device"); + (void)err; } + +template +VulkanObjectWrapper VulkanLogicalDevice::CreateVulkanObject(VkCreateObjectFuncType VkCreateObject, + const VkObjectCreateInfoType& CreateInfo, + const char* DebugName, + const char* ObjectType) const +{ + if (DebugName == nullptr) + DebugName = ""; + + VkObjectType VkObject = VK_NULL_HANDLE; + + auto err = VkCreateObject(m_VkDevice, &CreateInfo, m_VkAllocator, &VkObject); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create Vulkan ", ObjectType, " '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + SetVulkanObjectName(m_VkDevice, VkObject, DebugName); + + return VulkanObjectWrapper{GetSharedPtr(), std::move(VkObject)}; +} + +CommandPoolWrapper VulkanLogicalDevice::CreateCommandPool(const VkCommandPoolCreateInfo& CmdPoolCI, + const char* DebugName) const +{ + VERIFY_EXPR(CmdPoolCI.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO); + return CreateVulkanObject(vkCreateCommandPool, CmdPoolCI, DebugName, "command pool"); +} + +BufferWrapper VulkanLogicalDevice::CreateBuffer(const VkBufferCreateInfo& BufferCI, + const char* DebugName) const +{ + VERIFY_EXPR(BufferCI.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO); + return CreateVulkanObject(vkCreateBuffer, BufferCI, DebugName, "buffer"); +} + +BufferViewWrapper VulkanLogicalDevice::CreateBufferView(const VkBufferViewCreateInfo& BuffViewCI, + const char* DebugName) const +{ + VERIFY_EXPR(BuffViewCI.sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO); + return CreateVulkanObject(vkCreateBufferView, BuffViewCI, DebugName, "buffer view"); +} + +ImageWrapper VulkanLogicalDevice::CreateImage(const VkImageCreateInfo& ImageCI, + const char* DebugName) const +{ + VERIFY_EXPR(ImageCI.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); + return CreateVulkanObject(vkCreateImage, ImageCI, DebugName, "image"); +} + +ImageViewWrapper VulkanLogicalDevice::CreateImageView(const VkImageViewCreateInfo& ImageViewCI, + const char* DebugName) const +{ + VERIFY_EXPR(ImageViewCI.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO); + return CreateVulkanObject(vkCreateImageView, ImageViewCI, DebugName, "image view"); +} + +SamplerWrapper VulkanLogicalDevice::CreateSampler(const VkSamplerCreateInfo& SamplerCI, const char* DebugName) const +{ + VERIFY_EXPR(SamplerCI.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); + return CreateVulkanObject(vkCreateSampler, SamplerCI, DebugName, "sampler"); +} + +FenceWrapper VulkanLogicalDevice::CreateFence(const VkFenceCreateInfo& FenceCI, const char* DebugName) const +{ + VERIFY_EXPR(FenceCI.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO); + return CreateVulkanObject(vkCreateFence, FenceCI, DebugName, "fence"); +} + +RenderPassWrapper VulkanLogicalDevice::CreateRenderPass(const VkRenderPassCreateInfo& RenderPassCI, const char* DebugName) const +{ + VERIFY_EXPR(RenderPassCI.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO); + return CreateVulkanObject(vkCreateRenderPass, RenderPassCI, DebugName, "render pass"); +} + +DeviceMemoryWrapper VulkanLogicalDevice::AllocateDeviceMemory(const VkMemoryAllocateInfo& AllocInfo, + const char* DebugName) const +{ + VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); + + if (DebugName == nullptr) + DebugName = ""; + + VkDeviceMemory vkDeviceMem = VK_NULL_HANDLE; + + auto err = vkAllocateMemory(m_VkDevice, &AllocInfo, m_VkAllocator, &vkDeviceMem); + CHECK_VK_ERROR_AND_THROW(err, "Failed to allocate device memory '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + SetDeviceMemoryName(m_VkDevice, vkDeviceMem, DebugName); + + return DeviceMemoryWrapper{GetSharedPtr(), std::move(vkDeviceMem)}; +} + +PipelineWrapper VulkanLogicalDevice::CreateComputePipeline(const VkComputePipelineCreateInfo& PipelineCI, + VkPipelineCache cache, + const char* DebugName) const +{ + VERIFY_EXPR(PipelineCI.sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO); + + if (DebugName == nullptr) + DebugName = ""; + + VkPipeline vkPipeline = VK_NULL_HANDLE; + + auto err = vkCreateComputePipelines(m_VkDevice, cache, 1, &PipelineCI, m_VkAllocator, &vkPipeline); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create compute pipeline '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + SetPipelineName(m_VkDevice, vkPipeline, DebugName); + + return PipelineWrapper{GetSharedPtr(), std::move(vkPipeline)}; +} + +PipelineWrapper VulkanLogicalDevice::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& PipelineCI, + VkPipelineCache cache, + const char* DebugName) const +{ + VERIFY_EXPR(PipelineCI.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO); + + if (DebugName == nullptr) + DebugName = ""; + + VkPipeline vkPipeline = VK_NULL_HANDLE; + + auto err = vkCreateGraphicsPipelines(m_VkDevice, cache, 1, &PipelineCI, m_VkAllocator, &vkPipeline); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create graphics pipeline '", DebugName, '\''); + + if (DebugName != nullptr && *DebugName != 0) + SetPipelineName(m_VkDevice, vkPipeline, DebugName); + + return PipelineWrapper{GetSharedPtr(), std::move(vkPipeline)}; +} + +ShaderModuleWrapper VulkanLogicalDevice::CreateShaderModule(const VkShaderModuleCreateInfo& ShaderModuleCI, const char* DebugName) const +{ + VERIFY_EXPR(ShaderModuleCI.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); + return CreateVulkanObject(vkCreateShaderModule, ShaderModuleCI, DebugName, "shader module"); +} + +PipelineLayoutWrapper VulkanLogicalDevice::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& PipelineLayoutCI, const char* DebugName) const +{ + VERIFY_EXPR(PipelineLayoutCI.sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO); + return CreateVulkanObject(vkCreatePipelineLayout, PipelineLayoutCI, DebugName, "pipeline layout"); +} + +FramebufferWrapper VulkanLogicalDevice::CreateFramebuffer(const VkFramebufferCreateInfo& FramebufferCI, const char* DebugName) const +{ + VERIFY_EXPR(FramebufferCI.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO); + return CreateVulkanObject(vkCreateFramebuffer, FramebufferCI, DebugName, "framebuffer"); +} + +DescriptorPoolWrapper VulkanLogicalDevice::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& DescrPoolCI, const char* DebugName) const +{ + VERIFY_EXPR(DescrPoolCI.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO); + return CreateVulkanObject(vkCreateDescriptorPool, DescrPoolCI, DebugName, "descriptor pool"); +} + +DescriptorSetLayoutWrapper VulkanLogicalDevice::CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& LayoutCI, const char* DebugName) const +{ + VERIFY_EXPR(LayoutCI.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO); + return CreateVulkanObject(vkCreateDescriptorSetLayout, LayoutCI, DebugName, "descriptor set layout"); +} + +SemaphoreWrapper VulkanLogicalDevice::CreateSemaphore(const VkSemaphoreCreateInfo& SemaphoreCI, const char* DebugName) const +{ + VERIFY_EXPR(SemaphoreCI.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); + return CreateVulkanObject(vkCreateSemaphore, SemaphoreCI, DebugName, "semaphore"); +} + +VkCommandBuffer VulkanLogicalDevice::AllocateVkCommandBuffer(const VkCommandBufferAllocateInfo& AllocInfo, const char* DebugName) const +{ + VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO); + + if (DebugName == nullptr) + DebugName = ""; + + VkCommandBuffer CmdBuff = VK_NULL_HANDLE; + + auto err = vkAllocateCommandBuffers(m_VkDevice, &AllocInfo, &CmdBuff); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to allocate command buffer '", DebugName, '\''); + (void)err; + + if (DebugName != nullptr && *DebugName != 0) + SetCommandBufferName(m_VkDevice, CmdBuff, DebugName); + + return CmdBuff; +} + +VkDescriptorSet VulkanLogicalDevice::AllocateVkDescriptorSet(const VkDescriptorSetAllocateInfo& AllocInfo, const char* DebugName) const +{ + VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO); + VERIFY_EXPR(AllocInfo.descriptorSetCount == 1); + + if (DebugName == nullptr) + DebugName = ""; + + VkDescriptorSet DescrSet = VK_NULL_HANDLE; + + auto err = vkAllocateDescriptorSets(m_VkDevice, &AllocInfo, &DescrSet); + if (err != VK_SUCCESS) + return VK_NULL_HANDLE; + + if (DebugName != nullptr && *DebugName != 0) + SetDescriptorSetName(m_VkDevice, DescrSet, DebugName); + + return DescrSet; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(CommandPoolWrapper&& CmdPool) const +{ + vkDestroyCommandPool(m_VkDevice, CmdPool.m_VkObject, m_VkAllocator); + CmdPool.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(BufferWrapper&& Buffer) const +{ + vkDestroyBuffer(m_VkDevice, Buffer.m_VkObject, m_VkAllocator); + Buffer.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(BufferViewWrapper&& BufferView) const +{ + vkDestroyBufferView(m_VkDevice, BufferView.m_VkObject, m_VkAllocator); + BufferView.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(ImageWrapper&& Image) const +{ + vkDestroyImage(m_VkDevice, Image.m_VkObject, m_VkAllocator); + Image.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(ImageViewWrapper&& ImageView) const +{ + vkDestroyImageView(m_VkDevice, ImageView.m_VkObject, m_VkAllocator); + ImageView.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(SamplerWrapper&& Sampler) const +{ + vkDestroySampler(m_VkDevice, Sampler.m_VkObject, m_VkAllocator); + Sampler.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(FenceWrapper&& Fence) const +{ + vkDestroyFence(m_VkDevice, Fence.m_VkObject, m_VkAllocator); + Fence.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(RenderPassWrapper&& RenderPass) const +{ + vkDestroyRenderPass(m_VkDevice, RenderPass.m_VkObject, m_VkAllocator); + RenderPass.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(DeviceMemoryWrapper&& Memory) const +{ + vkFreeMemory(m_VkDevice, Memory.m_VkObject, m_VkAllocator); + Memory.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(PipelineWrapper&& Pipeline) const +{ + vkDestroyPipeline(m_VkDevice, Pipeline.m_VkObject, m_VkAllocator); + Pipeline.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(ShaderModuleWrapper&& ShaderModule) const +{ + vkDestroyShaderModule(m_VkDevice, ShaderModule.m_VkObject, m_VkAllocator); + ShaderModule.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(PipelineLayoutWrapper&& PipelineLayout) const +{ + vkDestroyPipelineLayout(m_VkDevice, PipelineLayout.m_VkObject, m_VkAllocator); + PipelineLayout.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(FramebufferWrapper&& Framebuffer) const +{ + vkDestroyFramebuffer(m_VkDevice, Framebuffer.m_VkObject, m_VkAllocator); + Framebuffer.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(DescriptorPoolWrapper&& DescriptorPool) const +{ + vkDestroyDescriptorPool(m_VkDevice, DescriptorPool.m_VkObject, m_VkAllocator); + DescriptorPool.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(DescriptorSetLayoutWrapper&& DescriptorSetLayout) const +{ + vkDestroyDescriptorSetLayout(m_VkDevice, DescriptorSetLayout.m_VkObject, m_VkAllocator); + DescriptorSetLayout.m_VkObject = VK_NULL_HANDLE; +} + +void VulkanLogicalDevice::ReleaseVulkanObject(SemaphoreWrapper&& Semaphore) const +{ + vkDestroySemaphore(m_VkDevice, Semaphore.m_VkObject, m_VkAllocator); + Semaphore.m_VkObject = VK_NULL_HANDLE; +} + + +void VulkanLogicalDevice::FreeDescriptorSet(VkDescriptorPool Pool, VkDescriptorSet Set) const +{ + VERIFY_EXPR(Pool != VK_NULL_HANDLE && Set != VK_NULL_HANDLE); + vkFreeDescriptorSets(m_VkDevice, Pool, 1, &Set); +} + + + + +VkMemoryRequirements VulkanLogicalDevice::GetBufferMemoryRequirements(VkBuffer vkBuffer) const +{ + VkMemoryRequirements MemReqs = {}; + vkGetBufferMemoryRequirements(m_VkDevice, vkBuffer, &MemReqs); + return MemReqs; +} + +VkMemoryRequirements VulkanLogicalDevice::GetImageMemoryRequirements(VkImage vkImage) const +{ + VkMemoryRequirements MemReqs = {}; + vkGetImageMemoryRequirements(m_VkDevice, vkImage, &MemReqs); + return MemReqs; +} + +VkResult VulkanLogicalDevice::BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) const +{ + return vkBindBufferMemory(m_VkDevice, buffer, memory, memoryOffset); +} + +VkResult VulkanLogicalDevice::BindImageMemory(VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) const +{ + return vkBindImageMemory(m_VkDevice, image, memory, memoryOffset); +} + +VkResult VulkanLogicalDevice::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) const +{ + return vkMapMemory(m_VkDevice, memory, offset, size, flags, ppData); +} + +void VulkanLogicalDevice::UnmapMemory(VkDeviceMemory memory) const +{ + vkUnmapMemory(m_VkDevice, memory); +} + +VkResult VulkanLogicalDevice::InvalidateMappedMemoryRanges(uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) const +{ + return vkInvalidateMappedMemoryRanges(m_VkDevice, memoryRangeCount, pMemoryRanges); +} + +VkResult VulkanLogicalDevice::FlushMappedMemoryRanges(uint32_t memoryRangeCount, const VkMappedMemoryRange* pMemoryRanges) const +{ + return vkFlushMappedMemoryRanges(m_VkDevice, memoryRangeCount, pMemoryRanges); +} + +VkResult VulkanLogicalDevice::GetFenceStatus(VkFence fence) const +{ + return vkGetFenceStatus(m_VkDevice, fence); +} + +VkResult VulkanLogicalDevice::ResetFence(VkFence fence) const +{ + auto err = vkResetFences(m_VkDevice, 1, &fence); + DEV_CHECK_ERR(err == VK_SUCCESS, "vkResetFences() failed"); + return err; +} + +VkResult VulkanLogicalDevice::WaitForFences(uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout) const +{ + return vkWaitForFences(m_VkDevice, fenceCount, pFences, waitAll, timeout); +} + +void VulkanLogicalDevice::UpdateDescriptorSets(uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites, + uint32_t descriptorCopyCount, + const VkCopyDescriptorSet* pDescriptorCopies) const +{ + vkUpdateDescriptorSets(m_VkDevice, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); +} + +VkResult VulkanLogicalDevice::ResetCommandPool(VkCommandPool vkCmdPool, + VkCommandPoolResetFlags flags) const +{ + auto err = vkResetCommandPool(m_VkDevice, vkCmdPool, flags); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset command pool"); + return err; +} + +VkResult VulkanLogicalDevice::ResetDescriptorPool(VkDescriptorPool vkDescriptorPool, + VkDescriptorPoolResetFlags flags) const +{ + auto err = vkResetDescriptorPool(m_VkDevice, vkDescriptorPool, flags); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset descriptor pool"); + return err; +} + +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp index ac79e6d0..cc36ed99 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp @@ -27,7 +27,7 @@ namespace VulkanUtilities { - + VulkanMemoryAllocation::~VulkanMemoryAllocation() { if (Page != nullptr) @@ -37,24 +37,28 @@ VulkanMemoryAllocation::~VulkanMemoryAllocation() } VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr, - VkDeviceSize PageSize, + VkDeviceSize PageSize, uint32_t MemoryTypeIndex, - bool IsHostVisible)noexcept : + bool IsHostVisible) noexcept : + // clang-format off m_ParentMemoryMgr{ParentMemoryMgr}, m_AllocationMgr {PageSize, ParentMemoryMgr.m_Allocator} +// clang-format on { VkMemoryAllocateInfo MemAlloc = {}; - MemAlloc.pNext = nullptr; - MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - MemAlloc.allocationSize = PageSize; + + MemAlloc.pNext = nullptr; + MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + MemAlloc.allocationSize = PageSize; MemAlloc.memoryTypeIndex = MemoryTypeIndex; auto MemoryName = Diligent::FormatString("Device memory page. Size: ", Diligent::FormatMemorySize(PageSize, 2), ", type: ", MemoryTypeIndex); - m_VkMemory = ParentMemoryMgr.m_LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str()); + m_VkMemory = ParentMemoryMgr.m_LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str()); if (IsHostVisible) { - auto err = ParentMemoryMgr.m_LogicalDevice.MapMemory(m_VkMemory, + auto err = ParentMemoryMgr.m_LogicalDevice.MapMemory( + m_VkMemory, 0, // offset PageSize, 0, // flags, reserved for future use @@ -77,12 +81,12 @@ VulkanMemoryPage::~VulkanMemoryPage() VulkanMemoryAllocation VulkanMemoryPage::Allocate(VkDeviceSize size, VkDeviceSize alignment) { std::lock_guard Lock{m_Mutex}; - auto Allocation = m_AllocationMgr.Allocate(size, alignment); + auto Allocation = m_AllocationMgr.Allocate(size, alignment); if (Allocation.IsValid()) { // Offset may not necessarily be aligned, but the allocation is guaranteed to be large enough // to accomodate requested alignment - VERIFY_EXPR( Diligent::Align(VkDeviceSize{Allocation.UnalignedOffset}, alignment) - Allocation.UnalignedOffset + size <= Allocation.Size ); + VERIFY_EXPR(Diligent::Align(VkDeviceSize{Allocation.UnalignedOffset}, alignment) - Allocation.UnalignedOffset + size <= Allocation.Size); return VulkanMemoryAllocation{this, Allocation.UnalignedOffset, Allocation.Size}; } else @@ -101,8 +105,8 @@ void VulkanMemoryPage::Free(VulkanMemoryAllocation&& Allocation) VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps) { - // memoryTypeBits is a bitmask and contains one bit set for every supported memory type for the resource. - // Bit i is set if and only if the memory type i in the VkPhysicalDeviceMemoryProperties structure for the + // memoryTypeBits is a bitmask and contains one bit set for every supported memory type for the resource. + // Bit i is set if and only if the memory type i in the VkPhysicalDeviceMemoryProperties structure for the // physical device is supported for the resource. auto MemoryTypeIndex = m_PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, MemoryProps); if (MemoryProps == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) @@ -113,7 +117,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& "at least one bit set corresponding to a VkMemoryType with a propertyFlags that has the " "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT bit set (11.6)"); } - else if ( (MemoryProps & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) + else if ((MemoryProps & (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { DEV_CHECK_ERR(MemoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex, "Vulkan spec requires that for a VkBuffer not created with the VK_BUFFER_CREATE_SPARSE_BINDING_BIT " @@ -136,16 +140,17 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDevice VulkanMemoryAllocation Allocation; // On integrated GPUs, there is no difference between host-visible and GPU-only - // memory, so MemoryTypeIndex is the same. As GPU-only pages do not have CPU address, + // memory, so MemoryTypeIndex is the same. As GPU-only pages do not have CPU address, // we need to use HostVisible flag to differentiate the two. - // It is likely a good idea to always keep staging pages separate to reduce fragmenation - // even though on integrated GPUs same pages can be used for both GPU-only and staging - // allocations. Staging allocations are short-living and will be released when upload is + // It is likely a good idea to always keep staging pages separate to reduce fragmenation + // even though on integrated GPUs same pages can be used for both GPU-only and staging + // allocations. Staging allocations are short-living and will be released when upload is // complete, while GPU-only allocations are expected to be long-living. - MemoryPageIndex PageIdx{MemoryTypeIndex, HostVisible}; + MemoryPageIndex PageIdx{MemoryTypeIndex, HostVisible}; std::lock_guard Lock{m_PagesMtx}; + auto range = m_Pages.equal_range(PageIdx); - for(auto page_it = range.first; page_it != range.second; ++page_it) + for (auto page_it = range.first; page_it != range.second; ++page_it) { Allocation = page_it->second.Allocate(Size, Alignment); if (Allocation.Page != nullptr) @@ -163,8 +168,8 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDevice m_PeakAllocatedSize[stat_ind] = std::max(m_PeakAllocatedSize[stat_ind], m_CurrAllocatedSize[stat_ind]); auto it = m_Pages.emplace(PageIdx, VulkanMemoryPage{*this, PageSize, MemoryTypeIndex, HostVisible}); - LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': created new ", (HostVisible ? "host-visible" : "device-local"), - " page. (", Diligent::FormatMemorySize(PageSize, 2), ", type idx: ", MemoryTypeIndex, + LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': created new ", (HostVisible ? "host-visible" : "device-local"), + " page. (", Diligent::FormatMemorySize(PageSize, 2), ", type idx: ", MemoryTypeIndex, "). Current allocated size: ", Diligent::FormatMemorySize(m_CurrAllocatedSize[stat_ind], 2)); OnNewPageCreated(it->second); Allocation = it->second.Allocate(Size, Alignment); @@ -193,16 +198,17 @@ void VulkanMemoryManager::ShrinkMemory() { auto curr_it = it; ++it; - auto& Page = curr_it->second; - bool IsHostVisible = Page.GetCPUMemory() != nullptr; - auto ReserveSize = IsHostVisible ? m_HostVisibleReserveSize : m_DeviceLocalReserveSize; + auto& Page = curr_it->second; + bool IsHostVisible = Page.GetCPUMemory() != nullptr; + auto ReserveSize = IsHostVisible ? m_HostVisibleReserveSize : m_DeviceLocalReserveSize; if (Page.IsEmpty() && m_CurrAllocatedSize[IsHostVisible ? 1 : 0] > ReserveSize) { auto PageSize = Page.GetPageSize(); m_CurrAllocatedSize[IsHostVisible ? 1 : 0] -= PageSize; - LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': destroying ", (IsHostVisible ? "host-visible" : "device-local"), - " page (", Diligent::FormatMemorySize(PageSize, 2), ")." - " Current allocated size: ", Diligent::FormatMemorySize(m_CurrAllocatedSize[IsHostVisible ? 1 : 0], 2)); + LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': destroying ", (IsHostVisible ? "host-visible" : "device-local"), + " page (", Diligent::FormatMemorySize(PageSize, 2), + "). Current allocated size: ", + Diligent::FormatMemorySize(m_CurrAllocatedSize[IsHostVisible ? 1 : 0], 2)); OnPageDestroy(Page); m_Pages.erase(curr_it); } @@ -211,7 +217,7 @@ void VulkanMemoryManager::ShrinkMemory() void VulkanMemoryManager::OnFreeAllocation(VkDeviceSize Size, bool IsHostVisble) { - m_CurrUsedSize[IsHostVisble ? 1 : 0].fetch_add( -static_cast(Size) ); + m_CurrUsedSize[IsHostVisble ? 1 : 0].fetch_add(-static_cast(Size)); } VulkanMemoryManager::~VulkanMemoryManager() @@ -219,19 +225,18 @@ VulkanMemoryManager::~VulkanMemoryManager() auto PeakDeviceLocalPages = m_PeakAllocatedSize[0] / m_DeviceLocalPageSize; auto PeakHostVisisblePages = m_PeakAllocatedSize[1] / m_HostVisiblePageSize; LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "' stats:\n" - " Peak used/allocated device-local memory size: ", - Diligent::FormatMemorySize(m_PeakUsedSize[0], 2, m_PeakAllocatedSize[0]), " / ", + " Peak used/allocated device-local memory size: ", + Diligent::FormatMemorySize(m_PeakUsedSize[0], 2, m_PeakAllocatedSize[0]), " / ", Diligent::FormatMemorySize(m_PeakAllocatedSize[0], 2, m_PeakAllocatedSize[0]), " (", PeakDeviceLocalPages, (PeakDeviceLocalPages == 1 ? " page)" : " pages)"), - "\n Peak used/allocated host-visible memory size: ", - Diligent::FormatMemorySize(m_PeakUsedSize[1], 2, m_PeakAllocatedSize[1]), " / ", + "\n Peak used/allocated host-visible memory size: ", + Diligent::FormatMemorySize(m_PeakUsedSize[1], 2, m_PeakAllocatedSize[1]), " / ", Diligent::FormatMemorySize(m_PeakAllocatedSize[1], 2, m_PeakAllocatedSize[1]), - " (", PeakHostVisisblePages, (PeakHostVisisblePages == 1 ? " page)" : " pages)") - ); - - for(auto it=m_Pages.begin(); it != m_Pages.end(); ++it ) + " (", PeakHostVisisblePages, (PeakHostVisisblePages == 1 ? " page)" : " pages)")); + + for (auto it = m_Pages.begin(); it != m_Pages.end(); ++it) VERIFY(it->second.IsEmpty(), "The page contains outstanding allocations"); VERIFY(m_CurrUsedSize[0] == 0 && m_CurrUsedSize[1] == 0, "Not all allocations have been released"); } -} +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index ba2e0dda..9a0677bd 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -28,174 +28,177 @@ namespace VulkanUtilities { - std::unique_ptr VulkanPhysicalDevice::Create(VkPhysicalDevice vkDevice) + +std::unique_ptr VulkanPhysicalDevice::Create(VkPhysicalDevice vkDevice) +{ + auto* PhysicalDevice = new VulkanPhysicalDevice{vkDevice}; + return std::unique_ptr{PhysicalDevice}; +} + +VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice) : + m_VkDevice{vkDevice} +{ + VERIFY_EXPR(m_VkDevice != VK_NULL_HANDLE); + + vkGetPhysicalDeviceProperties(m_VkDevice, &m_Properties); + vkGetPhysicalDeviceFeatures(m_VkDevice, &m_Features); + vkGetPhysicalDeviceMemoryProperties(m_VkDevice, &m_MemoryProperties); + uint32_t QueueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(m_VkDevice, &QueueFamilyCount, nullptr); + VERIFY_EXPR(QueueFamilyCount > 0); + m_QueueFamilyProperties.resize(QueueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(m_VkDevice, &QueueFamilyCount, m_QueueFamilyProperties.data()); + VERIFY_EXPR(QueueFamilyCount == m_QueueFamilyProperties.size()); + + // Get list of supported extensions + uint32_t ExtensionCount = 0; + vkEnumerateDeviceExtensionProperties(m_VkDevice, nullptr, &ExtensionCount, nullptr); + if (ExtensionCount > 0) { - auto* PhysicalDevice = new VulkanPhysicalDevice{vkDevice}; - return std::unique_ptr{PhysicalDevice}; + m_SupportedExtensions.resize(ExtensionCount); + auto res = vkEnumerateDeviceExtensionProperties(m_VkDevice, nullptr, &ExtensionCount, m_SupportedExtensions.data()); + VERIFY_EXPR(res == VK_SUCCESS); + (void)res; + VERIFY_EXPR(ExtensionCount == m_SupportedExtensions.size()); } +} - VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice) : - m_VkDevice{vkDevice} +uint32_t VulkanPhysicalDevice::FindQueueFamily(VkQueueFlags QueueFlags) const +{ + // All commands that are allowed on a queue that supports transfer operations are also allowed on + // a queue that supports either graphics or compute operations. Thus, if the capabilities of a queue + // family include VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT, then reporting the VK_QUEUE_TRANSFER_BIT + // capability separately for that queue family is optional (4.1). + VkQueueFlags QueueFlagsOpt = QueueFlags; + if (QueueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) { - VERIFY_EXPR(m_VkDevice != VK_NULL_HANDLE); - - vkGetPhysicalDeviceProperties(m_VkDevice, &m_Properties); - vkGetPhysicalDeviceFeatures(m_VkDevice, &m_Features); - vkGetPhysicalDeviceMemoryProperties(m_VkDevice, &m_MemoryProperties); - uint32_t QueueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(m_VkDevice, &QueueFamilyCount, nullptr); - VERIFY_EXPR(QueueFamilyCount> 0); - m_QueueFamilyProperties.resize(QueueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(m_VkDevice, &QueueFamilyCount, m_QueueFamilyProperties.data()); - VERIFY_EXPR(QueueFamilyCount == m_QueueFamilyProperties.size()); - - // Get list of supported extensions - uint32_t ExtensionCount = 0; - vkEnumerateDeviceExtensionProperties(m_VkDevice, nullptr, &ExtensionCount, nullptr); - if (ExtensionCount > 0) - { - m_SupportedExtensions.resize(ExtensionCount); - auto res = vkEnumerateDeviceExtensionProperties(m_VkDevice, nullptr, &ExtensionCount, m_SupportedExtensions.data()); - VERIFY_EXPR(res == VK_SUCCESS); (void)res; - VERIFY_EXPR(ExtensionCount == m_SupportedExtensions.size()); - } + QueueFlags &= ~VK_QUEUE_TRANSFER_BIT; + QueueFlagsOpt = QueueFlags | VK_QUEUE_TRANSFER_BIT; } - uint32_t VulkanPhysicalDevice::FindQueueFamily(VkQueueFlags QueueFlags)const + static constexpr uint32_t InvalidFamilyInd = std::numeric_limits::max(); + uint32_t FamilyInd = InvalidFamilyInd; + + for (uint32_t i = 0; i < m_QueueFamilyProperties.size(); ++i) { - // All commands that are allowed on a queue that supports transfer operations are also allowed on - // a queue that supports either graphics or compute operations. Thus, if the capabilities of a queue - // family include VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT, then reporting the VK_QUEUE_TRANSFER_BIT - // capability separately for that queue family is optional (4.1). - VkQueueFlags QueueFlagsOpt = QueueFlags; - if (QueueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) + // First try to find a queue, for which the flags match exactly + // (i.e. dedicated compute or transfer queue) + const auto& Props = m_QueueFamilyProperties[i]; + if (Props.queueFlags == QueueFlags || + Props.queueFlags == QueueFlagsOpt) { - QueueFlags &= ~VK_QUEUE_TRANSFER_BIT; - QueueFlagsOpt = QueueFlags | VK_QUEUE_TRANSFER_BIT; + FamilyInd = i; + break; } + } - static constexpr uint32_t InvalidFamilyInd = std::numeric_limits::max(); - uint32_t FamilyInd = InvalidFamilyInd; - - for(uint32_t i=0; i < m_QueueFamilyProperties.size(); ++i) + if (FamilyInd == InvalidFamilyInd) + { + for (uint32_t i = 0; i < m_QueueFamilyProperties.size(); ++i) { - // First try to find a queue, for which the flags match exactly - // (i.e. dedicated compute or transfer queue) - const auto &Props = m_QueueFamilyProperties[i]; - if( Props.queueFlags == QueueFlags || - Props.queueFlags == QueueFlagsOpt) + // Try to find a queue for which all requested flags are set + const auto& Props = m_QueueFamilyProperties[i]; + // Check only QueueFlags as VK_QUEUE_TRANSFER_BIT is + // optional for graphics and/or compute queues + if ((Props.queueFlags & QueueFlags) == QueueFlags) { FamilyInd = i; break; } } + } - if(FamilyInd == InvalidFamilyInd) - { - for (uint32_t i = 0; i < m_QueueFamilyProperties.size(); ++i) - { - // Try to find a queue for which all requested flags are set - const auto &Props = m_QueueFamilyProperties[i]; - // Check only QueueFlags as VK_QUEUE_TRANSFER_BIT is - // optional for graphics and/or compute queues - if ((Props.queueFlags & QueueFlags) == QueueFlags) - { - FamilyInd = i; - break; - } - } - } - - if (FamilyInd != InvalidFamilyInd) + if (FamilyInd != InvalidFamilyInd) + { + if (QueueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) { - if (QueueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) - { #ifdef _DEBUG - const auto& Props = m_QueueFamilyProperties[FamilyInd]; - // Queues supporting graphics and/or compute operations must report (1,1,1) - // in minImageTransferGranularity, meaning that there are no additional restrictions - // on the granularity of image transfer operations for these queues (4.1). - VERIFY_EXPR(Props.minImageTransferGranularity.width == 1 && - Props.minImageTransferGranularity.height == 1 && - Props.minImageTransferGranularity.depth == 1); + const auto& Props = m_QueueFamilyProperties[FamilyInd]; + // Queues supporting graphics and/or compute operations must report (1,1,1) + // in minImageTransferGranularity, meaning that there are no additional restrictions + // on the granularity of image transfer operations for these queues (4.1). + VERIFY_EXPR(Props.minImageTransferGranularity.width == 1 && + Props.minImageTransferGranularity.height == 1 && + Props.minImageTransferGranularity.depth == 1); #endif - } } - else - { - LOG_ERROR_AND_THROW("Failed to find suitable queue family"); - } - - return FamilyInd; } - - bool VulkanPhysicalDevice::IsExtensionSupported(const char *ExtensionName)const + else { - for(const auto& Extension : m_SupportedExtensions) - if(strcmp(Extension.extensionName, ExtensionName) == 0) - return true; - - return false; + LOG_ERROR_AND_THROW("Failed to find suitable queue family"); } - bool VulkanPhysicalDevice::CheckPresentSupport(uint32_t queueFamilyIndex, VkSurfaceKHR VkSurface)const - { - VkBool32 PresentSupport = VK_FALSE; - vkGetPhysicalDeviceSurfaceSupportKHR(m_VkDevice, queueFamilyIndex, VkSurface, &PresentSupport); - return PresentSupport == VK_TRUE; - } + return FamilyInd; +} +bool VulkanPhysicalDevice::IsExtensionSupported(const char* ExtensionName) const +{ + for (const auto& Extension : m_SupportedExtensions) + if (strcmp(Extension.extensionName, ExtensionName) == 0) + return true; - // This function is used to find a device memory type that supports all the property flags we request - // Params: - // * memoryTypeBitsRequirement - a bitmask that contains one bit set for every supported memory type for - // the resource. Bit i is set if and only if the memory type i in the - // VkPhysicalDeviceMemoryProperties structure for the physical device is - // supported for the resource. - // * requiredProperties - required memory properties (device local, host visible, etc.) - uint32_t VulkanPhysicalDevice::GetMemoryTypeIndex(uint32_t memoryTypeBitsRequirement, - VkMemoryPropertyFlags requiredProperties)const - { - // Iterate over all memory types available for the device - // For each pair of elements X and Y returned in memoryTypes, X must be placed at a lower index position than Y if: - // * either the set of bit flags of X is a strict subset of the set of bit flags of Y. - // * or the propertyFlags members of X and Y are equal, and X belongs to a memory heap with greater performance + return false; +} + +bool VulkanPhysicalDevice::CheckPresentSupport(uint32_t queueFamilyIndex, VkSurfaceKHR VkSurface) const +{ + VkBool32 PresentSupport = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR(m_VkDevice, queueFamilyIndex, VkSurface, &PresentSupport); + return PresentSupport == VK_TRUE; +} + + +// This function is used to find a device memory type that supports all the property flags we request +// Params: +// * memoryTypeBitsRequirement - a bitmask that contains one bit set for every supported memory type for +// the resource. Bit i is set if and only if the memory type i in the +// VkPhysicalDeviceMemoryProperties structure for the physical device is +// supported for the resource. +// * requiredProperties - required memory properties (device local, host visible, etc.) +uint32_t VulkanPhysicalDevice::GetMemoryTypeIndex(uint32_t memoryTypeBitsRequirement, + VkMemoryPropertyFlags requiredProperties) const +{ + // Iterate over all memory types available for the device + // For each pair of elements X and Y returned in memoryTypes, X must be placed at a lower index position than Y if: + // * either the set of bit flags of X is a strict subset of the set of bit flags of Y. + // * or the propertyFlags members of X and Y are equal, and X belongs to a memory heap with greater performance - for (uint32_t memoryIndex = 0; memoryIndex < m_MemoryProperties.memoryTypeCount; memoryIndex++) + for (uint32_t memoryIndex = 0; memoryIndex < m_MemoryProperties.memoryTypeCount; memoryIndex++) + { + // Each memory type returned by vkGetPhysicalDeviceMemoryProperties must have its propertyFlags set + // to one of the following values: + // * 0 + // * HOST_VISIBLE_BIT | HOST_COHERENT_BIT + // * HOST_VISIBLE_BIT | HOST_CACHED_BIT + // * HOST_VISIBLE_BIT | HOST_CACHED_BIT | HOST_COHERENT_BIT + // * DEVICE_LOCAL_BIT + // * DEVICE_LOCAL_BIT | HOST_VISIBLE_BIT | HOST_COHERENT_BIT + // * DEVICE_LOCAL_BIT | HOST_VISIBLE_BIT | HOST_CACHED_BIT + // * DEVICE_LOCAL_BIT | HOST_VISIBLE_BIT | HOST_CACHED_BIT | HOST_COHERENT_BIT + // * DEVICE_LOCAL_BIT | LAZILY_ALLOCATED_BIT + // + // There must be at least one memory type with both the HOST_VISIBLE_BIT and HOST_COHERENT_BIT bits set + // There must be at least one memory type with the DEVICE_LOCAL_BIT bit set + + const uint32_t memoryTypeBit = (1 << memoryIndex); + const bool isRequiredMemoryType = (memoryTypeBitsRequirement & memoryTypeBit) != 0; + if (isRequiredMemoryType) { - // Each memory type returned by vkGetPhysicalDeviceMemoryProperties must have its propertyFlags set - // to one of the following values: - // * 0 - // * HOST_VISIBLE_BIT | HOST_COHERENT_BIT - // * HOST_VISIBLE_BIT | HOST_CACHED_BIT - // * HOST_VISIBLE_BIT | HOST_CACHED_BIT | HOST_COHERENT_BIT - // * DEVICE_LOCAL_BIT - // * DEVICE_LOCAL_BIT | HOST_VISIBLE_BIT | HOST_COHERENT_BIT - // * DEVICE_LOCAL_BIT | HOST_VISIBLE_BIT | HOST_CACHED_BIT - // * DEVICE_LOCAL_BIT | HOST_VISIBLE_BIT | HOST_CACHED_BIT | HOST_COHERENT_BIT - // * DEVICE_LOCAL_BIT | LAZILY_ALLOCATED_BIT - // - // There must be at least one memory type with both the HOST_VISIBLE_BIT and HOST_COHERENT_BIT bits set - // There must be at least one memory type with the DEVICE_LOCAL_BIT bit set - - const uint32_t memoryTypeBit = (1 << memoryIndex); - const bool isRequiredMemoryType = (memoryTypeBitsRequirement & memoryTypeBit) != 0; - if(isRequiredMemoryType) - { - const VkMemoryPropertyFlags properties = m_MemoryProperties.memoryTypes[memoryIndex].propertyFlags; - const bool hasRequiredProperties = (properties & requiredProperties) == requiredProperties; + const VkMemoryPropertyFlags properties = m_MemoryProperties.memoryTypes[memoryIndex].propertyFlags; + const bool hasRequiredProperties = (properties & requiredProperties) == requiredProperties; - if (hasRequiredProperties) - return memoryIndex; - } + if (hasRequiredProperties) + return memoryIndex; } - return InvalidMemoryTypeIndex; } + return InvalidMemoryTypeIndex; +} - VkFormatProperties VulkanPhysicalDevice::GetPhysicalDeviceFormatProperties(VkFormat imageFormat)const - { - VkFormatProperties formatProperties; - vkGetPhysicalDeviceFormatProperties(m_VkDevice, imageFormat, &formatProperties); - return formatProperties; - } +VkFormatProperties VulkanPhysicalDevice::GetPhysicalDeviceFormatProperties(VkFormat imageFormat) const +{ + VkFormatProperties formatProperties; + vkGetPhysicalDeviceFormatProperties(m_VkDevice, imageFormat, &formatProperties); + return formatProperties; } + +} // namespace VulkanUtilities -- cgit v1.2.3