diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-08-15 22:42:13 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-08-15 22:42:13 +0000 |
| commit | df3a2c7c744eae194c79187a59914c6662f69b52 (patch) | |
| tree | 6f67919092b671b4a0fb637db26f75293f849886 /Graphics/GraphicsEngineVulkan | |
| parent | Fixed Visual Studio 16.7 build error (diff) | |
| parent | Vk backend: not setting render pass in SetPipelineState (diff) | |
| download | DiligentCore-df3a2c7c744eae194c79187a59914c6662f69b52.tar.gz DiligentCore-df3a2c7c744eae194c79187a59914c6662f69b52.zip | |
Added render passes to the API (fixed https://github.com/DiligentGraphics/DiligentCore/issues/9)
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
25 files changed, 1102 insertions, 191 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 28cf8b0f..93a811b1 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -11,6 +11,7 @@ set(INCLUDE include/DescriptorPoolManager.hpp include/DeviceContextVkImpl.hpp include/FenceVkImpl.hpp + include/FramebufferVkImpl.hpp include/VulkanDynamicHeap.hpp include/FramebufferCache.hpp include/GenerateMipsVkHelper.hpp @@ -20,6 +21,7 @@ set(INCLUDE include/QueryManagerVk.hpp include/QueryVkImpl.hpp include/RenderDeviceVkImpl.hpp + include/RenderPassVkImpl.hpp include/RenderPassCache.hpp include/SamplerVkImpl.hpp include/ShaderVkImpl.hpp @@ -57,9 +59,11 @@ set(INTERFACE interface/DeviceContextVk.h interface/EngineFactoryVk.h interface/FenceVk.h + interface/FramebufferVk.h interface/PipelineStateVk.h interface/QueryVk.h interface/RenderDeviceVk.h + interface/RenderPassVk.h interface/SamplerVk.h interface/ShaderVk.h interface/ShaderResourceBindingVk.h @@ -78,6 +82,7 @@ set(SRC src/DeviceContextVkImpl.cpp src/EngineFactoryVk.cpp src/FenceVkImpl.cpp + src/FramebufferVkImpl.cpp src/VulkanDynamicHeap.cpp src/FramebufferCache.cpp src/GenerateMipsVkHelper.cpp @@ -86,6 +91,7 @@ set(SRC src/QueryManagerVk.cpp src/QueryVkImpl.cpp src/RenderDeviceVkImpl.cpp + src/RenderPassVkImpl.cpp src/RenderPassCache.cpp src/SamplerVkImpl.cpp src/ShaderVkImpl.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index 83e2c077..ebca0282 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -45,6 +45,8 @@ #include "TextureVkImpl.hpp" #include "PipelineStateVkImpl.hpp" #include "QueryVkImpl.hpp" +#include "FramebufferVkImpl.hpp" +#include "RenderPassVkImpl.hpp" #include "HashUtils.hpp" #include "ManagedVulkanObject.hpp" #include "QueryManagerVk.hpp" @@ -53,8 +55,6 @@ namespace Diligent { -class RenderDeviceVkImpl; - struct DeviceContextVkImplTraits { using BufferType = BufferVkImpl; @@ -63,6 +63,8 @@ struct DeviceContextVkImplTraits using DeviceType = RenderDeviceVkImpl; using ICommandQueueType = ICommandQueueVk; using QueryType = QueryVkImpl; + using FramebufferType = FramebufferVkImpl; + using RenderPassType = RenderPassVkImpl; }; /// Device context implementation in Vulkan backend. @@ -133,6 +135,15 @@ public: ITextureView* pDepthStencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override final; + /// Implementation of IDeviceContext::BeginRenderPass() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::NextSubpass() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE NextSubpass() override final; + + /// Implementation of IDeviceContext::EndRenderPass() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE EndRenderPass() override final; + // clang-format off /// Implementation of IDeviceContext::Draw() in Vulkan backend. virtual void DILIGENT_CALL_TYPE Draw (const DrawAttribs& Attribs) override final; @@ -427,11 +438,11 @@ private: /// Render pass that matches currently bound render targets. /// This render pass may or may not be currently set in the command buffer - VkRenderPass m_RenderPass = VK_NULL_HANDLE; + VkRenderPass m_vkRenderPass = VK_NULL_HANDLE; /// Framebuffer that matches currently bound render targets. /// This framebuffer may or may not be currently set in the command buffer - VkFramebuffer m_Framebuffer = VK_NULL_HANDLE; + VkFramebuffer m_vkFramebuffer = VK_NULL_HANDLE; FixedBlockMemoryAllocator m_CmdListAllocator; @@ -489,6 +500,8 @@ private: std::unique_ptr<QueryManagerVk> m_QueryMgr; Int32 m_ActiveQueriesCounter = 0; + + std::vector<VkClearValue> m_vkClearValues; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/FramebufferVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/FramebufferVkImpl.hpp new file mode 100644 index 00000000..3e15852c --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/FramebufferVkImpl.hpp @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + +/// \file +/// Declaration of Diligent::FramebufferVkImpl class + +#include "FramebufferVk.h" +#include "FramebufferBase.hpp" +#include "RenderDeviceVkImpl.hpp" +#include "VulkanUtilities/VulkanObjectWrappers.hpp" + +namespace Diligent +{ + +class FixedBlockMemoryAllocator; + +/// Render pass implementation in Direct3D11 backend. +class FramebufferVkImpl final : public FramebufferBase<IFramebufferVk, RenderDeviceVkImpl> +{ +public: + using TFramebufferBase = FramebufferBase<IFramebufferVk, RenderDeviceVkImpl>; + + FramebufferVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDevice, + const FramebufferDesc& Desc); + ~FramebufferVkImpl(); + + VkFramebuffer GetVkFramebuffer() const override final + { + return m_VkFramebuffer; + } + +private: + VulkanUtilities::FramebufferWrapper m_VkFramebuffer; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index aca69cac..b8d5b0ec 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -68,8 +68,8 @@ public: /// Implementation of IPipelineState::IsCompatibleWith() in Vulkan backend. virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final; - /// Implementation of IPipelineStateVk::GetVkRenderPass(). - virtual VkRenderPass DILIGENT_CALL_TYPE GetVkRenderPass() const override final { return m_RenderPass; } + /// Implementation of IPipelineStateVk::GetRenderPass(). + virtual IRenderPassVk* DILIGENT_CALL_TYPE GetRenderPass() const override final { return m_pRenderPass.RawPtr<IRenderPassVk>(); } /// Implementation of IPipelineStateVk::GetVkPipeline(). virtual VkPipeline DILIGENT_CALL_TYPE GetVkPipeline() const override final { return m_Pipeline; } @@ -113,13 +113,13 @@ public: return m_SRBMemAllocator; } - static VkRenderPassCreateInfo GetRenderPassCreateInfo(Uint32 NumRenderTargets, - const TEXTURE_FORMAT RTVFormats[], - TEXTURE_FORMAT DSVFormat, - Uint32 SampleCount, - std::array<VkAttachmentDescription, MAX_RENDER_TARGETS + 1>& Attachments, - std::array<VkAttachmentReference, MAX_RENDER_TARGETS + 1>& AttachmentReferences, - VkSubpassDescription& SubpassDesc); + static RenderPassDesc GetImplicitRenderPassDesc(Uint32 NumRenderTargets, + const TEXTURE_FORMAT RTVFormats[], + TEXTURE_FORMAT DSVFormat, + Uint8 SampleCount, + std::array<RenderPassAttachmentDesc, MAX_RENDER_TARGETS + 1>& Attachments, + std::array<AttachmentReference, MAX_RENDER_TARGETS + 1>& AttachmentReferences, + SubpassDesc& SubpassDesc); void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const; @@ -152,7 +152,6 @@ private: std::array<VulkanUtilities::ShaderModuleWrapper, MAX_SHADERS_IN_PIPELINE> m_ShaderModules; - VkRenderPass m_RenderPass = VK_NULL_HANDLE; // Render passes are managed by the render device VulkanUtilities::PipelineWrapper m_Pipeline; PipelineLayout m_PipelineLayout; diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index 7204cad7..38bd4893 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -98,6 +98,19 @@ public: /// Implementation of IRenderDevice::CreateQuery() in Vulkan backend. virtual void DILIGENT_CALL_TYPE CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) override final; + /// Implementation of IRenderDevice::CreateRenderPass() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE CreateRenderPass(const RenderPassDesc& Desc, + IRenderPass** ppRenderPass) override final; + + void CreateRenderPass(const RenderPassDesc& Desc, + IRenderPass** ppRenderPass, + bool IsDeviceInternal); + + + /// Implementation of IRenderDevice::CreateFramebuffer() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE CreateFramebuffer(const FramebufferDesc& Desc, + IFramebuffer** ppFramebuffer) override final; + /// Implementation of IRenderDeviceVk::GetVkDevice(). virtual VkDevice DILIGENT_CALL_TYPE GetVkDevice() override final { return m_LogicalVkDevice->GetVkDevice(); } @@ -144,7 +157,7 @@ public: const VulkanUtilities::VulkanLogicalDevice& GetLogicalDevice() { return *m_LogicalVkDevice; } FramebufferCache& GetFramebufferCache() { return m_FramebufferCache; } - RenderPassCache& GetRenderPassCache() { return m_RenderPassCache; } + RenderPassCache& GetImplicitRenderPassCache() { return m_ImplicitRenderPassCache; } VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties) { @@ -173,7 +186,7 @@ private: EngineVkCreateInfo m_EngineAttribs; FramebufferCache m_FramebufferCache; - RenderPassCache m_RenderPassCache; + RenderPassCache m_ImplicitRenderPassCache; DescriptorSetAllocator m_DescriptorSetAllocator; DescriptorPoolManager m_DynamicDescriptorPool; diff --git a/Graphics/GraphicsEngineVulkan/include/RenderPassCache.hpp b/Graphics/GraphicsEngineVulkan/include/RenderPassCache.hpp index bfab6c53..ba21fcd9 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderPassCache.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderPassCache.hpp @@ -36,17 +36,18 @@ #include "Constants.h" #include "HashUtils.hpp" #include "VulkanUtilities/VulkanObjectWrappers.hpp" +#include "RefCntAutoPtr.hpp" namespace Diligent { class RenderDeviceVkImpl; +class RenderPassVkImpl; + class RenderPassCache { public: - RenderPassCache(RenderDeviceVkImpl& DeviceVk) noexcept : - m_DeviceVkImpl{DeviceVk} - {} + RenderPassCache(RenderDeviceVkImpl& DeviceVk) noexcept; // clang-format off RenderPassCache (const RenderPassCache&) = delete; @@ -123,7 +124,9 @@ public: mutable size_t Hash = 0; }; - VkRenderPass GetRenderPass(const RenderPassCacheKey& Key); + RenderPassVkImpl* GetRenderPass(const RenderPassCacheKey& Key); + + void Destroy(); private: struct RenderPassCacheKeyHash @@ -136,8 +139,8 @@ private: RenderDeviceVkImpl& m_DeviceVkImpl; - std::mutex m_Mutex; - std::unordered_map<RenderPassCacheKey, VulkanUtilities::RenderPassWrapper, RenderPassCacheKeyHash> m_Cache; + std::mutex m_Mutex; + std::unordered_map<RenderPassCacheKey, RefCntAutoPtr<RenderPassVkImpl>, RenderPassCacheKeyHash> m_Cache; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/RenderPassVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderPassVkImpl.hpp new file mode 100644 index 00000000..5c77784f --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/RenderPassVkImpl.hpp @@ -0,0 +1,63 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + +/// \file +/// Declaration of Diligent::RenderPassVkImpl class + +#include "RenderDeviceVk.h" +#include "RenderPassVk.h" +#include "RenderPassBase.hpp" +#include "RenderDeviceVkImpl.hpp" +#include "VulkanUtilities/VulkanObjectWrappers.hpp" + +namespace Diligent +{ + +class FixedBlockMemoryAllocator; + +/// Render pass implementation in Direct3D11 backend. +class RenderPassVkImpl final : public RenderPassBase<IRenderPassVk, RenderDeviceVkImpl> +{ +public: + using TRenderPassBase = RenderPassBase<IRenderPassVk, RenderDeviceVkImpl>; + + RenderPassVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDevice, + const RenderPassDesc& Desc, + bool IsDeviceInternal); + ~RenderPassVkImpl(); + + /// Implementation of ISamplerVk::GetVkRenderPass(). + virtual VkRenderPass DILIGENT_CALL_TYPE GetVkRenderPass() const override final { return m_VkRenderPass; } + +private: + VulkanUtilities::RenderPassWrapper m_VkRenderPass; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp index 172c82a8..a5278cb7 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp @@ -117,6 +117,7 @@ public: VkDescriptorImageInfo GetImageDescriptorWriteInfo (bool IsImmutableSampler)const; VkBufferView GetBufferViewWriteInfo () const; VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const; + VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const; // clang-format on }; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp index 07050821..a6d20641 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp @@ -260,6 +260,11 @@ public: VkDescriptorSet vkDescrSet, Uint32 ArrayInd) const; + void CacheInputAttachment(IDeviceObject* pTexView, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd) const; + template <typename ObjectType, typename TPreUpdateObject> bool UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes, RefCntAutoPtr<ObjectType>&& pObject, diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp index 15420ead..dbba5b7e 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp @@ -65,7 +65,7 @@ VkSamplerAddressMode AddressModeToVkAddressMode(TEXTURE_ADDRESS_MODE AddressMode VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[]); VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags); -VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag); +VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsideRenderPass = false); RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags); RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout); @@ -73,4 +73,13 @@ RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout); SURFACE_TRANSFORM VkSurfaceTransformFlagToSurfaceTransform(VkSurfaceTransformFlagBitsKHR vkTransformFlag); VkSurfaceTransformFlagBitsKHR SurfaceTransformToVkSurfaceTransformFlag(SURFACE_TRANSFORM SrfTransform); +VkAttachmentLoadOp AttachmentLoadOpToVkAttachmentLoadOp(ATTACHMENT_LOAD_OP LoadOp); +ATTACHMENT_LOAD_OP VkAttachmentLoadOpToAttachmentLoadOp(VkAttachmentLoadOp VkLoadOp); + +VkAttachmentStoreOp AttachmentStoreOpToVkAttachmentStoreOp(ATTACHMENT_STORE_OP StoreOp); +ATTACHMENT_STORE_OP VkAttachmentStoreOpToAttachmentStoreOp(VkAttachmentStoreOp VkStoreOp); + +VkPipelineStageFlags PipelineStageFlagsToVkPipelineStageFlags(PIPELINE_STAGE_FLAGS PipelineStageFlags); +VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags); + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp index 1465024b..5b4fc1e7 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp @@ -156,7 +156,12 @@ public: vkCmdDispatchIndirect(m_VkCmdBuffer, Buffer, Offset); } - __forceinline void BeginRenderPass(VkRenderPass RenderPass, VkFramebuffer Framebuffer, uint32_t FramebufferWidth, uint32_t FramebufferHeight) + __forceinline void BeginRenderPass(VkRenderPass RenderPass, + VkFramebuffer Framebuffer, + uint32_t FramebufferWidth, + uint32_t FramebufferHeight, + uint32_t ClearValueCount = 0, + const VkClearValue* pClearValues = nullptr) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); VERIFY(m_State.RenderPass == VK_NULL_HANDLE, "Current pass has not been ended"); @@ -170,13 +175,13 @@ public: BeginInfo.framebuffer = Framebuffer; // The render area MUST be contained within the framebuffer dimensions (7.4) BeginInfo.renderArea = {{0, 0}, {FramebufferWidth, FramebufferHeight}}; - BeginInfo.clearValueCount = 0; - BeginInfo.pClearValues = nullptr; // an array of VkClearValue structures that contains clear values for - // each attachment, if the attachment uses a loadOp value of VK_ATTACHMENT_LOAD_OP_CLEAR - // or if the attachment has a depth/stencil format and uses a stencilLoadOp value of - // VK_ATTACHMENT_LOAD_OP_CLEAR. The array is indexed by attachment number. Only elements - // corresponding to cleared attachments are used. Other elements of pClearValues are - // ignored (7.4) + BeginInfo.clearValueCount = ClearValueCount; + BeginInfo.pClearValues = pClearValues; // an array of VkClearValue structures that contains clear values for + // each attachment, if the attachment uses a loadOp value of VK_ATTACHMENT_LOAD_OP_CLEAR + // or if the attachment has a depth/stencil format and uses a stencilLoadOp value of + // VK_ATTACHMENT_LOAD_OP_CLEAR. The array is indexed by attachment number. Only elements + // corresponding to cleared attachments are used. Other elements of pClearValues are + // ignored (7.4) vkCmdBeginRenderPass(m_VkCmdBuffer, &BeginInfo, VK_SUBPASS_CONTENTS_INLINE // the contents of the subpass will be recorded inline in the @@ -208,6 +213,13 @@ public: } } + __forceinline void NextSubpass() + { + VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "Render pass has not been started"); + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + vkCmdNextSubpass(m_VkCmdBuffer, VK_SUBPASS_CONTENTS_INLINE); + } + __forceinline void EndCommandBuffer() { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); diff --git a/Graphics/GraphicsEngineVulkan/interface/FramebufferVk.h b/Graphics/GraphicsEngineVulkan/interface/FramebufferVk.h new file mode 100644 index 00000000..9edfb2eb --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/interface/FramebufferVk.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + +/// \file +/// Definition of the Diligent::IFramebufferVk interface + +#include "../../GraphicsEngine/interface/Framebuffer.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {846BE360-D89B-41AD-B089-7F2439ADCE3A} +static const INTERFACE_ID IID_FramebufferVk = + {0x846be360, 0xd89b, 0x41ad, {0xb0, 0x89, 0x7f, 0x24, 0x39, 0xad, 0xce, 0x3a}}; + +#define DILIGENT_INTERFACE_NAME IFramebufferVk +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define IFramebufferVkInclusiveMethods \ + /*IFramebufferInclusiveMethods*/ IDeviceObjectInclusiveMethods; \ + IFramebufferVkMethods FramebufferVk + +/// Exposes Vulkan-specific functionality of a Framebuffer object. +DILIGENT_BEGIN_INTERFACE(IFramebufferVk, IFramebuffer) +{ + /// Returns a Vulkan framebuffer object handle + VIRTUAL VkFramebuffer METHOD(GetVkFramebuffer)() CONST PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define IFramebufferVk_GetVkFramebuffer(This) CALL_IFACE_METHOD(FramebufferVk, GetVkFramebuffer, This) + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h b/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h index 679b6e73..f3377f08 100644 --- a/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h +++ b/Graphics/GraphicsEngineVulkan/interface/PipelineStateVk.h @@ -31,6 +31,7 @@ /// Definition of the Diligent::IPipeplineStateVk interface #include "../../GraphicsEngine/interface/PipelineState.h" +#include "RenderPassVk.h" DILIGENT_BEGIN_NAMESPACE(Diligent) @@ -48,8 +49,8 @@ static const INTERFACE_ID IID_PipelineStateVk = /// Exposes Vulkan-specific functionality of a pipeline state object. DILIGENT_BEGIN_INTERFACE(IPipelineStateVk, IPipelineState) { - /// Returns handle to a vulkan render pass object. - VIRTUAL VkRenderPass METHOD(GetVkRenderPass)(THIS) CONST PURE; + /// Returns the pointer to the internal render pass object. + VIRTUAL IRenderPassVk* METHOD(GetRenderPass)(THIS) CONST PURE; /// Returns handle to a vulkan pipeline pass object. VIRTUAL VkPipeline METHOD(GetVkPipeline)(THIS) CONST PURE; @@ -62,8 +63,8 @@ DILIGENT_END_INTERFACE // clang-format off -# define IPipelineStateVk_GetVkRenderPass(This) CALL_IFACE_METHOD(PipelineStateVk, GetVkRenderPass, This) -# define IPipelineStateVk_GetVkPipeline(This) CALL_IFACE_METHOD(PipelineStateVk, GetVkPipeline, This) +# define IPipelineStateVk_GetRenderPass(This) CALL_IFACE_METHOD(PipelineStateVk, GetRenderPass, This) +# define IPipelineStateVk_GetVkPipeline(This) CALL_IFACE_METHOD(PipelineStateVk, GetVkPipeline, This) // clang-format on diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderPassVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderPassVk.h new file mode 100644 index 00000000..6096e723 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/interface/RenderPassVk.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 + +/// \file +/// Definition of the Diligent::IRenderPassVk interface + +#include "../../GraphicsEngine/interface/RenderPass.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {3DE6938F-D34D-4135-A6FA-15A89E9525D0} +static const INTERFACE_ID IID_RenderPassVk = + {0x3de6938f, 0xd34d, 0x4135, {0xa6, 0xfa, 0x15, 0xa8, 0x9e, 0x95, 0x25, 0xd0}}; + +#define DILIGENT_INTERFACE_NAME IRenderPassVk +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define IRenderPassVkInclusiveMethods \ + /*IRenderPassInclusiveMethods*/ IDeviceObjectInclusiveMethods; \ + IRenderPassVkMethods RenderPassVk + +/// Exposes Vulkan-specific functionality of a RenderPass object. +DILIGENT_BEGIN_INTERFACE(IRenderPassVk, IRenderPass) +{ + /// Returns a Vulkan RenderPass object handle + VIRTUAL VkRenderPass METHOD(GetVkRenderPass)() CONST PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define IRenderPassVk_GetVkRenderPass(This) CALL_IFACE_METHOD(RenderPassVk, GetVkRenderPass, This) + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d61ddc97..619ec23c 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -32,6 +32,7 @@ #include "PipelineStateVkImpl.hpp" #include "TextureVkImpl.hpp" #include "BufferVkImpl.hpp" +#include "RenderPassVkImpl.hpp" #include "VulkanTypeConversions.hpp" #include "CommandListVkImpl.hpp" #include "FenceVkImpl.hpp" @@ -114,6 +115,8 @@ DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* p RefCntAutoPtr<IBuffer> pDummyVB; m_pDevice->CreateBuffer(DummyVBDesc, nullptr, &pDummyVB); m_DummyVB = pDummyVB.RawPtr<BufferVkImpl>(); + + m_vkClearValues.reserve(16); } DeviceContextVkImpl::~DeviceContextVkImpl() @@ -176,7 +179,7 @@ void DeviceContextVkImpl::DisposeVkCmdBuffer(Uint32 CmdQueue, VkCommandBuffer vk public: // clang-format off CmdBufferDeleter(VkCommandBuffer _vkCmdBuff, - VulkanUtilities::VulkanCommandBufferPool& _Pool) noexcept : + VulkanUtilities::VulkanCommandBufferPool& _Pool) noexcept : vkCmdBuff {_vkCmdBuff}, Pool {&_Pool } { @@ -231,9 +234,11 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) if (PipelineStateVkImpl::IsSameObject(m_pPipelineState, pPipelineStateVk)) return; - // Never flush deferred context! - // A query must begin and end in the same command buffer (17.2) - if (!m_bIsDeferred && m_State.NumCommands >= m_NumCommandsToFlush && m_ActiveQueriesCounter == 0) + if (m_State.NumCommands >= m_NumCommandsToFlush && + !m_bIsDeferred && // Never flush deferred context + !m_pActiveRenderPass && // Never flush inside active render pass (https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-vkEndCommandBuffer-commandBuffer-00060) + m_ActiveQueriesCounter == 0 // A query must begin and end in the same command buffer (17.2) + ) { Flush(); } @@ -278,7 +283,6 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) { m_CommandBuffer.SetStencilReference(m_StencilRef); m_CommandBuffer.SetBlendConstants(m_BlendFactors); - CommitRenderPassAndFramebuffer(true); CommitViewports(); } @@ -293,7 +297,12 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) void DeviceContextVkImpl::TransitionShaderResources(IPipelineState* pPipelineState, IShaderResourceBinding* pShaderResourceBinding) { - VERIFY_EXPR(pPipelineState != nullptr); + DEV_CHECK_ERR(pPipelineState != nullptr, "Pipeline state must mot be null"); + if (m_pActiveRenderPass) + { + LOG_ERROR_MESSAGE("State transitions are not allowed inside a render pass."); + return; + } auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState); pPipelineStateVk->CommitAndTransitionShaderResources(pShaderResourceBinding, this, false, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, nullptr); @@ -417,6 +426,9 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) #ifdef DILIGENT_DEVELOPMENT 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"); #endif EnsureVkCmdBuffer(); @@ -460,14 +472,19 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) # endif #endif -#ifdef DILIGENT_DEVELOPMENT - if (m_pPipelineState->GetVkRenderPass() != m_RenderPass) + if (m_pPipelineState->GetDesc().GraphicsPipeline.pRenderPass == nullptr) { - DvpLogRenderPass_PSOMismatch(); - } +#ifdef DILIGENT_DEVELOPMENT + if (m_pPipelineState->GetRenderPass()->GetVkRenderPass() != m_vkRenderPass) + { + // Note that different Vulkan render passes may still be compatible, + // so we should only verify implicit render passes + 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) @@ -631,13 +648,21 @@ void DeviceContextVkImpl::ClearDepthStencil(ITextureView* pView 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) + bool ClearAsAttachment = pVkDSV == m_pBoundDepthStencil; + VERIFY(m_pActiveRenderPass == nullptr || ClearAsAttachment, + "DSV was not found in the framebuffer. This is unexpected because TDeviceContextBase::ClearDepthStencil " + "checks if the DSV is bound as a framebuffer attachment and returns false otherwise (in development mode)."); + if (ClearAsAttachment) { - // 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); + VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE); + if (m_pActiveRenderPass == nullptr) + { + // Render pass may not be currently committed + + TransitionRenderTargets(StateTransitionMode); + // No need to verify states again + CommitRenderPassAndFramebuffer(false); + } VkClearAttachment ClearAttachment = {}; ClearAttachment.aspectMask = 0; @@ -732,7 +757,7 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const float* RG 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<Uint32>(-1); + static constexpr const Uint32 InvalidAttachmentIndex = ~Uint32{0}; Uint32 attachmentIndex = InvalidAttachmentIndex; for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) @@ -744,13 +769,21 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const float* RG } } + VERIFY(m_pActiveRenderPass == nullptr || attachmentIndex != InvalidAttachmentIndex, + "Render target was not found in the framebuffer. This is unexpected because TDeviceContextBase::ClearRenderTarget " + "checks if the RTV is bound as a framebuffer attachment and returns false otherwise (in development mode)."); + 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); + VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE && m_vkFramebuffer != VK_NULL_HANDLE); + if (m_pActiveRenderPass == nullptr) + { + // Render pass may not be currently committed + + TransitionRenderTargets(StateTransitionMode); + // No need to verify states again + CommitRenderPassAndFramebuffer(false); + } VkClearAttachment ClearAttachment = {}; ClearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -773,6 +806,8 @@ void DeviceContextVkImpl::ClearRenderTarget(ITextureView* pView, const float* RG } else { + VERIFY(m_pActiveRenderPass == nullptr, "This branch should never execute inside a render pass."); + // End current render pass and clear the image with vkCmdClearColorImage if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) m_CommandBuffer.EndRenderPass(); @@ -837,6 +872,11 @@ void DeviceContextVkImpl::FinishFrame() "All queries must be ended before the frame is finished."); } + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Finishing frame inside an active render pass."); + } + 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."); @@ -866,14 +906,19 @@ void DeviceContextVkImpl::Flush() { if (m_bIsDeferred) { - LOG_ERROR_MESSAGE("Flush() should only be called for immediate contexts"); + LOG_ERROR_MESSAGE("Flush() should only be called for immediate contexts."); return; } if (m_ActiveQueriesCounter > 0) { LOG_ERROR_MESSAGE("Flushing device context that has ", m_ActiveQueriesCounter, - " active queries. Vulkan requires that queries are begun and ended in the same command buffer"); + " active queries. Vulkan requires that queries are begun and ended in the same command buffer."); + } + + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Flushing device context inside an active render pass."); } VkSubmitInfo SubmitInfo = {}; @@ -933,7 +978,9 @@ void DeviceContextVkImpl::Flush() m_State = ContextState{}; m_DescrSetBindInfo.Reset(); m_CommandBuffer.Reset(); - m_pPipelineState = nullptr; + m_pPipelineState = nullptr; + m_pActiveRenderPass = nullptr; + m_pBoundFramebuffer = nullptr; } void DeviceContextVkImpl::SetVertexBuffers(Uint32 StartSlot, @@ -962,9 +1009,9 @@ void DeviceContextVkImpl::InvalidateState() 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_State = ContextState{}; + m_vkRenderPass = VK_NULL_HANDLE; + m_vkFramebuffer = VK_NULL_HANDLE; m_DescrSetBindInfo.Reset(); VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Invalidating context with unifinished render pass"); m_CommandBuffer.Reset(); @@ -1078,6 +1125,9 @@ void DeviceContextVkImpl::SetScissorRects(Uint32 NumRects, const Rect* pRects, U void DeviceContextVkImpl::TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { + VERIFY(StateTransitionMode != RESOURCE_STATE_TRANSITION_MODE_TRANSITION || m_pActiveRenderPass == nullptr, + "State transitions are not allowed inside a render pass."); + if (m_pBoundDepthStencil) { auto* pDepthBufferVk = ValidatedCast<TextureVkImpl>(m_pBoundDepthStencil->GetTexture()); @@ -1098,22 +1148,24 @@ void DeviceContextVkImpl::TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE void DeviceContextVkImpl::CommitRenderPassAndFramebuffer(bool VerifyStates) { + VERIFY(m_pActiveRenderPass == nullptr, "This method must not be called inside an active render pass."); + const auto& CmdBufferState = m_CommandBuffer.GetState(); - if (CmdBufferState.Framebuffer != m_Framebuffer) + if (CmdBufferState.Framebuffer != m_vkFramebuffer) { if (CmdBufferState.RenderPass != VK_NULL_HANDLE) m_CommandBuffer.EndRenderPass(); - if (m_Framebuffer != VK_NULL_HANDLE) + if (m_vkFramebuffer != VK_NULL_HANDLE) { - VERIFY_EXPR(m_RenderPass != VK_NULL_HANDLE); + VERIFY_EXPR(m_vkRenderPass != VK_NULL_HANDLE); #ifdef DILIGENT_DEVELOPMENT if (VerifyStates) { TransitionRenderTargets(RESOURCE_STATE_TRANSITION_MODE_VERIFY); } #endif - m_CommandBuffer.BeginRenderPass(m_RenderPass, m_Framebuffer, m_FramebufferWidth, m_FramebufferHeight); + m_CommandBuffer.BeginRenderPass(m_vkRenderPass, m_vkFramebuffer, m_FramebufferWidth, m_FramebufferHeight); } } } @@ -1123,6 +1175,14 @@ void DeviceContextVkImpl::SetRenderTargets(Uint32 NumRen ITextureView* pDepthStencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { +#ifdef DILIGENT_DEVELOPMENT + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Calling SetRenderTargets inside active render pass is invalid. End the render pass first"); + return; + } +#endif + if (TDeviceContextBase::SetRenderTargets(NumRenderTargets, ppRenderTargets, pDepthStencil)) { FramebufferCache::FramebufferCacheKey FBKey; @@ -1163,12 +1223,12 @@ void DeviceContextVkImpl::SetRenderTargets(Uint32 NumRen } auto& FBCache = m_pDevice->GetFramebufferCache(); - auto& RPCache = m_pDevice->GetRenderPassCache(); + auto& RPCache = m_pDevice->GetImplicitRenderPassCache(); - m_RenderPass = RPCache.GetRenderPass(RenderPassKey); - FBKey.Pass = m_RenderPass; + m_vkRenderPass = RPCache.GetRenderPass(RenderPassKey)->GetVkRenderPass(); + FBKey.Pass = m_vkRenderPass; FBKey.CommandQueueMask = ~Uint64{0}; - m_Framebuffer = FBCache.GetFramebuffer(FBKey, m_FramebufferWidth, m_FramebufferHeight, m_FramebufferSlices); + m_vkFramebuffer = FBCache.GetFramebuffer(FBKey, m_FramebufferWidth, m_FramebufferHeight, m_FramebufferSlices); // Set the viewport to match the render target size SetViewports(1, nullptr, 0, 0); @@ -1184,12 +1244,81 @@ void DeviceContextVkImpl::SetRenderTargets(Uint32 NumRen void DeviceContextVkImpl::ResetRenderTargets() { TDeviceContextBase::ResetRenderTargets(); - m_RenderPass = VK_NULL_HANDLE; - m_Framebuffer = VK_NULL_HANDLE; + m_vkRenderPass = VK_NULL_HANDLE; + m_vkFramebuffer = VK_NULL_HANDLE; if (m_CommandBuffer.GetVkCmdBuffer() != VK_NULL_HANDLE && m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) m_CommandBuffer.EndRenderPass(); } +void DeviceContextVkImpl::BeginRenderPass(const BeginRenderPassAttribs& Attribs) +{ + TDeviceContextBase::BeginRenderPass(Attribs); + + VERIFY_EXPR(m_pActiveRenderPass != nullptr); + VERIFY_EXPR(m_pBoundFramebuffer != nullptr); + VERIFY_EXPR(m_vkRenderPass == VK_NULL_HANDLE); + VERIFY_EXPR(m_vkFramebuffer == VK_NULL_HANDLE); + + m_vkRenderPass = m_pActiveRenderPass->GetVkRenderPass(); + m_vkFramebuffer = m_pBoundFramebuffer->GetVkFramebuffer(); + + VkClearValue* pVkClearValues = nullptr; + if (Attribs.ClearValueCount > 0) + { + m_vkClearValues.resize(Attribs.ClearValueCount); + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + for (Uint32 i = 0; i < std::min(RPDesc.AttachmentCount, Attribs.ClearValueCount); ++i) + { + const auto& ClearVal = Attribs.pClearValues[i]; + auto& vkClearVal = m_vkClearValues[i]; + + const auto& FmtAttribs = GetTextureFormatAttribs(RPDesc.pAttachments[i].Format); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH || + FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + vkClearVal.depthStencil.depth = ClearVal.DepthStencil.Depth; + vkClearVal.depthStencil.stencil = ClearVal.DepthStencil.Stencil; + } + else + { + vkClearVal.color.float32[0] = ClearVal.Color[0]; + vkClearVal.color.float32[1] = ClearVal.Color[1]; + vkClearVal.color.float32[2] = ClearVal.Color[2]; + vkClearVal.color.float32[3] = ClearVal.Color[3]; + } + } + pVkClearValues = m_vkClearValues.data(); + } + + EnsureVkCmdBuffer(); + m_CommandBuffer.BeginRenderPass(m_vkRenderPass, m_vkFramebuffer, m_FramebufferWidth, m_FramebufferHeight, Attribs.ClearValueCount, pVkClearValues); + + // Set the viewport to match the framebuffer size + SetViewports(1, nullptr, 0, 0); +} + +void DeviceContextVkImpl::NextSubpass() +{ + TDeviceContextBase::NextSubpass(); + VERIFY_EXPR(m_CommandBuffer.GetVkCmdBuffer() != VK_NULL_HANDLE && m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE); + m_CommandBuffer.NextSubpass(); +} + +void DeviceContextVkImpl::EndRenderPass() +{ + TDeviceContextBase::EndRenderPass(); + // TDeviceContextBase::EndRenderPass calls ResetRenderTargets() that in turn + // calls m_CommandBuffer.EndRenderPass() + + if (m_State.NumCommands >= m_NumCommandsToFlush && + !m_bIsDeferred && // Never flush deferred context + m_ActiveQueriesCounter == 0 // A query must begin and end in the same command buffer (17.2) + ) + { + Flush(); + } +} + void DeviceContextVkImpl::UpdateBufferRegion(BufferVkImpl* pBuffVk, Uint64 DstOffset, Uint64 NumBytes, @@ -1948,6 +2077,8 @@ void DeviceContextVkImpl::UnmapTextureSubresource(ITexture* pTexture, void DeviceContextVkImpl::FinishCommandList(class ICommandList** ppCommandList) { + VERIFY(m_pActiveRenderPass == nullptr, "Finishing command list inside an active render pass."); + if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE) { m_CommandBuffer.EndRenderPass(); @@ -2112,6 +2243,7 @@ void DeviceContextVkImpl::EndQuery(IQuery* pQuery) void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayout NewLayout) { VERIFY_EXPR(pTexture != nullptr); + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); auto pTextureVk = ValidatedCast<TextureVkImpl>(pTexture); if (!pTextureVk->IsInKnownState()) { @@ -2131,6 +2263,7 @@ void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& Textur bool UpdateTextureState, VkImageSubresourceRange* pSubresRange /* = nullptr*/) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (OldState == RESOURCE_STATE_UNKNOWN) { if (TextureVk.IsInKnownState()) @@ -2206,6 +2339,7 @@ void DeviceContextVkImpl::TransitionOrVerifyTextureState(TextureVkImpl& { if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (Texture.IsInKnownState()) { if (!Texture.CheckState(RequiredState)) @@ -2253,6 +2387,7 @@ void DeviceContextVkImpl::BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags Ne void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE_STATE OldState, RESOURCE_STATE NewState, bool UpdateBufferState) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (OldState == RESOURCE_STATE_UNKNOWN) { if (BufferVk.IsInKnownState()) @@ -2302,6 +2437,7 @@ void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl& { if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); if (Buffer.IsInKnownState()) { if (!Buffer.CheckState(RequiredState)) @@ -2330,6 +2466,8 @@ VulkanDynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(Uint32 SizeInB void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { + VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass"); + if (BarrierCount == 0) return; diff --git a/Graphics/GraphicsEngineVulkan/src/FramebufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/FramebufferVkImpl.cpp new file mode 100644 index 00000000..54b77e36 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/FramebufferVkImpl.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "pch.h" + +#include <vector> + +#include "FramebufferVkImpl.hpp" +#include "EngineMemory.h" +#include "RenderPassVkImpl.hpp" +#include "TextureViewVkImpl.hpp" + +namespace Diligent +{ + +FramebufferVkImpl::FramebufferVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDevice, + const FramebufferDesc& Desc) : + TFramebufferBase{pRefCounters, pDevice, Desc} +{ + VkFramebufferCreateInfo FramebufferCI = {}; + + FramebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + FramebufferCI.pNext = nullptr; + FramebufferCI.flags = 0; + + auto* pRenderPassVkImpl = ValidatedCast<RenderPassVkImpl>(m_Desc.pRenderPass); + FramebufferCI.renderPass = pRenderPassVkImpl->GetVkRenderPass(); + + FramebufferCI.attachmentCount = m_Desc.AttachmentCount; + + std::vector<VkImageView> vkImgViews(m_Desc.AttachmentCount); + for (Uint32 i = 0; i < m_Desc.AttachmentCount; ++i) + { + if (auto* pView = m_Desc.ppAttachments[i]) + { + vkImgViews[i] = ValidatedCast<TextureViewVkImpl>(pView)->GetVulkanImageView(); + } + } + FramebufferCI.pAttachments = vkImgViews.data(); + + FramebufferCI.width = m_Desc.Width; + FramebufferCI.height = m_Desc.Height; + FramebufferCI.layers = m_Desc.NumArraySlices; + + const auto& LogicalDevice = pDevice->GetLogicalDevice(); + + m_VkFramebuffer = LogicalDevice.CreateFramebuffer(FramebufferCI, m_Desc.Name); + if (!m_VkFramebuffer) + { + LOG_ERROR_AND_THROW("Failed to create Vulkan framebuffer"); + } +} + +FramebufferVkImpl::~FramebufferVkImpl() +{ + m_pDevice->SafeReleaseDeviceObject(std::move(m_VkFramebuffer), ~Uint64{0}); +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index 32a68780..aa027b25 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -64,7 +64,7 @@ class ResourceTypeToVkDescriptorType public: ResourceTypeToVkDescriptorType() { - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 10, "Please add corresponding decriptor type"); + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please add the corresponding decriptor type"); m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; m_Map[SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; m_Map[SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; @@ -75,6 +75,7 @@ public: m_Map[SPIRVShaderResourceAttribs::ResourceType::AtomicCounter] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateImage] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateSampler] = VK_DESCRIPTOR_TYPE_SAMPLER; + m_Map[SPIRVShaderResourceAttribs::ResourceType::InputAttachment] = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; } VkDescriptorType operator[](SPIRVShaderResourceAttribs::ResourceType ResType) const diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 99b27d2c..96592793 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -32,10 +32,12 @@ #include "VulkanTypeConversions.hpp" #include "RenderDeviceVkImpl.hpp" #include "DeviceContextVkImpl.hpp" +#include "RenderPassVkImpl.hpp" #include "ShaderResourceBindingVkImpl.hpp" #include "EngineMemory.h" #include "StringTools.hpp" + #if !DILIGENT_NO_HLSL # include "spirv-tools/optimizer.hpp" #endif @@ -43,97 +45,88 @@ namespace Diligent { -VkRenderPassCreateInfo PipelineStateVkImpl::GetRenderPassCreateInfo( - Uint32 NumRenderTargets, - const TEXTURE_FORMAT RTVFormats[], - TEXTURE_FORMAT DSVFormat, - Uint32 SampleCount, - std::array<VkAttachmentDescription, MAX_RENDER_TARGETS + 1>& Attachments, - std::array<VkAttachmentReference, MAX_RENDER_TARGETS + 1>& AttachmentReferences, - VkSubpassDescription& SubpassDesc) +RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( + Uint32 NumRenderTargets, + const TEXTURE_FORMAT RTVFormats[], + TEXTURE_FORMAT DSVFormat, + Uint8 SampleCount, + std::array<RenderPassAttachmentDesc, MAX_RENDER_TARGETS + 1>& Attachments, + std::array<AttachmentReference, MAX_RENDER_TARGETS + 1>& AttachmentReferences, + SubpassDesc& SubpassDesc) { VERIFY_EXPR(NumRenderTargets <= MAX_RENDER_TARGETS); - // Prepare render pass create info (7.1) - VkRenderPassCreateInfo RenderPassCI = {}; + RenderPassDesc RPDesc; - 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; + RPDesc.AttachmentCount = (DSVFormat != TEX_FORMAT_UNKNOWN ? 1 : 0) + NumRenderTargets; - uint32_t AttachmentInd = 0; - VkSampleCountFlagBits SampleCountFlags = static_cast<VkSampleCountFlagBits>(SampleCount); - VkAttachmentReference* pDepthAttachmentReference = nullptr; + uint32_t AttachmentInd = 0; + AttachmentReference* pDepthAttachmentReference = nullptr; if (DSVFormat != TEX_FORMAT_UNKNOWN) { auto& DepthAttachment = Attachments[AttachmentInd]; - 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 - // area are written to memory. For attachments with a depth/stencil format, - // 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->attachment = AttachmentInd; - pDepthAttachmentReference->layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + DepthAttachment.Format = DSVFormat; + DepthAttachment.SampleCount = SampleCount; + DepthAttachment.LoadOp = 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 = 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. + DepthAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_LOAD; + DepthAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_STORE; + DepthAttachment.InitialState = RESOURCE_STATE_DEPTH_WRITE; + DepthAttachment.FinalState = RESOURCE_STATE_DEPTH_WRITE; + + pDepthAttachmentReference = &AttachmentReferences[AttachmentInd]; + pDepthAttachmentReference->AttachmentIndex = AttachmentInd; + pDepthAttachmentReference->State = RESOURCE_STATE_DEPTH_WRITE; ++AttachmentInd; } - VkAttachmentReference* pColorAttachmentsReference = NumRenderTargets > 0 ? &AttachmentReferences[AttachmentInd] : nullptr; + AttachmentReference* pColorAttachmentsReference = NumRenderTargets > 0 ? &AttachmentReferences[AttachmentInd] : nullptr; for (Uint32 rt = 0; rt < NumRenderTargets; ++rt, ++AttachmentInd) { auto& ColorAttachment = Attachments[AttachmentInd]; - 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.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. - 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]; - ColorAttachmentRef.attachment = AttachmentInd; - ColorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + ColorAttachment.Format = RTVFormats[rt]; + ColorAttachment.SampleCount = SampleCount; + ColorAttachment.LoadOp = 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 = 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. + ColorAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_DISCARD; + ColorAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_DISCARD; + ColorAttachment.InitialState = RESOURCE_STATE_RENDER_TARGET; + ColorAttachment.FinalState = RESOURCE_STATE_RENDER_TARGET; + + auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd]; + ColorAttachmentRef.AttachmentIndex = AttachmentInd; + ColorAttachmentRef.State = RESOURCE_STATE_RENDER_TARGET; } - 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. - - - 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; - SubpassDesc.colorAttachmentCount = NumRenderTargets; - SubpassDesc.pColorAttachments = pColorAttachmentsReference; - SubpassDesc.pResolveAttachments = nullptr; - SubpassDesc.pDepthStencilAttachment = pDepthAttachmentReference; - SubpassDesc.preserveAttachmentCount = 0; - SubpassDesc.pPreserveAttachments = nullptr; - - return RenderPassCI; + RPDesc.pAttachments = Attachments.data(); + RPDesc.SubpassCount = 1; + RPDesc.pSubpasses = &SubpassDesc; + RPDesc.DependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies. + RPDesc.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing + // dependencies between pairs of subpasses, or NULL if dependencyCount is zero. + + + SubpassDesc.InputAttachmentCount = 0; + SubpassDesc.pInputAttachments = nullptr; + SubpassDesc.RenderTargetAttachmentCount = NumRenderTargets; + SubpassDesc.pRenderTargetAttachments = pColorAttachmentsReference; + SubpassDesc.pResolveAttachments = nullptr; + SubpassDesc.pDepthStencilAttachment = pDepthAttachmentReference; + SubpassDesc.PreserveAttachmentCount = 0; + SubpassDesc.pPreserveAttachments = nullptr; + + return RPDesc; } static std::vector<uint32_t> StripReflection(const std::vector<uint32_t>& OriginalSPIRV) @@ -295,14 +288,17 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun { const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - auto& RPCache = pDeviceVk->GetRenderPassCache(); + auto& RPCache = pDeviceVk->GetImplicitRenderPassCache(); - RenderPassCache::RenderPassCacheKey Key{ - GraphicsPipeline.NumRenderTargets, - GraphicsPipeline.SmplDesc.Count, - GraphicsPipeline.RTVFormats, - GraphicsPipeline.DSVFormat}; - m_RenderPass = RPCache.GetRenderPass(Key); + if (m_pRenderPass == nullptr) + { + RenderPassCache::RenderPassCacheKey Key{ + GraphicsPipeline.NumRenderTargets, + GraphicsPipeline.SmplDesc.Count, + GraphicsPipeline.RTVFormats, + GraphicsPipeline.DSVFormat}; + m_pRenderPass = RPCache.GetRenderPass(Key); + } VkGraphicsPipelineCreateInfo PipelineCI = {}; @@ -398,13 +394,16 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun DepthStencilStateDesc_To_VkDepthStencilStateCI(GraphicsPipeline.DepthStencilDesc); PipelineCI.pDepthStencilState = &DepthStencilStateCI; - std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(m_Desc.GraphicsPipeline.NumRenderTargets); + const auto& RPDesc = m_pRenderPass->GetDesc(); + const auto NumRTAttachments = RPDesc.pSubpasses[GraphicsPipeline.SubpassIndex].RenderTargetAttachmentCount; + VERIFY_EXPR(GraphicsPipeline.pRenderPass != nullptr || GraphicsPipeline.NumRenderTargets == NumRTAttachments); + std::vector<VkPipelineColorBlendAttachmentState> ColorBlendAttachmentStates(NumRTAttachments); VkPipelineColorBlendStateCreateInfo BlendStateCI = {}; 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. + BlendStateCI.attachmentCount = NumRTAttachments; // must equal the colorAttachmentCount for the subpass + // in which this pipeline is used. BlendStateDesc_To_VkBlendStateCI(GraphicsPipeline.BlendDesc, BlendStateCI, ColorBlendAttachmentStates); PipelineCI.pColorBlendState = &BlendStateCI; @@ -442,8 +441,8 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun PipelineCI.pDynamicState = &DynamicStateCI; - PipelineCI.renderPass = m_RenderPass; - PipelineCI.subpass = 0; + PipelineCI.renderPass = GetRenderPass()->GetVkRenderPass(); + PipelineCI.subpass = m_Desc.GraphicsPipeline.SubpassIndex; 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 diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 4e6049b0..18814e06 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -37,6 +37,8 @@ #include "DeviceContextVkImpl.hpp" #include "FenceVkImpl.hpp" #include "QueryVkImpl.hpp" +#include "RenderPassVkImpl.hpp" +#include "FramebufferVkImpl.hpp" #include "EngineMemory.h" namespace Diligent @@ -71,15 +73,17 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* sizeof(PipelineStateVkImpl), sizeof(ShaderResourceBindingVkImpl), sizeof(FenceVkImpl), - sizeof(QueryVkImpl) + sizeof(QueryVkImpl), + sizeof(RenderPassVkImpl), + sizeof(FramebufferVkImpl) } }, - m_VulkanInstance {Instance }, - m_PhysicalDevice {std::move(PhysicalDevice)}, - m_LogicalVkDevice {std::move(LogicalDevice) }, - m_EngineAttribs {EngineCI }, - m_FramebufferCache {*this }, - m_RenderPassCache {*this }, + m_VulkanInstance {Instance }, + m_PhysicalDevice {std::move(PhysicalDevice)}, + m_LogicalVkDevice {std::move(LogicalDevice) }, + m_EngineAttribs {EngineCI }, + m_FramebufferCache {*this }, + m_ImplicitRenderPassCache{*this }, m_DescriptorSetAllocator { *this, @@ -207,6 +211,9 @@ RenderDeviceVkImpl::~RenderDeviceVkImpl() // the heap into release queues m_DynamicMemoryManager.Destroy(); + // Explicitly destroy render pass cache + m_ImplicitRenderPassCache.Destroy(); + // Wait for the GPU to complete all its operations IdleGPU(); @@ -618,4 +625,35 @@ void RenderDeviceVkImpl::CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) ); } +void RenderDeviceVkImpl::CreateRenderPass(const RenderPassDesc& Desc, + IRenderPass** ppRenderPass, + bool IsDeviceInternal) +{ + CreateDeviceObject( + "RenderPass", Desc, ppRenderPass, + [&]() // + { + RenderPassVkImpl* pRenderPassVk(NEW_RC_OBJ(m_RenderPassAllocator, "RenderPassVkImpl instance", RenderPassVkImpl)(this, Desc, IsDeviceInternal)); + pRenderPassVk->QueryInterface(IID_RenderPass, reinterpret_cast<IObject**>(ppRenderPass)); + OnCreateDeviceObject(pRenderPassVk); + } // + ); +} + +void RenderDeviceVkImpl::CreateRenderPass(const RenderPassDesc& Desc, IRenderPass** ppRenderPass) +{ + CreateRenderPass(Desc, ppRenderPass, /*IsDeviceInternal = */ false); +} + +void RenderDeviceVkImpl::CreateFramebuffer(const FramebufferDesc& Desc, IFramebuffer** ppFramebuffer) +{ + CreateDeviceObject("Framebuffer", Desc, ppFramebuffer, + [&]() // + { + FramebufferVkImpl* pFramebufferVk(NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferVkImpl instance", FramebufferVkImpl)(this, Desc)); + pFramebufferVk->QueryInterface(IID_Framebuffer, reinterpret_cast<IObject**>(ppFramebuffer)); + OnCreateDeviceObject(pFramebufferVk); + }); +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp b/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp index c352c2a9..a40010f1 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderPassCache.cpp @@ -30,36 +30,52 @@ #include "RenderPassCache.hpp" #include "RenderDeviceVkImpl.hpp" #include "PipelineStateVkImpl.hpp" +#include "RenderPassVkImpl.hpp" namespace Diligent { +RenderPassCache::RenderPassCache(RenderDeviceVkImpl& DeviceVk) noexcept : + m_DeviceVkImpl{DeviceVk} +{} + + RenderPassCache::~RenderPassCache() { + // Render pass cache is part of the render device, so we can't release + // render pass objects from here as their destructors will attmept to + // call SafeReleaseDeviceObject. + VERIFY(m_Cache.empty(), "Render pass cache is not empty. Did you call Destroy?"); +} + +void RenderPassCache::Destroy() +{ auto& FBCache = m_DeviceVkImpl.GetFramebufferCache(); for (auto it = m_Cache.begin(); it != m_Cache.end(); ++it) { - FBCache.OnDestroyRenderPass(it->second); + FBCache.OnDestroyRenderPass(it->second->GetVkRenderPass()); } + m_Cache.clear(); } -VkRenderPass RenderPassCache::GetRenderPass(const RenderPassCacheKey& Key) + +RenderPassVkImpl* RenderPassCache::GetRenderPass(const RenderPassCacheKey& Key) { std::lock_guard<std::mutex> Lock{m_Mutex}; auto it = m_Cache.find(Key); if (it == m_Cache.end()) { // Do not zero-intitialize arrays - std::array<VkAttachmentDescription, MAX_RENDER_TARGETS + 1> Attachments; - std::array<VkAttachmentReference, MAX_RENDER_TARGETS + 1> AttachmentReferences; + std::array<RenderPassAttachmentDesc, MAX_RENDER_TARGETS + 1> Attachments; + std::array<AttachmentReference, MAX_RENDER_TARGETS + 1> AttachmentReferences; - VkSubpassDescription Subpass; + SubpassDesc Subpass; - auto RenderPassCI = - PipelineStateVkImpl::GetRenderPassCreateInfo(Key.NumRenderTargets, Key.RTVFormats, Key.DSVFormat, - Key.SampleCount, Attachments, AttachmentReferences, Subpass); + auto RPDesc = + PipelineStateVkImpl::GetImplicitRenderPassDesc(Key.NumRenderTargets, Key.RTVFormats, Key.DSVFormat, + Key.SampleCount, Attachments, AttachmentReferences, Subpass); std::stringstream PassNameSS; - PassNameSS << "Render pass: RT count: " << Uint32{Key.NumRenderTargets} << "; sample count: " << Uint32{Key.SampleCount} + PassNameSS << "Implicit render pass: RT count: " << Uint32{Key.NumRenderTargets} << "; sample count: " << Uint32{Key.SampleCount} << "; DSV Format: " << GetTextureFormatAttribs(Key.DSVFormat).Name; if (Key.NumRenderTargets > 0) { @@ -69,9 +85,11 @@ VkRenderPass RenderPassCache::GetRenderPass(const RenderPassCacheKey& Key) 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); - it = m_Cache.emplace(Key, std::move(RenderPass)).first; + + RefCntAutoPtr<RenderPassVkImpl> pRenderPass; + m_DeviceVkImpl.CreateRenderPass(RPDesc, pRenderPass.GetRawDblPtr<IRenderPass>(), /* IsDeviceInternal = */ true); + VERIFY_EXPR(pRenderPass != nullptr); + it = m_Cache.emplace(Key, std::move(pRenderPass)).first; } return it->second; diff --git a/Graphics/GraphicsEngineVulkan/src/RenderPassVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderPassVkImpl.cpp new file mode 100644 index 00000000..c010e460 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/RenderPassVkImpl.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 "pch.h" +#include <vector> + +#include "RenderPassVkImpl.hpp" +#include "VulkanTypeConversions.hpp" + +namespace Diligent +{ + +RenderPassVkImpl::RenderPassVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDevice, + const RenderPassDesc& Desc, + bool IsDeviceInternal) : + TRenderPassBase{pRefCounters, pDevice, Desc, IsDeviceInternal} +{ + VkRenderPassCreateInfo RenderPassCI = {}; + + RenderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + RenderPassCI.pNext = nullptr; + RenderPassCI.flags = 0; + + std::vector<VkAttachmentDescription> vkAttachments(m_Desc.AttachmentCount); + for (Uint32 i = 0; i < m_Desc.AttachmentCount; ++i) + { + const auto& Attachment = m_Desc.pAttachments[i]; + auto& vkAttachment = vkAttachments[i]; + vkAttachment.flags = 0; + vkAttachment.format = TexFormatToVkFormat(Attachment.Format); + vkAttachment.samples = static_cast<VkSampleCountFlagBits>(Attachment.SampleCount); + vkAttachment.loadOp = AttachmentLoadOpToVkAttachmentLoadOp(Attachment.LoadOp); + vkAttachment.storeOp = AttachmentStoreOpToVkAttachmentStoreOp(Attachment.StoreOp); + vkAttachment.stencilLoadOp = AttachmentLoadOpToVkAttachmentLoadOp(Attachment.StencilLoadOp); + vkAttachment.stencilStoreOp = AttachmentStoreOpToVkAttachmentStoreOp(Attachment.StencilStoreOp); + vkAttachment.initialLayout = ResourceStateToVkImageLayout(Attachment.InitialState, /*IsInsideRenderPass = */ false); + vkAttachment.finalLayout = ResourceStateToVkImageLayout(Attachment.FinalState, /*IsInsideRenderPass = */ true); + } + RenderPassCI.attachmentCount = Desc.AttachmentCount; + RenderPassCI.pAttachments = vkAttachments.data(); + + + Uint32 TotalAttachmentReferencesCount = 0; + Uint32 TotalPreserveAttachmentsCount = 0; + CountSubpassAttachmentReferences(Desc, TotalAttachmentReferencesCount, TotalPreserveAttachmentsCount); + std::vector<VkAttachmentReference> vkAttachmentReferences(TotalAttachmentReferencesCount); + std::vector<Uint32> vkPreserveAttachments(TotalPreserveAttachmentsCount); + + Uint32 CurrAttachmentReferenceInd = 0; + Uint32 CurrPreserveAttachmentInd = 0; + + std::vector<VkSubpassDescription> vkSubpasses(Desc.SubpassCount); + for (Uint32 i = 0; i < m_Desc.SubpassCount; ++i) + { + const auto& SubpassDesc = m_Desc.pSubpasses[i]; + auto& vkSubpass = vkSubpasses[i]; + vkSubpass.flags = 0; + vkSubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + vkSubpass.inputAttachmentCount = SubpassDesc.InputAttachmentCount; + + auto ConvertAttachmentReferences = [&](Uint32 NumAttachments, const AttachmentReference* pSrcAttachments) // + { + auto* pCurrVkAttachmentReference = &vkAttachmentReferences[CurrAttachmentReferenceInd]; + for (Uint32 attachment = 0; attachment < NumAttachments; ++attachment, ++CurrAttachmentReferenceInd) + { + const auto& AttachmnetRef = pSrcAttachments[attachment]; + + vkAttachmentReferences[CurrAttachmentReferenceInd].attachment = AttachmnetRef.AttachmentIndex; + vkAttachmentReferences[CurrAttachmentReferenceInd].layout = + ResourceStateToVkImageLayout(AttachmnetRef.State, /*IsInsideRenderPass = */ true); + } + + return pCurrVkAttachmentReference; + }; + + if (SubpassDesc.InputAttachmentCount != 0) + { + vkSubpass.pInputAttachments = ConvertAttachmentReferences(SubpassDesc.InputAttachmentCount, SubpassDesc.pInputAttachments); + } + + vkSubpass.colorAttachmentCount = SubpassDesc.RenderTargetAttachmentCount; + if (SubpassDesc.RenderTargetAttachmentCount != 0) + { + vkSubpass.pColorAttachments = ConvertAttachmentReferences(SubpassDesc.RenderTargetAttachmentCount, SubpassDesc.pRenderTargetAttachments); + if (SubpassDesc.pResolveAttachments != nullptr) + { + vkSubpass.pResolveAttachments = ConvertAttachmentReferences(SubpassDesc.RenderTargetAttachmentCount, SubpassDesc.pResolveAttachments); + } + } + + if (SubpassDesc.pDepthStencilAttachment != nullptr) + { + vkSubpass.pDepthStencilAttachment = ConvertAttachmentReferences(1, SubpassDesc.pDepthStencilAttachment); + } + + vkSubpass.preserveAttachmentCount = SubpassDesc.PreserveAttachmentCount; + if (SubpassDesc.PreserveAttachmentCount != 0) + { + vkSubpass.pPreserveAttachments = &vkPreserveAttachments[CurrPreserveAttachmentInd]; + for (Uint32 prsv_attachment = 0; prsv_attachment < SubpassDesc.PreserveAttachmentCount; ++prsv_attachment, ++CurrPreserveAttachmentInd) + { + vkPreserveAttachments[CurrPreserveAttachmentInd] = SubpassDesc.pPreserveAttachments[prsv_attachment]; + } + } + } + VERIFY_EXPR(CurrAttachmentReferenceInd == vkAttachmentReferences.size()); + VERIFY_EXPR(CurrPreserveAttachmentInd == vkPreserveAttachments.size()); + RenderPassCI.subpassCount = Desc.SubpassCount; + RenderPassCI.pSubpasses = vkSubpasses.data(); + + std::vector<VkSubpassDependency> vkDependencies(Desc.DependencyCount); + for (Uint32 i = 0; i < Desc.DependencyCount; ++i) + { + const auto& DependencyDesc = m_Desc.pDependencies[i]; + auto& vkDependency = vkDependencies[i]; + vkDependency.srcSubpass = DependencyDesc.SrcSubpass; + vkDependency.dstSubpass = DependencyDesc.DstSubpass; + vkDependency.srcStageMask = DependencyDesc.SrcStageMask; + vkDependency.dstStageMask = DependencyDesc.DstStageMask; + vkDependency.srcAccessMask = DependencyDesc.SrcAccessMask; + vkDependency.dstAccessMask = DependencyDesc.DstAccessMask; + vkDependency.dependencyFlags = 0; + } + RenderPassCI.dependencyCount = Desc.DependencyCount; + RenderPassCI.pDependencies = vkDependencies.data(); + + const auto& LogicalDevice = pDevice->GetLogicalDevice(); + + m_VkRenderPass = LogicalDevice.CreateRenderPass(RenderPassCI, Desc.Name); + if (!m_VkRenderPass) + { + LOG_ERROR_AND_THROW("Failed to create Vulkan render pass"); + } +} + +RenderPassVkImpl::~RenderPassVkImpl() +{ + m_pDevice->SafeReleaseDeviceObject(std::move(m_VkRenderPass), ~Uint64{0}); +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index 06239703..caf8ffd2 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -155,6 +155,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) for (Uint32 res = 0; res < m_TotalResources; ++res) { auto& Res = pResources[res]; + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below"); switch (Res.Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: @@ -312,6 +313,14 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } break; + case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: + { + // Nothing to do with input attachments - they are transitioned by the render pass. + // There is nothing we can validate here - a texture may be in different state at + // the beginning of the render pass before being transitioned to INPUT_ATTACHMENT state. + } + break; + default: UNEXPECTED("Unexpected resource type"); } } @@ -472,4 +481,20 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWrite return DescrImgInfo; } +VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescriptorWriteInfo() const +{ + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected"); + DEV_CHECK_ERR(pObject != nullptr, "Unable to get input attachment write info: cached object is null"); + + auto* pTexViewVk = pObject.RawPtr<const TextureViewVkImpl>(); + VERIFY_EXPR(pTexViewVk->GetDesc().ViewType == TEXTURE_VIEW_SHADER_RESOURCE); + + VkDescriptorImageInfo DescrImgInfo; + DescrImgInfo.sampler = VK_NULL_HANDLE; + DescrImgInfo.imageView = pTexViewVk->GetVulkanImageView(); + DescrImgInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + return DescrImgInfo; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index a02cd8bb..4f28af80 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -526,6 +526,11 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* { VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); AddResource(s, Layout, Resources, SepImg); + }, + [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32) + { + VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment); + AddResource(s, Layout, Resources, InputAtt); } ); // clang-format on @@ -640,7 +645,7 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* Uint16& DynamicBuffersCounter) const { VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected"); - RefCntAutoPtr<BufferVkImpl> pBufferVk(pBuffer, IID_BufferVk); + RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk}; #ifdef DILIGENT_DEVELOPMENT VerifyConstantBufferBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); #endif @@ -681,7 +686,7 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* "Storage buffer resource is expected"); // clang-format on - RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk(pBufferView, IID_BufferViewVk); + RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk}; #ifdef DILIGENT_DEVELOPMENT { // HLSL buffer SRVs are mapped to storge buffers in GLSL @@ -727,7 +732,7 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* "Uniform or storage buffer resource is expected"); // clang-format on - RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk(pBufferView, IID_BufferViewVk); + RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk}; #ifdef DILIGENT_DEVELOPMENT { // HLSL buffer SRVs are mapped to storge buffers in GLSL @@ -776,7 +781,7 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* "Storage image, separate image or sampled image resource is expected"); // clang-format on - RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0(pTexView, IID_TextureViewVk); + RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk}; #ifdef DILIGENT_DEVELOPMENT { // HLSL buffer SRVs are mapped to storge buffers in GLSL @@ -840,7 +845,7 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected"); VERIFY(!IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler"); - RefCntAutoPtr<SamplerVkImpl> pSamplerVk(pSampler, IID_Sampler); + RefCntAutoPtr<SamplerVkImpl> pSamplerVk{pSampler, IID_Sampler}; #ifdef DILIGENT_DEVELOPMENT if (pSampler != nullptr && pSamplerVk == nullptr) { @@ -868,6 +873,28 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* } } +void ShaderResourceLayoutVk::VkResource::CacheInputAttachment(IDeviceObject* pTexView, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd) const +{ + VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected"); + RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk}; +#ifdef DILIGENT_DEVELOPMENT + VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); +#endif + if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {})) + { + // 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) + { + VkDescriptorImageInfo DescrImgInfo = DstRes.GetInputAttachmentDescriptorWriteInfo(); + UpdateDescriptorHandle(vkDescrSet, ArrayInd, &DescrImgInfo, nullptr, nullptr); + } + // + } +} void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const { @@ -898,6 +925,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 if (pObj) { + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below"); switch (SpirvAttribs.Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: @@ -945,6 +973,10 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 } break; + case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: + CacheInputAttachment(pObj, DstRes, vkDescrSet, ArrayIndex); + break; + default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(SpirvAttribs.Type)); } } diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 2a634162..ca04f900 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -139,6 +139,10 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, { ImageCI.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; } + if (m_Desc.BindFlags & BIND_INPUT_ATTACHMENT) + { + ImageCI.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } if (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) { diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp index d5e4f48b..25966163 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp @@ -1140,7 +1140,6 @@ VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[]) static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) { // Currently not used: - //VK_ACCESS_INPUT_ATTACHMENT_READ_BIT //VK_ACCESS_HOST_READ_BIT //VK_ACCESS_HOST_WRITE_BIT //VK_ACCESS_MEMORY_READ_BIT @@ -1155,7 +1154,7 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) //VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX //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"); + static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag"); VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set"); switch (StateFlag) { @@ -1175,6 +1174,7 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag) case RESOURCE_STATE_COPY_SOURCE: return VK_ACCESS_TRANSFER_READ_BIT; 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_INPUT_ATTACHMENT: return VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; case RESOURCE_STATE_PRESENT: return VK_ACCESS_MEMORY_READ_BIT; // clang-format on @@ -1203,7 +1203,7 @@ public: } private: - static constexpr const Uint32 MaxFlagBitPos = 15; + static constexpr const Uint32 MaxFlagBitPos = 16; std::array<VkAccessFlags, MaxFlagBitPos + 1> FlagBitPosToVkAccessFlagsMap; }; @@ -1235,7 +1235,7 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit) case VK_ACCESS_INDEX_READ_BIT: return RESOURCE_STATE_INDEX_BUFFER; case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: return RESOURCE_STATE_VERTEX_BUFFER; case VK_ACCESS_UNIFORM_READ_BIT: return RESOURCE_STATE_CONSTANT_BUFFER; - case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: return RESOURCE_STATE_UNKNOWN; + case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: return RESOURCE_STATE_INPUT_ATTACHMENT; case VK_ACCESS_SHADER_READ_BIT: return RESOURCE_STATE_SHADER_RESOURCE; case VK_ACCESS_SHADER_WRITE_BIT: return RESOURCE_STATE_UNORDERED_ACCESS; case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: return RESOURCE_STATE_RENDER_TARGET; @@ -1304,7 +1304,7 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags) -VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) +VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsideRenderPass) { if (StateFlag == RESOURCE_STATE_UNKNOWN) { @@ -1317,7 +1317,7 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) //VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, //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"); + static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag"); VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set"); switch (StateFlag) { @@ -1335,8 +1335,9 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag) case RESOURCE_STATE_INDIRECT_ARGUMENT: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED; case RESOURCE_STATE_COPY_DEST: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; case RESOURCE_STATE_COPY_SOURCE: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - case RESOURCE_STATE_RESOLVE_DEST: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + case RESOURCE_STATE_RESOLVE_DEST: return IsInsideRenderPass ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; case RESOURCE_STATE_RESOLVE_SOURCE: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; case RESOURCE_STATE_PRESENT: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // clang-format on @@ -1348,7 +1349,7 @@ 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"); + static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag"); switch (Layout) { // clang-format off @@ -1421,4 +1422,93 @@ VkSurfaceTransformFlagBitsKHR SurfaceTransformToVkSurfaceTransformFlag(SURFACE_T // clang-format on } + +#define ASSERT_SAME(Val1, Val2) static_assert(static_cast<int>(Val1) == static_cast<int>(Val2), #Val1 " is expected to be equal to " #Val2) + +ASSERT_SAME(ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); +ASSERT_SAME(ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); +ASSERT_SAME(ATTACHMENT_LOAD_OP_DISCARD, VK_ATTACHMENT_LOAD_OP_DONT_CARE); +VkAttachmentLoadOp AttachmentLoadOpToVkAttachmentLoadOp(ATTACHMENT_LOAD_OP LoadOp) +{ + return static_cast<VkAttachmentLoadOp>(LoadOp); +} +ATTACHMENT_LOAD_OP VkAttachmentLoadOpToAttachmentLoadOp(VkAttachmentLoadOp VkLoadOp) +{ + return static_cast<ATTACHMENT_LOAD_OP>(VkLoadOp); +} + + +ASSERT_SAME(ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_STORE_OP_STORE); +ASSERT_SAME(ATTACHMENT_STORE_OP_DISCARD, VK_ATTACHMENT_STORE_OP_DONT_CARE); +VkAttachmentStoreOp AttachmentStoreOpToVkAttachmentStoreOp(ATTACHMENT_STORE_OP StoreOp) +{ + return static_cast<VkAttachmentStoreOp>(StoreOp); +} +ATTACHMENT_STORE_OP VkAttachmentStoreOpToAttachmentStoreOp(VkAttachmentStoreOp VkStoreOp) +{ + return static_cast<ATTACHMENT_STORE_OP>(VkStoreOp); +} + + +// clang-format off +ASSERT_SAME(PIPELINE_STAGE_FLAG_TOP_OF_PIPE, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_DRAW_INDIRECT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_VERTEX_INPUT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_VERTEX_SHADER, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_HULL_SHADER, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_DOMAIN_SHADER, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_GEOMETRY_SHADER, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_PIXEL_SHADER, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_EARLY_FRAGMENT_TESTS, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_LATE_FRAGMENT_TESTS, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_RENDER_TARGET, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_COMPUTE_SHADER, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_TRANSFER, VK_PIPELINE_STAGE_TRANSFER_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_BOTTOM_OF_PIPE, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_HOST, VK_PIPELINE_STAGE_HOST_BIT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_CONDITIONAL_RENDERING, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT); +ASSERT_SAME(PIPELINE_STAGE_FLAG_SHADING_RATE_TEXTURE, VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV); +ASSERT_SAME(PIPELINE_STAGE_FLAG_RAY_TRACING_SHADER, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV); +ASSERT_SAME(PIPELINE_STAGE_FLAG_ACCELERATION_STRUCTURE_BUILD, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV); +ASSERT_SAME(PIPELINE_STAGE_FLAG_TASK_SHADER, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV); +ASSERT_SAME(PIPELINE_STAGE_FLAG_MESH_SHADER, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV); +ASSERT_SAME(PIPELINE_STAGE_FLAG_FRAGMENT_DENSITY_PROCESS, VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT); +// clang-format on +VkPipelineStageFlags PipelineStageFlagsToVkPipelineStageFlags(PIPELINE_STAGE_FLAGS PipelineStageFlags) +{ + return static_cast<VkPipelineStageFlags>(PipelineStageFlags); +} + + +// clang-format off +static_assert(ACCESS_FLAG_NONE == 0, ""); +ASSERT_SAME(ACCESS_FLAG_INDIRECT_COMMAND_READ, VK_ACCESS_INDIRECT_COMMAND_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_INDEX_READ, VK_ACCESS_INDEX_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_VERTEX_READ, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_UNIFORM_READ, VK_ACCESS_UNIFORM_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_INPUT_ATTACHMENT_READ, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_SHADER_READ, VK_ACCESS_SHADER_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_SHADER_WRITE, VK_ACCESS_SHADER_WRITE_BIT); +ASSERT_SAME(ACCESS_FLAG_RENDER_TARGET_READ, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_RENDER_TARGET_WRITE, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); +ASSERT_SAME(ACCESS_FLAG_DEPTH_STENCIL_READ, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_DEPTH_STENCIL_WRITE, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); +ASSERT_SAME(ACCESS_FLAG_COPY_SRC, VK_ACCESS_TRANSFER_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_COPY_DST, VK_ACCESS_TRANSFER_WRITE_BIT); +ASSERT_SAME(ACCESS_FLAG_HOST_READ, VK_ACCESS_HOST_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_HOST_WRITE, VK_ACCESS_HOST_WRITE_BIT); +ASSERT_SAME(ACCESS_FLAG_MEMORY_READ, VK_ACCESS_MEMORY_READ_BIT); +ASSERT_SAME(ACCESS_FLAG_MEMORY_WRITE, VK_ACCESS_MEMORY_WRITE_BIT); +ASSERT_SAME(ACCESS_FLAG_CONDITIONAL_RENDERING_READ, VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT); +ASSERT_SAME(ACCESS_FLAG_SHADING_RATE_TEXTURE_READ, VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV); +ASSERT_SAME(ACCESS_FLAG_ACCELERATION_STRUCTURE_READ, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV); +ASSERT_SAME(ACCESS_FLAG_ACCELERATION_STRUCTURE_WRITE, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV); +ASSERT_SAME(ACCESS_FLAG_FRAGMENT_DENSITY_MAP_READ, VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT); +// clang-format on +VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags) +{ + return static_cast<VkAccessFlags>(AccessFlags); +} +#undef ASSERT_SAME + } // namespace Diligent |
