diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-08-04 21:05:42 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-08-04 21:05:42 +0000 |
| commit | 86bd2d7175d3e2d0f5c1c313a802a22c9f95b4ea (patch) | |
| tree | e4d8d6f4f90a4805d6d230d6fd7f49390be4cdab | |
| parent | Added render pass MS resolve test (diff) | |
| download | DiligentCore-86bd2d7175d3e2d0f5c1c313a802a22c9f95b4ea.tar.gz DiligentCore-86bd2d7175d3e2d0f5c1c313a802a22c9f95b4ea.zip | |
Implemented input attachments in Vulkan backend; added test
16 files changed, 667 insertions, 38 deletions
diff --git a/Graphics/GLSLTools/include/SPIRVShaderResources.hpp b/Graphics/GLSLTools/include/SPIRVShaderResources.hpp index 96e778a0..7a1b93ce 100644 --- a/Graphics/GLSLTools/include/SPIRVShaderResources.hpp +++ b/Graphics/GLSLTools/include/SPIRVShaderResources.hpp @@ -70,6 +70,7 @@ struct SPIRVShaderResourceAttribs AtomicCounter, SeparateImage, SeparateSampler, + InputAttachment, NumResourceTypes }; @@ -205,7 +206,8 @@ public: Uint32 GetNumSmpldImgs()const noexcept{ return (m_AtomicCounterOffset - m_SampledImageOffset); } Uint32 GetNumACs ()const noexcept{ return (m_SeparateSamplerOffset - m_AtomicCounterOffset); } Uint32 GetNumSepSmplrs()const noexcept{ return (m_SeparateImageOffset - m_SeparateSamplerOffset);} - Uint32 GetNumSepImgs ()const noexcept{ return (m_TotalResources - m_SeparateImageOffset); } + Uint32 GetNumSepImgs ()const noexcept{ return (m_InputAttachmentOffset - m_SeparateImageOffset); } + Uint32 GetNumInptAtts ()const noexcept{ return (m_TotalResources - m_InputAttachmentOffset);} Uint32 GetTotalResources() const noexcept { return m_TotalResources; } Uint32 GetNumShaderStageInputs()const noexcept { return m_NumShaderStageInputs; } @@ -216,6 +218,7 @@ public: const SPIRVShaderResourceAttribs& GetAC (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } const SPIRVShaderResourceAttribs& GetSepSmplr(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset); } const SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } + const SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset); } const SPIRVShaderResourceAttribs& GetResource(Uint32 n)const noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } // clang-format on @@ -243,6 +246,7 @@ public: Uint32 NumACs = 0; Uint32 NumSepSmplrs = 0; Uint32 NumSepImgs = 0; + Uint32 NumInptAtts = 0; }; SHADER_TYPE GetShaderType() const noexcept { return m_ShaderType; } @@ -254,14 +258,16 @@ public: typename THandleSmplImg, typename THandleAC, typename THandleSepSmpl, - typename THandleSepImg> + typename THandleSepImg, + typename THandleInptAtt> void ProcessResources(THandleUB HandleUB, THandleSB HandleSB, THandleImg HandleImg, THandleSmplImg HandleSmplImg, THandleAC HandleAC, THandleSepSmpl HandleSepSmpl, - THandleSepImg HandleSepImg) const + THandleSepImg HandleSepImg, + THandleInptAtt HandleInptAtt) const { for (Uint32 n = 0; n < GetNumUBs(); ++n) { @@ -304,6 +310,14 @@ public: const auto& SepImg = GetSepImg(n); HandleSepImg(SepImg, n); } + + for (Uint32 n = 0; n < GetNumInptAtts(); ++n) + { + const auto& InptAtt = GetInptAtt(n); + HandleInptAtt(InptAtt, n); + } + + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type here, if needed"); } template <typename THandler> @@ -359,6 +373,7 @@ private: SPIRVShaderResourceAttribs& GetAC (Uint32 n)noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } SPIRVShaderResourceAttribs& GetSepSmplr(Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset); } SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } + SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset); } SPIRVShaderResourceAttribs& GetResource(Uint32 n)noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } // clang-format on @@ -384,6 +399,7 @@ private: OffsetType m_AtomicCounterOffset = 0; OffsetType m_SeparateSamplerOffset = 0; OffsetType m_SeparateImageOffset = 0; + OffsetType m_InputAttachmentOffset = 0; OffsetType m_TotalResources = 0; OffsetType m_NumShaderStageInputs = 0; diff --git a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp index 46705ace..0dd3e4ae 100644 --- a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp +++ b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp @@ -91,7 +91,7 @@ ShaderResourceDesc SPIRVShaderResourceAttribs::GetResourceDesc() const ResourceDesc.Name = Name; ResourceDesc.ArraySize = ArraySize; - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 10, "Please update switch statement below"); + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below"); switch (Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: @@ -137,6 +137,10 @@ ShaderResourceDesc SPIRVShaderResourceAttribs::GetResourceDesc() const ResourceDesc.Type = SHADER_RESOURCE_TYPE_SAMPLER; break; + case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT; + break; + default: UNEXPECTED("Unknown SPIRV resource type"); } @@ -245,6 +249,7 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, size_t ResourceNamesPoolSize = 0; for (const auto& ub : resources.uniform_buffers) ResourceNamesPoolSize += GetUBName(Compiler, ub, ParsedIRSource).length() + 1; + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please account for the new resource type below"); for (auto* pResType : { &resources.storage_buffers, @@ -252,10 +257,11 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, &resources.sampled_images, &resources.atomic_counters, &resources.separate_images, - &resources.separate_samplers - //clang-format off + &resources.separate_samplers, + &resources.subpass_inputs + // clang-format off }) - //clang-format on + // clang-format on { for (const auto& res : *pResType) ResourceNamesPoolSize += res.name.length() + 1; @@ -322,6 +328,8 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, ResCounters.NumACs = static_cast<Uint32>(resources.atomic_counters.size()); ResCounters.NumSepSmplrs = static_cast<Uint32>(resources.separate_samplers.size()); ResCounters.NumSepImgs = static_cast<Uint32>(resources.separate_images.size()); + ResCounters.NumInptAtts = static_cast<Uint32>(resources.subpass_inputs.size()); + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please set the new resource type counter here"); Initialize(Allocator, ResCounters, NumShaderStageInputs, ResourceNamesPoolSize); { @@ -469,6 +477,21 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, VERIFY_EXPR(CurrSepImg == GetNumSepImgs()); } + { + Uint32 CurrSubpassInput = 0; + for (const auto& SubpassInput : resources.subpass_inputs) + { + new (&GetInptAtt(CurrSubpassInput++)) + SPIRVShaderResourceAttribs(Compiler, + SubpassInput, + m_ResourceNames.CopyString(SubpassInput.name), + SPIRVShaderResourceAttribs::ResourceType::InputAttachment); + } + VERIFY_EXPR(CurrSubpassInput == GetNumInptAtts()); + } + + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please initialize SPIRVShaderResourceAttribs for the new resource type here"); + if (CombinedSamplerSuffix != nullptr) { m_CombinedSamplerSuffix = m_ResourceNames.CopyString(CombinedSamplerSuffix); @@ -531,7 +554,9 @@ void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, m_AtomicCounterOffset = AdvanceOffset(Counters.NumACs); m_SeparateSamplerOffset = AdvanceOffset(Counters.NumSepSmplrs); m_SeparateImageOffset = AdvanceOffset(Counters.NumSepImgs); + m_InputAttachmentOffset = AdvanceOffset(Counters.NumInptAtts); m_TotalResources = AdvanceOffset(0); + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please update the new resource type offset"); VERIFY(NumShaderStageInputs <= MaxOffset, "Max offset exceeded"); m_NumShaderStageInputs = static_cast<OffsetType>(NumShaderStageInputs); @@ -692,6 +717,13 @@ std::string SPIRVShaderResources::DumpResources() ss << std::endl << std::setw(3) << ResNum << " Separate Img "; DumpResource(SepImg); + }, + [&](const SPIRVShaderResourceAttribs& InptAtt, Uint32) // + { + VERIFY(InptAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Unexpected resource type"); + ss << std::endl + << std::setw(3) << ResNum << " Input Attachment "; + DumpResource(InptAtt); } // ); VERIFY_EXPR(ResNum == GetTotalResources()); diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index 0a4afd54..5cefca34 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -1019,6 +1019,7 @@ String GetBufferDescString(const BufferDesc& Desc) const Char* GetResourceStateFlagString(RESOURCE_STATE State) { VERIFY((State & (State - 1)) == 0, "Single state is expected"); + static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "Please update this function to handle the new resource state"); switch (State) { // clang-format off @@ -1038,6 +1039,7 @@ const Char* GetResourceStateFlagString(RESOURCE_STATE State) case RESOURCE_STATE_COPY_SOURCE: return "COPY_SOURCE"; case RESOURCE_STATE_RESOLVE_DEST: return "RESOLVE_DEST"; case RESOURCE_STATE_RESOLVE_SOURCE: return "RESOLVE_SOURCE"; + case RESOURCE_STATE_INPUT_ATTACHMENT: return "INPUT_ATTACHMENT"; case RESOURCE_STATE_PRESENT: return "PRESENT"; // clang-format on default: diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp index 38414be2..fd0256b6 100644 --- a/Graphics/GraphicsEngine/include/TextureBase.hpp +++ b/Graphics/GraphicsEngine/include/TextureBase.hpp @@ -123,6 +123,9 @@ public: ") correspond to one of ", pDevice->GetCommandQueueCount(), " available device command queues"); this->m_Desc.CommandQueueMask &= DeviceQueuesMask; + if ((this->m_Desc.BindFlags & BIND_INPUT_ATTACHMENT) != 0) + this->m_Desc.BindFlags |= BIND_SHADER_RESOURCE; + // Validate correctness of texture description ValidateTextureDesc(this->m_Desc); } diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 3c0ca99a..727888d9 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -1644,6 +1644,7 @@ struct VulkanDescriptorPoolSize Uint32 NumStorageBufferDescriptors DEFAULT_INITIALIZER(0); Uint32 NumUniformTexelBufferDescriptors DEFAULT_INITIALIZER(0); Uint32 NumStorageTexelBufferDescriptors DEFAULT_INITIALIZER(0); + Uint32 NumInputAttachmentDescriptors DEFAULT_INITIALIZER(0); #if DILIGENT_CPP_INTERFACE VulkanDescriptorPoolSize()noexcept {} @@ -1656,7 +1657,8 @@ struct VulkanDescriptorPoolSize Uint32 _NumUniformBufferDescriptors, Uint32 _NumStorageBufferDescriptors, Uint32 _NumUniformTexelBufferDescriptors, - Uint32 _NumStorageTexelBufferDescriptors)noexcept : + Uint32 _NumStorageTexelBufferDescriptors, + Uint32 _NumInputAttachmentDescriptors)noexcept : MaxDescriptorSets {_MaxDescriptorSets }, NumSeparateSamplerDescriptors {_NumSeparateSamplerDescriptors }, NumCombinedSamplerDescriptors {_NumCombinedSamplerDescriptors }, @@ -1665,7 +1667,8 @@ struct VulkanDescriptorPoolSize NumUniformBufferDescriptors {_NumUniformBufferDescriptors }, NumStorageBufferDescriptors {_NumStorageBufferDescriptors }, NumUniformTexelBufferDescriptors{_NumUniformTexelBufferDescriptors}, - NumStorageTexelBufferDescriptors{_NumStorageTexelBufferDescriptors} + NumStorageTexelBufferDescriptors{_NumStorageTexelBufferDescriptors}, + NumInputAttachmentDescriptors {_NumInputAttachmentDescriptors } { // On clang aggregate initialization fails to compile if // structure members have default initializers @@ -1700,8 +1703,8 @@ struct EngineVkCreateInfo DILIGENT_DERIVE(EngineCreateInfo) /// the engine creates another one. VulkanDescriptorPoolSize MainDescriptorPoolSize #if DILIGENT_CPP_INTERFACE - //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB - {8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024} + //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt + {8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024, 256} #endif ; @@ -1712,8 +1715,8 @@ struct EngineVkCreateInfo DILIGENT_DERIVE(EngineCreateInfo) VulkanDescriptorPoolSize DynamicDescriptorPoolSize #if DILIGENT_CPP_INTERFACE - //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB - {2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256} + //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt + {2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256, 64} #endif ; diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h index eacd35f0..f3df92d3 100644 --- a/Graphics/GraphicsEngine/interface/Shader.h +++ b/Graphics/GraphicsEngine/interface/Shader.h @@ -283,8 +283,10 @@ struct ShaderCreateInfo }; typedef struct ShaderCreateInfo ShaderCreateInfo; +// clang-format off /// Describes shader resource type -DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8){ +DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8) +{ /// Shader resource type is unknown SHADER_RESOURCE_TYPE_UNKNOWN = 0, @@ -304,7 +306,12 @@ DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8){ SHADER_RESOURCE_TYPE_BUFFER_UAV, /// Sampler (separate sampler) - SHADER_RESOURCE_TYPE_SAMPLER}; + SHADER_RESOURCE_TYPE_SAMPLER, + + /// Input attachment in a render pass + SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT +}; +// clang-format on /// Shader resource description struct ShaderResourceDesc diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp index a0548e4d..b6b38dd0 100644 --- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp +++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp @@ -89,7 +89,8 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.InitialState != RESOURCE_STATE_COPY_DEST && - Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE) + Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE && + Attachment.InitialState != RESOURCE_STATE_INPUT_ATTACHMENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); } @@ -101,7 +102,8 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.FinalState != RESOURCE_STATE_COPY_DEST && - Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE) + Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE && + Attachment.FinalState != RESOURCE_STATE_INPUT_ATTACHMENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the final state of depth-stencil attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); } @@ -114,6 +116,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.InitialState != RESOURCE_STATE_RESOLVE_DEST && Attachment.InitialState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.InitialState != RESOURCE_STATE_COPY_SOURCE && + Attachment.InitialState != RESOURCE_STATE_INPUT_ATTACHMENT && Attachment.InitialState != RESOURCE_STATE_PRESENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the initial state of color attachment ", i, " (", GetResourceStateString(Attachment.InitialState), ") is invalid."); @@ -125,6 +128,7 @@ void ValidateRenderPassDesc(const RenderPassDesc& Desc) Attachment.FinalState != RESOURCE_STATE_RESOLVE_DEST && Attachment.FinalState != RESOURCE_STATE_RESOLVE_SOURCE && Attachment.FinalState != RESOURCE_STATE_COPY_SOURCE && + Attachment.FinalState != RESOURCE_STATE_INPUT_ATTACHMENT && Attachment.FinalState != RESOURCE_STATE_PRESENT) { LOG_RENDER_PASS_ERROR_AND_THROW("the final state of color attachment ", i, " (", GetResourceStateString(Attachment.FinalState), ") is invalid."); 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/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/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/Tests/DiligentCoreAPITest/include/InlineShaders/DrawCommandTestGLSL.h b/Tests/DiligentCoreAPITest/include/InlineShaders/DrawCommandTestGLSL.h index 83e63258..4c74e32c 100644 --- a/Tests/DiligentCoreAPITest/include/InlineShaders/DrawCommandTestGLSL.h +++ b/Tests/DiligentCoreAPITest/include/InlineShaders/DrawCommandTestGLSL.h @@ -93,6 +93,23 @@ void main() )" }; +const std::string InputAttachmentTest_FS{ +R"( +#version 420 core + +layout(input_attachment_index = 0, binding = 0) uniform subpassInput in_Color; +layout(location = 0) in vec3 in_VSOutColor; +layout(location = 0) out vec4 out_Color; + +void main() +{ + out_Color.rgb = in_VSOutColor.rgb * 0.125; + out_Color.rgb += (vec3(1.0, 1.0, 1.0) - subpassLoad(in_Color).brg) * 0.875; + out_Color.a = 1.0; +} +)" +}; + // clang-format on } // namespace GLSL diff --git a/Tests/DiligentCoreAPITest/src/RenderPassTest.cpp b/Tests/DiligentCoreAPITest/src/RenderPassTest.cpp index 0f0e9567..3f0dc23c 100644 --- a/Tests/DiligentCoreAPITest/src/RenderPassTest.cpp +++ b/Tests/DiligentCoreAPITest/src/RenderPassTest.cpp @@ -32,6 +32,8 @@ #include "gtest/gtest.h" +#include "InlineShaders/DrawCommandTestGLSL.h" + namespace Diligent { @@ -634,8 +636,242 @@ TEST_F(RenderPassTest, MSResolve) Present(); } -TEST_F(RenderPassTest, InputAttachments) +TEST_F(RenderPassTest, InputAttachment) { + auto* pEnv = TestingEnvironment::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + auto* pSwapChain = pEnv->GetSwapChain(); + auto* pContext = pEnv->GetDeviceContext(); + + constexpr float ClearColor[] = {0.5f, 0.125f, 0.25f, 0.25f}; + + RefCntAutoPtr<ITestingSwapChain> pTestingSwapChain(pSwapChain, IID_TestingSwapChain); + if (pTestingSwapChain) + { + pContext->Flush(); + pContext->InvalidateState(); + + auto deviceType = pDevice->GetDeviceCaps().DevType; + switch (deviceType) + { +#if D3D11_SUPPORTED + case RENDER_DEVICE_TYPE_D3D11: + RenderDrawCommandReferenceD3D11(pSwapChain); + break; +#endif + +#if D3D12_SUPPORTED + case RENDER_DEVICE_TYPE_D3D12: + RenderDrawCommandReferenceD3D12(pSwapChain); + break; +#endif + +#if GL_SUPPORTED || GLES_SUPPORTED + case RENDER_DEVICE_TYPE_GL: + case RENDER_DEVICE_TYPE_GLES: + RenderDrawCommandReferenceGL(pSwapChain); + break; + +#endif + +#if VULKAN_SUPPORTED + case RENDER_DEVICE_TYPE_VULKAN: + RenderPassInputAttachmentReferenceVk(pSwapChain, ClearColor); + break; +#endif + + default: + LOG_ERROR_AND_THROW("Unsupported device type"); + } + + pTestingSwapChain->TakeSnapshot(); + } + TestingEnvironment::ScopedReleaseResources EnvironmentAutoReset; + + const auto& SCDesc = pSwapChain->GetDesc(); + + RenderPassAttachmentDesc Attachments[2]; + Attachments[0].Format = SCDesc.ColorBufferFormat; + Attachments[0].SampleCount = 1; + Attachments[0].InitialState = RESOURCE_STATE_RENDER_TARGET; + Attachments[0].FinalState = RESOURCE_STATE_INPUT_ATTACHMENT; + Attachments[0].LoadOp = ATTACHMENT_LOAD_OP_CLEAR; + Attachments[0].StoreOp = ATTACHMENT_STORE_OP_DISCARD; + + Attachments[1].Format = SCDesc.ColorBufferFormat; + Attachments[1].SampleCount = 1; + Attachments[1].InitialState = RESOURCE_STATE_RENDER_TARGET; + Attachments[1].FinalState = RESOURCE_STATE_RENDER_TARGET; + Attachments[1].LoadOp = ATTACHMENT_LOAD_OP_CLEAR; + Attachments[1].StoreOp = ATTACHMENT_STORE_OP_STORE; + + RefCntAutoPtr<ITexture> pTex; + { + TextureDesc TexDesc; + TexDesc.Type = RESOURCE_DIM_TEX_2D; + TexDesc.Format = SCDesc.ColorBufferFormat; + TexDesc.Width = SCDesc.Width; + TexDesc.Height = SCDesc.Height; + TexDesc.BindFlags = BIND_RENDER_TARGET | BIND_INPUT_ATTACHMENT; + TexDesc.MipLevels = 1; + TexDesc.Usage = USAGE_DEFAULT; + + pDevice->CreateTexture(TexDesc, nullptr, &pTex); + ASSERT_NE(pTex, nullptr); + } + + SubpassDesc Subpasses[2]; + + // clang-format off + AttachmentReference RTAttachmentRefs0[] = + { + {0, RESOURCE_STATE_RENDER_TARGET} + }; + AttachmentReference RTAttachmentRefs1[] = + { + {1, RESOURCE_STATE_RENDER_TARGET} + }; + AttachmentReference InputAttachmentRefs1[] = + { + {0, RESOURCE_STATE_INPUT_ATTACHMENT} + }; + // clang-format on + Subpasses[0].RenderTargetAttachmentCount = _countof(RTAttachmentRefs0); + Subpasses[0].pRenderTargetAttachments = RTAttachmentRefs0; + + Subpasses[1].RenderTargetAttachmentCount = _countof(RTAttachmentRefs1); + Subpasses[1].pRenderTargetAttachments = RTAttachmentRefs1; + Subpasses[1].InputAttachmentCount = _countof(InputAttachmentRefs1); + Subpasses[1].pInputAttachments = InputAttachmentRefs1; + + SubpassDependencyDesc Dependencies[1]; + Dependencies[0].SrcSubpass = 0; + Dependencies[0].DstSubpass = 1; + Dependencies[0].SrcStageMask = PIPELINE_STAGE_FLAG_RENDER_TARGET; + Dependencies[0].DstStageMask = PIPELINE_STAGE_FLAG_PIXEL_SHADER; + Dependencies[0].SrcAccessMask = ACCESS_FLAG_RENDER_TARGET_WRITE; + Dependencies[0].DstAccessMask = ACCESS_FLAG_SHADER_READ; + + RenderPassDesc RPDesc; + RPDesc.Name = "Render pass input attachment test"; + RPDesc.AttachmentCount = _countof(Attachments); + RPDesc.pAttachments = Attachments; + RPDesc.SubpassCount = _countof(Subpasses); + RPDesc.pSubpasses = Subpasses; + RPDesc.DependencyCount = _countof(Dependencies); + RPDesc.pDependencies = Dependencies; + + RefCntAutoPtr<IRenderPass> pRenderPass; + pDevice->CreateRenderPass(RPDesc, &pRenderPass); + ASSERT_NE(pRenderPass, nullptr); + + RefCntAutoPtr<IPipelineState> pPSO; + RefCntAutoPtr<IShaderResourceBinding> pSRB; + CreateDrawTrisPSO(pRenderPass, 1, pPSO, pSRB); + ASSERT_TRUE(pPSO != nullptr && pSRB != nullptr); + + RefCntAutoPtr<IPipelineState> pInputAttachmentPSO; + RefCntAutoPtr<IShaderResourceBinding> pInputAttachmentSRB; + { + PipelineStateCreateInfo PSOCreateInfo; + PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; + + PSODesc.Name = "Render pass test - input attachment"; + + PSODesc.IsComputePipeline = false; + PSODesc.GraphicsPipeline.pRenderPass = pRenderPass; + PSODesc.GraphicsPipeline.SubpassIndex = 1; + PSODesc.GraphicsPipeline.SmplDesc.Count = 1; + PSODesc.GraphicsPipeline.PrimitiveTopology = PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + PSODesc.GraphicsPipeline.RasterizerDesc.CullMode = CULL_MODE_NONE; + PSODesc.GraphicsPipeline.DepthStencilDesc.DepthEnable = False; + + ShaderCreateInfo ShaderCI; + ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM; + ShaderCI.UseCombinedTextureSamplers = true; + + RefCntAutoPtr<IShader> pVS; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_VERTEX; + ShaderCI.EntryPoint = "main"; + ShaderCI.Desc.Name = "Input attachment test VS"; + ShaderCI.Source = GLSL::DrawTest_ProceduralTriangleVS.c_str(); + pDevice->CreateShader(ShaderCI, &pVS); + ASSERT_NE(pVS, nullptr); + } + + RefCntAutoPtr<IShader> pPS; + { + ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL; + ShaderCI.EntryPoint = "main"; + ShaderCI.Desc.Name = "Input attachment test PS"; + ShaderCI.Source = GLSL::InputAttachmentTest_FS.c_str(); + pDevice->CreateShader(ShaderCI, &pPS); + ASSERT_NE(pPS, nullptr); + } + + PSODesc.GraphicsPipeline.pVS = pVS; + PSODesc.GraphicsPipeline.pPS = pPS; + + pDevice->CreatePipelineState(PSOCreateInfo, &pInputAttachmentPSO); + ASSERT_NE(pInputAttachmentPSO, nullptr); + pInputAttachmentPSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "in_Color")->Set(pTex->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)); + pInputAttachmentPSO->CreateShaderResourceBinding(&pInputAttachmentSRB, true); + ASSERT_NE(pInputAttachmentSRB, nullptr); + pContext->TransitionShaderResources(pInputAttachmentPSO, pInputAttachmentSRB); + } + + ITextureView* pRTAttachments[] = // + { + pTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET), + pSwapChain->GetCurrentBackBufferRTV() // + }; + + FramebufferDesc FBDesc; + FBDesc.Name = "Render pass input attachment test framebuffer"; + FBDesc.pRenderPass = pRenderPass; + FBDesc.AttachmentCount = _countof(Attachments); + FBDesc.ppAttachments = pRTAttachments; + RefCntAutoPtr<IFramebuffer> pFramebuffer; + pDevice->CreateFramebuffer(FBDesc, &pFramebuffer); + ASSERT_TRUE(pFramebuffer); + + pContext->SetPipelineState(pPSO); + pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + + BeginRenderPassAttribs RPBeginInfo; + RPBeginInfo.pRenderPass = pRenderPass; + RPBeginInfo.pFramebuffer = pFramebuffer; + + OptimizedClearValue ClearValues[2]; + ClearValues[0].Color[0] = 0; + ClearValues[0].Color[1] = 0; + ClearValues[0].Color[2] = 0; + ClearValues[0].Color[3] = 0; + + ClearValues[1].Color[0] = ClearColor[0]; + ClearValues[1].Color[1] = ClearColor[1]; + ClearValues[1].Color[2] = ClearColor[2]; + ClearValues[1].Color[3] = ClearColor[3]; + + RPBeginInfo.pClearValues = ClearValues; + RPBeginInfo.ClearValueCount = _countof(ClearValues); + RPBeginInfo.StateTransitionMode = RESOURCE_STATE_TRANSITION_MODE_TRANSITION; + pContext->BeginRenderPass(RPBeginInfo); + + DrawAttribs DrawAttrs{6, DRAW_FLAG_VERIFY_ALL}; + pContext->Draw(DrawAttrs); + + pContext->NextSubpass(); + + pContext->SetPipelineState(pInputAttachmentPSO); + pContext->CommitShaderResources(pInputAttachmentSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY); + + pContext->Draw(DrawAttrs); + + pContext->EndRenderPass(true); + + Present(); } } // namespace diff --git a/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp b/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp index 1896ba60..e0561f34 100644 --- a/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp +++ b/Tests/DiligentCoreAPITest/src/TestingEnvironment.cpp @@ -303,8 +303,8 @@ TestingEnvironment::TestingEnvironment(RENDER_DEVICE_TYPE deviceType, ADAPTER_TY EngineVkCreateInfo CreateInfo; CreateInfo.DebugMessageCallback = MessageCallback; CreateInfo.EnableValidation = true; - CreateInfo.MainDescriptorPoolSize = VulkanDescriptorPoolSize{64, 64, 256, 256, 64, 32, 32, 32, 32}; - CreateInfo.DynamicDescriptorPoolSize = VulkanDescriptorPoolSize{64, 64, 256, 256, 64, 32, 32, 32, 32}; + CreateInfo.MainDescriptorPoolSize = VulkanDescriptorPoolSize{64, 64, 256, 256, 64, 32, 32, 32, 32, 16}; + CreateInfo.DynamicDescriptorPoolSize = VulkanDescriptorPoolSize{64, 64, 256, 256, 64, 32, 32, 32, 32, 16}; CreateInfo.UploadHeapPageSize = 32 * 1024; //CreateInfo.DeviceLocalMemoryReserveSize = 32 << 20; //CreateInfo.HostVisibleMemoryReserveSize = 48 << 20; diff --git a/Tests/DiligentCoreAPITest/src/Vulkan/DrawCommandReferenceVk.cpp b/Tests/DiligentCoreAPITest/src/Vulkan/DrawCommandReferenceVk.cpp index 2ee67755..6084402f 100644 --- a/Tests/DiligentCoreAPITest/src/Vulkan/DrawCommandReferenceVk.cpp +++ b/Tests/DiligentCoreAPITest/src/Vulkan/DrawCommandReferenceVk.cpp @@ -47,7 +47,10 @@ namespace struct ReferenceTriangleRenderer { - ReferenceTriangleRenderer(ISwapChain* pSwapChain, VkRenderPass vkRenderPass, VkSampleCountFlagBits SampleCount = VK_SAMPLE_COUNT_1_BIT) + ReferenceTriangleRenderer(ISwapChain* pSwapChain, + VkRenderPass vkRenderPass, + VkSampleCountFlagBits SampleCount = VK_SAMPLE_COUNT_1_BIT, + VkImageView InputAttachmentView = VK_NULL_HANDLE) { auto* pEnv = TestingEnvironmentVk::GetInstance(); auto vkDevice = pEnv->GetVkDevice(); @@ -59,7 +62,7 @@ struct ReferenceTriangleRenderer vkVSModule = pEnv->CreateShaderModule(SHADER_TYPE_VERTEX, GLSL::DrawTest_ProceduralTriangleVS); VERIFY_EXPR(vkVSModule != VK_NULL_HANDLE); - vkPSModule = pEnv->CreateShaderModule(SHADER_TYPE_PIXEL, GLSL::DrawTest_FS); + vkPSModule = pEnv->CreateShaderModule(SHADER_TYPE_PIXEL, InputAttachmentView != VK_NULL_HANDLE ? GLSL::InputAttachmentTest_FS : GLSL::DrawTest_FS); VERIFY_EXPR(vkPSModule != VK_NULL_HANDLE); VkGraphicsPipelineCreateInfo PipelineCI = {}; @@ -85,8 +88,76 @@ struct ReferenceTriangleRenderer VkPipelineLayoutCreateInfo PipelineLayoutCI = {}; PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + + VkDescriptorSetLayout vkSetLayout[1] = {}; + if (InputAttachmentView != VK_NULL_HANDLE) + { + VkDescriptorSetLayoutBinding Bindings[1] = {}; + Bindings[0].binding = 0; + Bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + Bindings[0].descriptorCount = 1; + Bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + Bindings[0].pImmutableSamplers = nullptr; + + VkDescriptorSetLayoutCreateInfo SetLayoutCI = {}; + + SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + SetLayoutCI.pNext = nullptr; + SetLayoutCI.flags = 0; + SetLayoutCI.bindingCount = 1; + SetLayoutCI.pBindings = Bindings; + + vkCreateDescriptorSetLayout(vkDevice, &SetLayoutCI, nullptr, &vkSetLayout[0]); + VERIFY_EXPR(vkSetLayout[0] != VK_NULL_HANDLE); + + PipelineLayoutCI.setLayoutCount = 1; + PipelineLayoutCI.pSetLayouts = vkSetLayout; + + VkDescriptorPoolCreateInfo DescriptorPoolCI = {}; + DescriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + DescriptorPoolCI.pNext = nullptr; + DescriptorPoolCI.flags = 0; + DescriptorPoolCI.maxSets = 1; + VkDescriptorPoolSize PoolSizes[] = {{VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1}}; + DescriptorPoolCI.poolSizeCount = _countof(PoolSizes); + DescriptorPoolCI.pPoolSizes = PoolSizes; + + vkCreateDescriptorPool(vkDevice, &DescriptorPoolCI, nullptr, &vkDescriptorPool); + VERIFY_EXPR(vkDescriptorPool != VK_NULL_HANDLE); + + VkDescriptorSetAllocateInfo SetAllocateInfo = {}; + SetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + SetAllocateInfo.pNext = nullptr; + SetAllocateInfo.descriptorPool = vkDescriptorPool; + SetAllocateInfo.descriptorSetCount = 1; + SetAllocateInfo.pSetLayouts = vkSetLayout; + + vkAllocateDescriptorSets(vkDevice, &SetAllocateInfo, &vkDescriptorSet); + VERIFY_EXPR(vkDescriptorSet != VK_NULL_HANDLE); + + VkWriteDescriptorSet DescriptorWrites[1] = {}; + + DescriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + DescriptorWrites[0].pNext = nullptr; + DescriptorWrites[0].dstSet = vkDescriptorSet; + DescriptorWrites[0].dstBinding = 0; + DescriptorWrites[0].dstArrayElement = 0; + DescriptorWrites[0].descriptorCount = 1; + DescriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + VkDescriptorImageInfo ImageInfo[1] = {}; + ImageInfo[0].sampler = VK_NULL_HANDLE; + ImageInfo[0].imageView = InputAttachmentView; + ImageInfo[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + DescriptorWrites[0].pImageInfo = ImageInfo; + + vkUpdateDescriptorSets(vkDevice, 1, DescriptorWrites, 0, nullptr); + } vkCreatePipelineLayout(vkDevice, &PipelineLayoutCI, nullptr, &vkLayout); VERIFY_EXPR(vkLayout != VK_NULL_HANDLE); + if (vkSetLayout[0] != VK_NULL_HANDLE) + { + vkDestroyDescriptorSetLayout(vkDevice, vkSetLayout[0], nullptr); + } PipelineCI.layout = vkLayout; VkPipelineVertexInputStateCreateInfo VertexInputStateCI = {}; @@ -191,7 +262,7 @@ struct ReferenceTriangleRenderer PipelineCI.pDynamicState = &DynamicStateCI; PipelineCI.renderPass = vkRenderPass; - PipelineCI.subpass = 0; + PipelineCI.subpass = InputAttachmentView != VK_NULL_HANDLE ? 1 : 0; PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from PipelineCI.basePipelineIndex = 0; // an index into the pCreateInfos parameter to use as a pipeline to derive from @@ -202,6 +273,8 @@ struct ReferenceTriangleRenderer void Draw(VkCommandBuffer vkCmdBuffer) { + if (vkDescriptorSet != VK_NULL_HANDLE) + vkCmdBindDescriptorSets(vkCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkLayout, 0, 1, &vkDescriptorSet, 0, nullptr); vkCmdBindPipeline(vkCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline); vkCmdDraw(vkCmdBuffer, 6, 1, 0, 0); } @@ -215,13 +288,17 @@ struct ReferenceTriangleRenderer vkDestroyPipelineLayout(vkDevice, vkLayout, nullptr); vkDestroyShaderModule(vkDevice, vkVSModule, nullptr); vkDestroyShaderModule(vkDevice, vkPSModule, nullptr); + if (vkDescriptorPool != VK_NULL_HANDLE) + vkDestroyDescriptorPool(vkDevice, vkDescriptorPool, nullptr); } private: - VkShaderModule vkVSModule = VK_NULL_HANDLE; - VkShaderModule vkPSModule = VK_NULL_HANDLE; - VkPipeline vkPipeline = VK_NULL_HANDLE; - VkPipelineLayout vkLayout = VK_NULL_HANDLE; + VkShaderModule vkVSModule = VK_NULL_HANDLE; + VkShaderModule vkPSModule = VK_NULL_HANDLE; + VkPipeline vkPipeline = VK_NULL_HANDLE; + VkPipelineLayout vkLayout = VK_NULL_HANDLE; + VkDescriptorPool vkDescriptorPool = VK_NULL_HANDLE; + VkDescriptorSet vkDescriptorSet = VK_NULL_HANDLE; }; } // namespace @@ -290,8 +367,8 @@ void RenderPassMSResolveReferenceVk(ISwapChain* pSwapChain, const float* pClearC Attachments[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference ColorAttachmentRef[1] = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference RslvAttachmentRef[1] = {1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference ColorAttachmentRef[] = {{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; + VkAttachmentReference RslvAttachmentRef[] = {{1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; VkSubpassDescription Subpasses[1] = {}; Subpasses[0].flags = 0; @@ -384,9 +461,8 @@ void RenderPassMSResolveReferenceVk(ISwapChain* pSwapChain, const float* pClearC BeginInfo.pClearValues = ClearValues; vkCmdBeginRenderPass(vkCmdBuffer, &BeginInfo, VK_SUBPASS_CONTENTS_INLINE); - TriRenderer.Draw(vkCmdBuffer); - pTestingSwapChainVk->EndRenderPass(vkCmdBuffer); + vkCmdEndRenderPass(vkCmdBuffer); vkEndCommandBuffer(vkCmdBuffer); pEnv->SubmitCommandBuffer(vkCmdBuffer, true); @@ -396,8 +472,177 @@ void RenderPassMSResolveReferenceVk(ISwapChain* pSwapChain, const float* pClearC void RenderPassInputAttachmentReferenceVk(ISwapChain* pSwapChain, const float* pClearColor) { -} + auto* pEnv = TestingEnvironmentVk::GetInstance(); + auto* pDevice = pEnv->GetDevice(); + auto vkDevice = pEnv->GetVkDevice(); + + auto* pTestingSwapChainVk = ValidatedCast<TestingSwapChainVk>(pSwapChain); + const auto& SCDesc = pTestingSwapChainVk->GetDesc(); + + VkRenderPassCreateInfo RenderPassCI = {}; + + RenderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + RenderPassCI.pNext = nullptr; + RenderPassCI.flags = 0; // reserved for future use + RenderPassCI.attachmentCount = 2; + + VkAttachmentDescription Attachments[2] = {}; + + Attachments[0].flags = 0; + Attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; + Attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + Attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + Attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + Attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + Attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + Attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + switch (SCDesc.ColorBufferFormat) + { + case TEX_FORMAT_RGBA8_UNORM: + Attachments[0].format = VK_FORMAT_R8G8B8A8_UNORM; + break; + + default: + UNSUPPORTED("Unsupported swap chain format"); + } + + Attachments[1].flags = 0; + Attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; + Attachments[1].format = Attachments[0].format; + Attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + Attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + Attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + Attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + Attachments[1].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + Attachments[1].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference ColorAttachmentRef0[] = {{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; + VkAttachmentReference InputAttachmentRef1[] = {{0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}}; + VkAttachmentReference ColorAttachmentRef1[] = {{1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; + + VkSubpassDescription Subpasses[2] = {}; + Subpasses[0].flags = 0; + Subpasses[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + Subpasses[0].colorAttachmentCount = _countof(ColorAttachmentRef0); + Subpasses[0].pColorAttachments = ColorAttachmentRef0; + + Subpasses[1].flags = 0; + Subpasses[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + Subpasses[1].colorAttachmentCount = _countof(ColorAttachmentRef1); + Subpasses[1].pColorAttachments = ColorAttachmentRef1; + Subpasses[1].inputAttachmentCount = _countof(InputAttachmentRef1); + Subpasses[1].pInputAttachments = InputAttachmentRef1; + + VkSubpassDependency dependencies[1] = {}; + dependencies[0].srcSubpass = 0; + dependencies[0].dstSubpass = 1; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + RenderPassCI.attachmentCount = _countof(Attachments); + RenderPassCI.pAttachments = Attachments; + RenderPassCI.subpassCount = _countof(Subpasses); + RenderPassCI.pSubpasses = Subpasses; + RenderPassCI.dependencyCount = _countof(dependencies); + RenderPassCI.pDependencies = dependencies; + + VkRenderPass vkRenderPass = VK_NULL_HANDLE; + vkCreateRenderPass(vkDevice, &RenderPassCI, nullptr, &vkRenderPass); + ASSERT_TRUE(vkRenderPass != VK_NULL_HANDLE); + + ReferenceTriangleRenderer TriRenderer{pSwapChain, vkRenderPass}; + RefCntAutoPtr<ITexture> pTex; + { + TextureDesc TexDesc; + TexDesc.Type = RESOURCE_DIM_TEX_2D; + TexDesc.Format = SCDesc.ColorBufferFormat; + TexDesc.Width = SCDesc.Width; + TexDesc.Height = SCDesc.Height; + TexDesc.BindFlags = BIND_RENDER_TARGET | BIND_INPUT_ATTACHMENT; + TexDesc.MipLevels = 1; + TexDesc.Usage = USAGE_DEFAULT; + + pDevice->CreateTexture(TexDesc, nullptr, &pTex); + ASSERT_NE(pTex, nullptr); + } + RefCntAutoPtr<ITextureVk> pTexVK{pTex, IID_TextureVk}; + ASSERT_NE(pTexVK, nullptr); + RefCntAutoPtr<ITextureViewVk> pTexViewVK{pTex->GetDefaultView(TEXTURE_VIEW_RENDER_TARGET), IID_TextureViewVk}; + ASSERT_NE(pTexViewVK, nullptr); + + ReferenceTriangleRenderer TriRenderer2{pSwapChain, vkRenderPass, VK_SAMPLE_COUNT_1_BIT, pTexViewVK->GetVulkanImageView()}; + + VkFramebufferCreateInfo FramebufferCI = {}; + + FramebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + FramebufferCI.pNext = nullptr; + FramebufferCI.flags = 0; + FramebufferCI.renderPass = vkRenderPass; + + VkImageView FramebufferAttachments[2]; + FramebufferAttachments[0] = pTexViewVK->GetVulkanImageView(); + FramebufferAttachments[1] = pTestingSwapChainVk->GetVkRenderTargetImageView(); + FramebufferCI.pAttachments = FramebufferAttachments; + FramebufferCI.attachmentCount = _countof(FramebufferAttachments); + + FramebufferCI.width = SCDesc.Width; + FramebufferCI.height = SCDesc.Height; + FramebufferCI.layers = 1; + + VkFramebuffer vkFramebuffer = VK_NULL_HANDLE; + vkCreateFramebuffer(vkDevice, &FramebufferCI, nullptr, &vkFramebuffer); + ASSERT_TRUE(vkFramebuffer != VK_NULL_HANDLE); + + VkCommandBuffer vkCmdBuffer = pEnv->AllocateCommandBuffer(); + pTestingSwapChainVk->TransitionRenderTarget(vkCmdBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + { + auto CurrLayout = pTexVK->GetLayout(); + + VkImageSubresourceRange SubResRange; + SubResRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + SubResRange.baseMipLevel = 0; + SubResRange.levelCount = 1; + SubResRange.baseArrayLayer = 0; + SubResRange.layerCount = 1; + pEnv->TransitionImageLayout(vkCmdBuffer, pTexVK->GetVkImage(), CurrLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, SubResRange, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + } + + VkRenderPassBeginInfo BeginInfo = {}; + + BeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + BeginInfo.renderPass = vkRenderPass; + BeginInfo.framebuffer = vkFramebuffer; + BeginInfo.renderArea.extent = VkExtent2D{SCDesc.Width, SCDesc.Height}; + + VkClearValue ClearValues[2] = {}; + ClearValues[0].color.float32[0] = 0; + ClearValues[0].color.float32[1] = 0; + ClearValues[0].color.float32[2] = 0; + ClearValues[0].color.float32[3] = 0; + + ClearValues[1].color.float32[0] = pClearColor[0]; + ClearValues[1].color.float32[1] = pClearColor[1]; + ClearValues[1].color.float32[2] = pClearColor[2]; + ClearValues[1].color.float32[3] = pClearColor[3]; + + BeginInfo.clearValueCount = _countof(ClearValues); + BeginInfo.pClearValues = ClearValues; + + vkCmdBeginRenderPass(vkCmdBuffer, &BeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + TriRenderer.Draw(vkCmdBuffer); + vkCmdNextSubpass(vkCmdBuffer, VK_SUBPASS_CONTENTS_INLINE); + TriRenderer2.Draw(vkCmdBuffer); + vkCmdEndRenderPass(vkCmdBuffer); + vkEndCommandBuffer(vkCmdBuffer); + pEnv->SubmitCommandBuffer(vkCmdBuffer, true); + + vkDestroyRenderPass(vkDevice, vkRenderPass, nullptr); + vkDestroyFramebuffer(vkDevice, vkFramebuffer, nullptr); +} } // namespace Testing |
