diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 225e3ed26..02ba3eed7 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -48,6 +48,7 @@ set(INCLUDE ) set(VULKAN_UTILS_INCLUDE + include/VulkanUtilities/RenderingInfoWrapper.hpp include/VulkanUtilities/VulkanCommandBuffer.hpp include/VulkanUtilities/VulkanCommandBufferPool.hpp include/VulkanUtilities/VulkanDebug.hpp @@ -128,6 +129,7 @@ set(SRC ) set(VULKAN_UTILS_SRC + src/VulkanUtilities/RenderingInfoWrapper.cpp src/VulkanUtilities/VulkanCommandBuffer.cpp src/VulkanUtilities/VulkanCommandBufferPool.cpp src/VulkanUtilities/VulkanDebug.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index 1a7ee9dbd..0a87189ae 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 Diligent Graphics LLC + * Copyright 2019-2025 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,6 +52,7 @@ #include "VulkanUtilities/VulkanCommandBufferPool.hpp" #include "VulkanUtilities/VulkanCommandBuffer.hpp" #include "VulkanUtilities/VulkanSyncObjectManager.hpp" +#include "VulkanUtilities/RenderingInfoWrapper.hpp" #include "VulkanUploadHeap.hpp" #include "VulkanDynamicHeap.hpp" #include "ResourceReleaseQueue.hpp" @@ -449,7 +450,7 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBaseGetCommandBuffer(); + VkCommandBuffer vkCmdBuff = m_CmdPool->GetCommandBuffer(); m_CommandBuffer.SetVkCmdBuffer(vkCmdBuff, m_CmdPool->GetSupportedStagesMask(), m_CmdPool->GetSupportedAccessMask()); } } @@ -489,6 +490,7 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase m_DynamicBufferOffsets; /// Temporary array used by CommitDescriptorSets - std::array m_DescriptorSets = {}; + std::array m_DescriptorSets = {}; /// Render pass that matches currently bound render targets. /// This render pass may or may not be currently set in the command buffer @@ -568,6 +570,9 @@ class DeviceContextVkImpl final : public DeviceContextNextGenBase m_DynamicRenderingInfo; + FixedBlockMemoryAllocator m_CmdListAllocator; // Semaphores are not owned by the command context diff --git a/Graphics/GraphicsEngineVulkan/include/FramebufferCache.hpp b/Graphics/GraphicsEngineVulkan/include/FramebufferCache.hpp index 1d38f151d..a3349f5cf 100644 --- a/Graphics/GraphicsEngineVulkan/include/FramebufferCache.hpp +++ b/Graphics/GraphicsEngineVulkan/include/FramebufferCache.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 Diligent Graphics LLC + * Copyright 2019-2025 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,8 +32,10 @@ #include #include +#include #include "VulkanUtilities/VulkanObjectWrappers.hpp" +#include "VulkanUtilities/RenderingInfoWrapper.hpp" namespace Diligent { @@ -77,7 +79,15 @@ class FramebufferCache void OnDestroyImageView(VkImageView ImgView); void OnDestroyRenderPass(VkRenderPass Pass); -private: + static std::unique_ptr CreateDyanmicRenderInfo( + const FramebufferCacheKey& Key, + bool UseDepthAttachment, + bool UseStencilAttachment, + uint32_t width, + uint32_t height, + uint32_t layers, + uint32_t viewMask); + RenderDeviceVkImpl& m_DeviceVk; struct FramebufferCacheKeyHash diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/RenderingInfoWrapper.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/RenderingInfoWrapper.hpp new file mode 100644 index 000000000..69f62f2ac --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/RenderingInfoWrapper.hpp @@ -0,0 +1,109 @@ +/* + * Copyright 2025 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include + +#include "VulkanHeaders.h" +#include "DebugUtilities.hpp" + +namespace VulkanUtilities +{ + +class RenderingInfoWrapper +{ +public: + RenderingInfoWrapper(size_t Hash, + uint32_t ColorAttachmentCount, + bool UseDepthAttachment, + bool UseStencilAttachment); + + // clang-format off + RenderingInfoWrapper (const RenderingInfoWrapper&) = delete; + RenderingInfoWrapper (RenderingInfoWrapper&&) = delete; + RenderingInfoWrapper& operator=(const RenderingInfoWrapper&) = delete; + RenderingInfoWrapper& operator=(RenderingInfoWrapper&&) = delete; + // clang-format on + + operator const VkRenderingInfoKHR&() const { return m_RI; } + + size_t GetHash() const { return m_Hash; } + + RenderingInfoWrapper& SetFlags(VkRenderingFlagsKHR flags) + { + m_RI.flags = flags; + return *this; + } + + RenderingInfoWrapper& SetRenderArea(const VkRect2D& renderArea) + { + m_RI.renderArea = renderArea; + return *this; + } + + RenderingInfoWrapper& SetLayerCount(uint32_t layerCount) + { + m_RI.layerCount = layerCount; + return *this; + } + + RenderingInfoWrapper& SetViewMask(uint32_t viewMask) + { + m_RI.viewMask = viewMask; + return *this; + } + + VkRenderingAttachmentInfoKHR& GetColorAttachment(uint32_t Index) + { + VERIFY_EXPR(Index < m_RI.colorAttachmentCount); + return m_Attachments[Index]; + } + + VkRenderingAttachmentInfoKHR& GetDepthAttachment() + { + VERIFY_EXPR(m_RI.pDepthAttachment != nullptr && m_DepthAttachmentIndex != ~0u); + return m_Attachments[m_DepthAttachmentIndex]; + } + + VkRenderingAttachmentInfoKHR& GetStencilAttachment() + { + VERIFY_EXPR(m_RI.pStencilAttachment != nullptr && m_StencilAttachmentIndex != ~0u); + return m_Attachments[m_StencilAttachmentIndex]; + } + +private: + VkRenderingInfoKHR m_RI; + + const size_t m_Hash = 0; + + std::unique_ptr m_Attachments; + + uint32_t m_DepthAttachmentIndex = ~0u; + uint32_t m_StencilAttachmentIndex = ~0u; +}; + +} // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp index c28e012dc..1398bafce 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp @@ -295,7 +295,7 @@ class VulkanCommandBuffer { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass == VK_NULL_HANDLE, "Current pass has not been ended"); - VERIFY(!m_State.RenderingBegan, "Current dynamic render pass has not been ended"); + VERIFY(m_State.DynamicRenderingHash == 0, "Current dynamic render pass has not been ended"); if (m_State.RenderPass != RenderPass || m_State.Framebuffer != Framebuffer) { @@ -354,28 +354,34 @@ class VulkanCommandBuffer vkCmdNextSubpass(m_VkCmdBuffer, VK_SUBPASS_CONTENTS_INLINE); } - __forceinline void BeginRendering(const VkRenderingInfoKHR& RenderingInfo) + __forceinline void BeginRendering(const VkRenderingInfoKHR& RenderingInfo, size_t Hash) { VERIFY(m_State.RenderPass == VK_NULL_HANDLE, "Another render pass has already been started"); - VERIFY(!m_State.RenderingBegan, "Rendering has already begun"); + VERIFY(m_State.DynamicRenderingHash == 0, "Rendering has already begun"); VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - vkCmdBeginRenderingKHR(m_VkCmdBuffer, &RenderingInfo); - m_State.RenderingBegan = true; + + if (m_State.DynamicRenderingHash != Hash) + { + FlushBarriers(); + + vkCmdBeginRenderingKHR(m_VkCmdBuffer, &RenderingInfo); + m_State.DynamicRenderingHash = Hash; + } } __forceinline void EndRendering() { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); - VERIFY(m_State.RenderingBegan, "Rendering has not begun"); + VERIFY(m_State.DynamicRenderingHash != 0, "Rendering has not begun"); vkCmdEndRenderingKHR(m_VkCmdBuffer); - m_State.RenderingBegan = false; + m_State.DynamicRenderingHash = 0; } __forceinline void EndRenderScope() { if (m_State.RenderPass != VK_NULL_HANDLE) EndRenderPass(); - else if (m_State.RenderingBegan) + else if (m_State.DynamicRenderingHash != 0) EndRendering(); } @@ -803,22 +809,22 @@ class VulkanCommandBuffer struct StateCache { - VkRenderPass RenderPass = VK_NULL_HANDLE; - VkFramebuffer Framebuffer = VK_NULL_HANDLE; - VkPipeline GraphicsPipeline = VK_NULL_HANDLE; - VkPipeline ComputePipeline = VK_NULL_HANDLE; - VkPipeline RayTracingPipeline = VK_NULL_HANDLE; - VkBuffer IndexBuffer = VK_NULL_HANDLE; - VkDeviceSize IndexBufferOffset = 0; - VkIndexType IndexType = VK_INDEX_TYPE_MAX_ENUM; - uint32_t FramebufferWidth = 0; - uint32_t FramebufferHeight = 0; - uint32_t InsidePassQueries = 0; - uint32_t OutsidePassQueries = 0; - bool RenderingBegan = false; + VkRenderPass RenderPass = VK_NULL_HANDLE; + VkFramebuffer Framebuffer = VK_NULL_HANDLE; + VkPipeline GraphicsPipeline = VK_NULL_HANDLE; + VkPipeline ComputePipeline = VK_NULL_HANDLE; + VkPipeline RayTracingPipeline = VK_NULL_HANDLE; + VkBuffer IndexBuffer = VK_NULL_HANDLE; + VkDeviceSize IndexBufferOffset = 0; + VkIndexType IndexType = VK_INDEX_TYPE_MAX_ENUM; + uint32_t FramebufferWidth = 0; + uint32_t FramebufferHeight = 0; + uint32_t InsidePassQueries = 0; + uint32_t OutsidePassQueries = 0; + size_t DynamicRenderingHash = 0; }; - __forceinline bool IsInRenderScope() const { return m_State.RenderPass != VK_NULL_HANDLE || m_State.RenderingBegan; } + __forceinline bool IsInRenderScope() const { return m_State.RenderPass != VK_NULL_HANDLE || m_State.DynamicRenderingHash != 0; } const StateCache& GetState() const { return m_State; } diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d5d9a5567..4d109c0cd 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -725,7 +725,7 @@ void DeviceContextVkImpl::DvpLogRenderPass_PSOMismatch() void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) { - if (m_vkFramebuffer == VK_NULL_HANDLE && m_State.NullRenderTargets) + if (m_vkFramebuffer == VK_NULL_HANDLE && !m_DynamicRenderingInfo && m_State.NullRenderTargets) { DEV_CHECK_ERR(m_FramebufferWidth > 0 && m_FramebufferHeight > 0, "Framebuffer width/height is zero. Call SetViewports to set the framebuffer sizes when no render targets are set."); @@ -736,8 +736,7 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) if ((Flags & DRAW_FLAG_VERIFY_RENDER_TARGETS) != 0) DvpVerifyRenderTargets(); - VERIFY(m_vkRenderPass != VK_NULL_HANDLE, "No render pass is active while executing draw command"); - VERIFY(m_vkFramebuffer != VK_NULL_HANDLE, "No framebuffer is bound while executing draw command"); + VERIFY((m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE) || m_DynamicRenderingInfo, "No render pass is active while executing draw command"); #endif EnsureVkCmdBuffer(); @@ -776,7 +775,9 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) if (m_pPipelineState->GetGraphicsPipelineDesc().pRenderPass == nullptr) { #ifdef DILIGENT_DEVELOPMENT - if (m_pPipelineState->GetRenderPass()->GetVkRenderPass() != m_vkRenderPass) + IRenderPassVk* pRenderPass = m_pPipelineState->GetRenderPass(); + VkRenderPass vkRenderPass = pRenderPass != nullptr ? pRenderPass->GetVkRenderPass() : VK_NULL_HANDLE; + if (vkRenderPass != m_vkRenderPass) { // Note that different Vulkan render passes may still be compatible, // so we should only verify implicit render passes @@ -1159,7 +1160,7 @@ void DeviceContextVkImpl::ClearDepthStencil(ITextureView* pView "checks if the DSV is bound as a framebuffer attachment and triggers an assert otherwise (in development mode)."); if (ClearAsAttachment) { - VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE); + VERIFY_EXPR((m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE) || m_DynamicRenderingInfo); if (m_pActiveRenderPass == nullptr) { // Render pass may not be currently committed @@ -1276,7 +1277,7 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const void* RGB if (attachmentIndex != InvalidAttachmentIndex) { - VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE); + VERIFY_EXPR((m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE) || m_DynamicRenderingInfo); if (m_pActiveRenderPass == nullptr) { // Render pass may not be currently committed @@ -1626,6 +1627,7 @@ void DeviceContextVkImpl::InvalidateState() m_BindInfo = {}; m_vkRenderPass = VK_NULL_HANDLE; m_vkFramebuffer = VK_NULL_HANDLE; + m_DynamicRenderingInfo.reset(); VERIFY(!m_CommandBuffer.IsInRenderScope(), "Invalidating context with unfinished render pass"); m_CommandBuffer.Reset(); @@ -1704,6 +1706,7 @@ void DeviceContextVkImpl::SetViewports(Uint32 NumViewports, const Viewport* pVie { // We need to bind another framebuffer since the size has changed m_vkFramebuffer = VK_NULL_HANDLE; + m_DynamicRenderingInfo.reset(); } m_FramebufferWidth = VPWidth; m_FramebufferHeight = VPHeight; @@ -1806,21 +1809,31 @@ void DeviceContextVkImpl::CommitRenderPassAndFramebuffer(bool VerifyStates) { VERIFY(m_pActiveRenderPass == nullptr, "This method must not be called inside an active render pass."); - if (m_CommandBuffer.GetState().Framebuffer != m_vkFramebuffer) + const size_t DynamicRenderingHash = m_DynamicRenderingInfo ? m_DynamicRenderingInfo->GetHash() : 0; + if ((m_CommandBuffer.GetState().Framebuffer != m_vkFramebuffer) || + (m_CommandBuffer.GetState().DynamicRenderingHash != DynamicRenderingHash)) { m_CommandBuffer.EndRenderScope(); - if (m_vkFramebuffer != VK_NULL_HANDLE) + if ((m_vkFramebuffer != VK_NULL_HANDLE) || (DynamicRenderingHash != 0)) { - VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE); #ifdef DILIGENT_DEVELOPMENT if (VerifyStates) { TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE_VERIFY); } #endif + } + + if (m_vkFramebuffer != VK_NULL_HANDLE) + { + VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE); m_CommandBuffer.BeginRenderPass(m_vkRenderPass, m_vkFramebuffer, m_FramebufferWidth, m_FramebufferHeight); } + else if (DynamicRenderingHash != 0) + { + m_CommandBuffer.BeginRendering(*m_DynamicRenderingInfo, DynamicRenderingHash); + } } } @@ -1880,7 +1893,6 @@ void DeviceContextVkImpl::ChooseRenderPassAndFramebuffer() FramebufferCache* FBCache = m_pDevice->GetFramebufferCache(); RenderPassCache* RPCache = m_pDevice->GetImplicitRenderPassCache(); - if (FBCache != nullptr && RPCache != nullptr) { if (RenderPassVkImpl* pRenderPass = RPCache->GetRenderPass(RenderPassKey)) @@ -1899,7 +1911,21 @@ void DeviceContextVkImpl::ChooseRenderPassAndFramebuffer() } else { - UNSUPPORTED("Dynamic rendering is not supported"); + bool UseDepthAttachment = false; + bool UseStencilAttachment = false; + if (m_pBoundDepthStencil) + { + const TEXTURE_FORMAT DepthStencilFmt = m_pBoundDepthStencil->GetTexture()->GetDesc().Format; + const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs(DepthStencilFmt); + + UseDepthAttachment = true; + UseStencilAttachment = FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL; + } + uint32_t ViewMask = (1u << m_NumViewports) - 1u; + + m_DynamicRenderingInfo = FramebufferCache::CreateDyanmicRenderInfo(FBKey, UseDepthAttachment, UseStencilAttachment, + m_FramebufferWidth, m_FramebufferHeight, m_FramebufferSlices, + ViewMask); } } @@ -1927,6 +1953,7 @@ void DeviceContextVkImpl::ResetRenderTargets() TDeviceContextBase::ResetRenderTargets(); m_vkRenderPass = VK_NULL_HANDLE; m_vkFramebuffer = VK_NULL_HANDLE; + m_DynamicRenderingInfo.reset(); if (m_CommandBuffer.GetVkCmdBuffer() != VK_NULL_HANDLE) m_CommandBuffer.EndRenderScope(); m_State.ShadingRateIsSet = false; @@ -1940,6 +1967,7 @@ void DeviceContextVkImpl::BeginRenderPass(const BeginRenderPassAttribs& Attribs) VERIFY_EXPR(m_pBoundFramebuffer != nullptr); VERIFY_EXPR(m_vkRenderPass == VK_NULL_HANDLE); VERIFY_EXPR(m_vkFramebuffer == VK_NULL_HANDLE); + VERIFY_EXPR(!m_DynamicRenderingInfo); m_vkRenderPass = m_pActiveRenderPass->GetVkRenderPass(); m_vkFramebuffer = m_pBoundFramebuffer->GetVkFramebuffer(); diff --git a/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp b/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp index 87ffc6fed..4ac11d154 100644 --- a/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp +++ b/Graphics/GraphicsEngineVulkan/src/FramebufferCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 Diligent Graphics LLC + * Copyright 2019-2025 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -98,7 +98,7 @@ VkFramebuffer FramebufferCache::GetFramebuffer(const FramebufferCacheKey& Key, u std::array Attachments; - auto& attachment = FramebufferCI.attachmentCount; + uint32_t& attachment = FramebufferCI.attachmentCount; if (Key.DSV != VK_NULL_HANDLE) Attachments[attachment++] = Key.DSV; @@ -115,8 +115,10 @@ VkFramebuffer FramebufferCache::GetFramebuffer(const FramebufferCacheKey& Key, u FramebufferCI.width = width; FramebufferCI.height = height; FramebufferCI.layers = layers; - auto Framebuffer = m_DeviceVk.GetLogicalDevice().CreateFramebuffer(FramebufferCI); - VkFramebuffer fb = Framebuffer; + + VulkanUtilities::FramebufferWrapper 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"); @@ -135,6 +137,53 @@ VkFramebuffer FramebufferCache::GetFramebuffer(const FramebufferCacheKey& Key, u } } +std::unique_ptr FramebufferCache::CreateDyanmicRenderInfo(const FramebufferCacheKey& Key, + bool UseDepthAttachment, + bool UseStencilAttachment, + uint32_t width, + uint32_t height, + uint32_t layers, + uint32_t viewMask) +{ + std::unique_ptr RI = std::make_unique( + Key.GetHash(), Key.NumRenderTargets, UseDepthAttachment, UseStencilAttachment); + + RI->SetRenderArea({{0, 0}, {width, height}}) + .SetLayerCount(layers) + .SetViewMask(viewMask); + + auto InitAttachment = [](VkRenderingAttachmentInfo& Attachment, VkImageView View, VkImageLayout Layout) { + Attachment.imageView = View; + Attachment.imageLayout = Layout; + Attachment.resolveMode = VK_RESOLVE_MODE_NONE_KHR; + Attachment.resolveImageView = VK_NULL_HANDLE; + Attachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + Attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + Attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + Attachment.clearValue = VkClearValue{}; + }; + + for (Uint32 rt = 0; rt < Key.NumRenderTargets; ++rt) + { + VkRenderingAttachmentInfo& RTAttachment = RI->GetColorAttachment(rt); + InitAttachment(RTAttachment, Key.RTVs[rt], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } + + if (UseDepthAttachment) + { + VkRenderingAttachmentInfo& DepthAttachment = RI->GetDepthAttachment(); + InitAttachment(DepthAttachment, Key.DSV, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + + if (UseStencilAttachment) + { + VkRenderingAttachmentInfo& StencilAttachment = RI->GetStencilAttachment(); + InitAttachment(StencilAttachment, Key.DSV, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + + return RI; +} + FramebufferCache::~FramebufferCache() { VERIFY(m_Cache.empty(), "All framebuffers must be released"); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/RenderingInfoWrapper.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/RenderingInfoWrapper.cpp new file mode 100644 index 000000000..9e2471545 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/RenderingInfoWrapper.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2025 Diligent Graphics LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "VulkanUtilities/RenderingInfoWrapper.hpp" + +namespace VulkanUtilities +{ + +RenderingInfoWrapper::RenderingInfoWrapper(size_t Hash, + uint32_t ColorAttachmentCount, + bool UseDepthAttachment, + bool UseStencilAttachment) : + m_RI{}, + m_Hash{Hash} +{ + m_RI.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; + m_RI.pNext = nullptr; + m_RI.flags = 0; + m_RI.colorAttachmentCount = ColorAttachmentCount; + + const uint32_t TotalAttachmentCount = ColorAttachmentCount + (UseDepthAttachment ? 1u : 0u) + (UseStencilAttachment ? 1u : 0u); + if (TotalAttachmentCount > 0) + { + m_Attachments = std::make_unique(TotalAttachmentCount); + for (size_t i = 0; i < TotalAttachmentCount; ++i) + m_Attachments[i].sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + } + uint32_t AttachmentInd = 0; + if (ColorAttachmentCount > 0) + { + m_RI.pColorAttachments = &m_Attachments[AttachmentInd]; + AttachmentInd += ColorAttachmentCount; + } + if (UseDepthAttachment) + { + m_DepthAttachmentIndex = AttachmentInd; + m_RI.pDepthAttachment = &m_Attachments[AttachmentInd]; + ++AttachmentInd; + } + if (UseStencilAttachment) + { + m_StencilAttachmentIndex = AttachmentInd; + m_RI.pStencilAttachment = &m_Attachments[AttachmentInd]; + ++AttachmentInd; + } + VERIFY_EXPR(AttachmentInd == TotalAttachmentCount); +} + +} // namespace VulkanUtilities