From b1bac52d792f348c8a5be7d85bae070d2322479d Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Thu, 25 Oct 2018 08:44:11 -0700 Subject: Some improvements D3D shader resource management --- .../include/ShaderResourceLayoutD3D11.h | 153 ++++------ .../src/ShaderResourceLayoutD3D11.cpp | 338 ++++++++++++--------- .../src/ShaderResourceLayoutD3D12.cpp | 6 +- .../include/D3DShaderResourceLoader.h | 40 ++- .../include/ShaderResources.h | 26 +- .../GraphicsEngineD3DBase/src/ShaderResources.cpp | 89 +++--- 6 files changed, 332 insertions(+), 320 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.h b/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.h index 937a992d..3a5bbbe2 100644 --- a/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.h +++ b/Graphics/GraphicsEngineD3D11/include/ShaderResourceLayoutD3D11.h @@ -211,13 +211,28 @@ public: Uint32 GetVariableIndex(const ShaderVariableD3D11Base& Variable)const; Uint32 GetTotalResourceCount()const { - auto ResourceCount = m_NumCBs + m_NumTexSRVs + m_NumTexUAVs + m_NumBufUAVs + m_NumBufSRVs; + auto ResourceCount = GetNumCBs() + GetNumTexSRVs() + GetNumTexUAVs() + GetNumBufUAVs() + GetNumBufSRVs(); // Do not expose sampler variables when using combined texture samplers if (!m_pResources->IsUsingCombinedTextureSamplers()) - ResourceCount += m_NumSamplers; + ResourceCount += GetNumSamplers(); return ResourceCount; } + Uint32 GetNumCBs() const { return (m_TexSRVsOffset - 0 ) / sizeof(ConstBuffBindInfo);} + Uint32 GetNumTexSRVs() const { return (m_TexUAVsOffset - m_TexSRVsOffset ) / sizeof(TexSRVBindInfo); } + Uint32 GetNumTexUAVs() const { return (m_BuffSRVsOffset - m_TexUAVsOffset ) / sizeof(TexUAVBindInfo) ; } + Uint32 GetNumBufSRVs() const { return (m_BuffUAVsOffset - m_BuffSRVsOffset) / sizeof(BuffSRVBindInfo); } + Uint32 GetNumBufUAVs() const { return (m_SamplerOffset - m_BuffUAVsOffset) / sizeof(BuffUAVBindInfo); } + Uint32 GetNumSamplers() const { return (m_MemorySize - m_SamplerOffset ) / sizeof(SamplerBindInfo); } + + template Uint32 GetNumResources()const; + template<> Uint32 GetNumResources() const { return GetNumCBs(); } + template<> Uint32 GetNumResources () const { return GetNumTexSRVs(); } + template<> Uint32 GetNumResources () const { return GetNumTexUAVs(); } + template<> Uint32 GetNumResources () const { return GetNumBufSRVs(); } + template<> Uint32 GetNumResources () const { return GetNumBufUAVs(); } + template<> Uint32 GetNumResources () const { return GetNumSamplers(); } + private: const Char* GetShaderName()const @@ -232,84 +247,40 @@ private: std::unique_ptr > m_ResourceBuffer; // Offsets in bytes - Uint16 m_TexSRVsOffset = 0; - Uint16 m_TexUAVsOffset = 0; - Uint16 m_BuffUAVsOffset = 0; - Uint16 m_BuffSRVsOffset = 0; - Uint16 m_SamplerOffset = 0; + using OffsetType = Uint16; + OffsetType m_TexSRVsOffset = 0; + OffsetType m_TexUAVsOffset = 0; + OffsetType m_BuffSRVsOffset = 0; + OffsetType m_BuffUAVsOffset = 0; + OffsetType m_SamplerOffset = 0; + OffsetType m_MemorySize = 0; - Uint8 m_NumCBs = 0; // Max == 14 - Uint8 m_NumTexSRVs = 0; // Max == 128 - Uint8 m_NumTexUAVs = 0; // Max == 8 - Uint8 m_NumBufUAVs = 0; // Max == 8 - Uint8 m_NumBufSRVs = 0; // Max == 128 - Uint8 m_NumSamplers = 0; // Max == 16 - - ConstBuffBindInfo& GetCB(Uint32 cb) - { - VERIFY_EXPR(cb(m_ResourceBuffer.get())[cb]; - } - const ConstBuffBindInfo& GetCB(Uint32 cb)const - { - VERIFY_EXPR(cb(m_ResourceBuffer.get())[cb]; - } - - TexSRVBindInfo& GetTexSRV(Uint32 t) - { - VERIFY_EXPR(t( reinterpret_cast(m_ResourceBuffer.get()) + m_TexSRVsOffset)[t]; - } - const TexSRVBindInfo& GetTexSRV(Uint32 t)const - { - VERIFY_EXPR(t( reinterpret_cast(m_ResourceBuffer.get()) + m_TexSRVsOffset)[t]; - } - - TexUAVBindInfo& GetTexUAV(Uint32 u) - { - VERIFY_EXPR(u < m_NumTexUAVs); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_TexUAVsOffset)[u]; - } - const TexUAVBindInfo& GetTexUAV(Uint32 u)const - { - VERIFY_EXPR(u < m_NumTexUAVs); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_TexUAVsOffset)[u]; - } - - BuffUAVBindInfo& GetBufUAV(Uint32 u) - { - VERIFY_EXPR(u < m_NumBufUAVs); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_BuffUAVsOffset)[u]; - } - const BuffUAVBindInfo& GetBufUAV(Uint32 u)const - { - VERIFY_EXPR(u < m_NumBufUAVs); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_BuffUAVsOffset)[u]; - } - - BuffSRVBindInfo& GetBufSRV(Uint32 s) - { - VERIFY_EXPR(s < m_NumBufSRVs); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_BuffSRVsOffset)[s]; - } - const BuffSRVBindInfo& GetBufSRV(Uint32 s)const - { - VERIFY_EXPR(s < m_NumBufSRVs); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_BuffSRVsOffset)[s]; - } - - SamplerBindInfo& GetSampler(Uint32 s) + template OffsetType GetResourceOffset()const; + template<> OffsetType GetResourceOffset() const { return 0; } + template<> OffsetType GetResourceOffset () const { return m_TexSRVsOffset; } + template<> OffsetType GetResourceOffset () const { return m_TexUAVsOffset; } + template<> OffsetType GetResourceOffset () const { return m_BuffSRVsOffset; } + template<> OffsetType GetResourceOffset () const { return m_BuffUAVsOffset; } + template<> OffsetType GetResourceOffset () const { return m_SamplerOffset; } + + template + ResourceType& GetResource(Uint32 ResIndex) { - VERIFY_EXPR(s < m_NumSamplers); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_SamplerOffset)[s]; + VERIFY(ResIndex < GetNumResources(), "Resource index (", ResIndex, ") exceeds max allowed value (", GetNumResources(), ")"); + auto Offset = GetResourceOffset(); + return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + Offset)[ResIndex]; } - const SamplerBindInfo& GetSampler(Uint32 s)const + + template + const ResourceType& GetConstResource(Uint32 ResIndex)const { - VERIFY_EXPR(s < m_NumSamplers); - return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + m_SamplerOffset)[s]; + VERIFY(ResIndex < GetNumResources(), "Resource index (", ResIndex, ") exceeds max allowed value (", GetNumResources(), ")"); + auto Offset = GetResourceOffset(); + return reinterpret_cast( reinterpret_cast(m_ResourceBuffer.get()) + Offset)[ResIndex]; } + + template + IShaderVariable* GetResourceByName( const Char* Name ); template(); ++cb) + HandleCB(GetResource(cb)); + + for (Uint32 t = 0; t < GetNumResources(); ++t) + HandleTexSRV(GetResource(t)); + + for (Uint32 u = 0; u < GetNumResources(); ++u) + HandleTexUAV(GetResource(u)); + + for (Uint32 s = 0; s < GetNumResources(); ++s) + HandleBufSRV(GetResource(s)); + + for (Uint32 u = 0; u < GetNumResources(); ++u) + HandleBufUAV(GetResource(u)); + + for (Uint32 s = 0; s < GetNumResources(); ++s) + HandleSampler(GetResource(s)); } std::shared_ptr m_pResources; IObject& m_Owner; + + friend class ShaderVariableIndexLocator; + friend class ShaderVariableLocator; }; } diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp index 1a175e38..d0e5f982 100755 --- a/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourceLayoutD3D11.cpp @@ -81,14 +81,13 @@ size_t ShaderResourceLayoutD3D11::GetRequiredMemorySize(const ShaderResourcesD3D const SHADER_VARIABLE_TYPE* VarTypes, Uint32 NumVarTypes) { - Uint32 NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers; - SrcResources.CountResources(VarTypes, NumVarTypes, NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers); - auto MemSize = NumCBs * sizeof(ConstBuffBindInfo) + - NumTexSRVs * sizeof(TexSRVBindInfo) + - NumTexUAVs * sizeof(TexUAVBindInfo) + - NumBufUAVs * sizeof(BuffUAVBindInfo) + - NumBufSRVs * sizeof(BuffSRVBindInfo) + - NumSamplers * sizeof(SamplerBindInfo); + auto ResCounters = SrcResources.CountResources(VarTypes, NumVarTypes); + auto MemSize = ResCounters.NumCBs * sizeof(ConstBuffBindInfo) + + ResCounters.NumTexSRVs * sizeof(TexSRVBindInfo) + + ResCounters.NumTexUAVs * sizeof(TexUAVBindInfo) + + ResCounters.NumBufSRVs * sizeof(BuffSRVBindInfo) + + ResCounters.NumBufUAVs * sizeof(BuffUAVBindInfo) + + ResCounters.NumSamplers * sizeof(SamplerBindInfo); return MemSize; } @@ -107,37 +106,41 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptrCountResources(VarTypes, NumVarTypes, NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers); + auto ResCounters = m_pResources->CountResources(VarTypes, NumVarTypes); // Initialize offsets - m_TexSRVsOffset = 0 + static_cast( NumCBs * sizeof(ConstBuffBindInfo)); - m_TexUAVsOffset = m_TexSRVsOffset + static_cast( NumTexSRVs * sizeof(TexSRVBindInfo) ); - m_BuffUAVsOffset = m_TexUAVsOffset + static_cast( NumTexUAVs * sizeof(TexUAVBindInfo) ); - m_BuffSRVsOffset = m_BuffUAVsOffset + static_cast( NumBufUAVs * sizeof(BuffUAVBindInfo) ); - m_SamplerOffset = m_BuffSRVsOffset + static_cast( NumBufSRVs * sizeof(BuffSRVBindInfo) ); - auto MemorySize = m_SamplerOffset + NumSamplers * sizeof(SamplerBindInfo) ; - - VERIFY_EXPR(MemorySize == GetRequiredMemorySize(*m_pResources, VarTypes, NumVarTypes)); - - if( MemorySize ) + size_t CurrentOffset = 0; + auto AdvanceOffset = [&CurrentOffset](size_t NumResources) + { + constexpr size_t MaxOffset = std::numeric_limits::max(); + VERIFY(CurrentOffset <= MaxOffset, "Current offser (", CurrentOffset, ") exceeds max allowed value (", MaxOffset, ")"); + auto Offset = static_cast(CurrentOffset); + CurrentOffset += NumResources; + return Offset; + }; + + auto CBOffset = AdvanceOffset(ResCounters.NumCBs * sizeof(ConstBuffBindInfo)); CBOffset; // To suppress warning + m_TexSRVsOffset = AdvanceOffset(ResCounters.NumTexSRVs * sizeof(TexSRVBindInfo) ); + m_TexUAVsOffset = AdvanceOffset(ResCounters.NumTexUAVs * sizeof(TexUAVBindInfo) ); + m_BuffSRVsOffset = AdvanceOffset(ResCounters.NumBufSRVs * sizeof(BuffSRVBindInfo) ); + m_BuffUAVsOffset = AdvanceOffset(ResCounters.NumBufUAVs * sizeof(BuffUAVBindInfo) ); + m_SamplerOffset = AdvanceOffset(ResCounters.NumSamplers * sizeof(SamplerBindInfo) ); + m_MemorySize = AdvanceOffset(0); + + VERIFY_EXPR(m_MemorySize == GetRequiredMemorySize(*m_pResources, VarTypes, NumVarTypes)); + + if (m_MemorySize) { - auto *pRawMem = ALLOCATE(ResLayoutDataAllocator, "Raw memory buffer for shader resource layout resources", MemorySize); + auto *pRawMem = ALLOCATE(ResLayoutDataAllocator, "Raw memory buffer for shader resource layout resources", m_MemorySize); m_ResourceBuffer = std::unique_ptr >(pRawMem, ResLayoutDataAllocator); } - VERIFY_EXPR(NumCBs < 255); - VERIFY_EXPR(NumTexSRVs < 255); - VERIFY_EXPR(NumTexUAVs < 255); - VERIFY_EXPR(NumBufSRVs < 255); - VERIFY_EXPR(NumBufUAVs < 255); - VERIFY_EXPR(NumSamplers< 255); - m_NumCBs = static_cast(NumCBs); - m_NumTexSRVs = static_cast(NumTexSRVs); - m_NumTexUAVs = static_cast(NumTexUAVs); - m_NumBufSRVs = static_cast(NumBufSRVs); - m_NumBufUAVs = static_cast(NumBufUAVs); - m_NumSamplers = static_cast(NumSamplers); + VERIFY_EXPR(ResCounters.NumCBs == GetNumCBs() ); + VERIFY_EXPR(ResCounters.NumTexSRVs == GetNumTexSRVs() ); + VERIFY_EXPR(ResCounters.NumTexUAVs == GetNumTexUAVs() ); + VERIFY_EXPR(ResCounters.NumBufSRVs == GetNumBufSRVs() ); + VERIFY_EXPR(ResCounters.NumBufUAVs == GetNumBufUAVs() ); + VERIFY_EXPR(ResCounters.NumSamplers== GetNumSamplers()); // Current resource index for every resource type Uint32 cb = 0; @@ -159,7 +162,7 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr(cb++)) ConstBuffBindInfo( CB, *this ); NumCBSlots = std::max(NumCBSlots, Uint32{CB.BindPoint} + Uint32{CB.BindCount}); }, @@ -171,7 +174,7 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr(sam++)) SamplerBindInfo( Sampler, *this ); NumSamplerSlots = std::max(NumSamplerSlots, Uint32{Sampler.BindPoint} + Uint32{Sampler.BindCount}); } }, @@ -179,7 +182,8 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr(AssignedSamplerIndex); if (strcmp(Sampler.Attribs.Name, AssignedSamplerAttribs.Name) == 0) break; } - VERIFY(AssignedSamplerIndex < m_NumSamplers, "Unable to find assigned sampler"); + VERIFY(AssignedSamplerIndex < NumSamplers, "Unable to find assigned sampler"); } } // Initialize tex SRV in place, increment counter of tex SRVs - new (&GetTexSRV(texSrv++)) TexSRVBindInfo( TexSRV, AssignedSamplerIndex, *this ); + new (&GetResource(texSrv++)) TexSRVBindInfo( TexSRV, AssignedSamplerIndex, *this ); NumSRVSlots = std::max(NumSRVSlots, Uint32{TexSRV.BindPoint} + Uint32{TexSRV.BindCount}); }, @@ -212,7 +216,7 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr(texUav++)) TexUAVBindInfo( TexUAV, *this ); NumUAVSlots = std::max(NumUAVSlots, Uint32{TexUAV.BindPoint} + Uint32{TexUAV.BindCount}); }, @@ -221,7 +225,7 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr(bufSrv++)) BuffSRVBindInfo( BuffSRV, *this ); NumSRVSlots = std::max(NumSRVSlots, Uint32{BuffSRV.BindPoint} + Uint32{BuffSRV.BindCount}); }, @@ -230,17 +234,17 @@ void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr(bufUav++)) BuffUAVBindInfo( BuffUAV, *this ); NumUAVSlots = std::max(NumUAVSlots, Uint32{BuffUAV.BindPoint} + Uint32{BuffUAV.BindCount}); } ); - VERIFY(cb == m_NumCBs, "Not all CBs are initialized which will cause a crash when dtor is called"); - VERIFY(texSrv == m_NumTexSRVs, "Not all Tex SRVs are initialized which will cause a crash when dtor is called"); - VERIFY(texUav == m_NumTexUAVs, "Not all Tex UAVs are initialized which will cause a crash when dtor is called"); - VERIFY(bufSrv == m_NumBufSRVs, "Not all Buf SRVs are initialized which will cause a crash when dtor is called"); - VERIFY(bufUav == m_NumBufUAVs, "Not all Buf UAVs are initialized which will cause a crash when dtor is called"); - VERIFY(sam == m_NumSamplers, "Not all samplers are initialized which will cause a crash when dtor is called"); + VERIFY(cb == GetNumCBs(), "Not all CBs are initialized which will cause a crash when dtor is called"); + VERIFY(texSrv == GetNumTexSRVs(), "Not all Tex SRVs are initialized which will cause a crash when dtor is called"); + VERIFY(texUav == GetNumTexUAVs(), "Not all Tex UAVs are initialized which will cause a crash when dtor is called"); + VERIFY(bufSrv == GetNumBufSRVs(), "Not all Buf SRVs are initialized which will cause a crash when dtor is called"); + VERIFY(bufUav == GetNumBufUAVs(), "Not all Buf UAVs are initialized which will cause a crash when dtor is called"); + VERIFY(sam == GetNumSamplers(), "Not all samplers are initialized which will cause a crash when dtor is called"); // Shader resource cache in the SRB is initialized by the constructor of ShaderResourceBindingD3D11Impl to // hold all variable types. The corresponding layout in the SRB is initialized to keep mutable and dynamic @@ -467,7 +471,7 @@ void ShaderResourceLayoutD3D11::TexSRVBindInfo::BindResource(IDeviceObject* pVie if (ValidSamplerAssigned()) { - auto& Sampler = m_ParentResLayout.GetSampler(SamplerIndex); + auto& Sampler = m_ParentResLayout.GetResource(SamplerIndex); VERIFY(!Sampler.Attribs.IsStaticSampler(), "Static samplers are not assigned to texture SRVs as they are initialized directly in the shader resource cache"); VERIFY_EXPR(Sampler.Attribs.BindCount == Attribs.BindCount || Sampler.Attribs.BindCount == 1); auto SamplerBindPoint = Sampler.Attribs.BindPoint + (Sampler.Attribs.BindCount != 1 ? ArrayIndex : 0); @@ -771,34 +775,87 @@ void ShaderResourceLayoutD3D11::BindResources( IResourceMapping* pResourceMappin ); } +template +IShaderVariable* ShaderResourceLayoutD3D11::GetResourceByName( const Char* Name ) +{ + auto NumResources = GetNumResources(); + for (Uint32 res = 0; res < NumResources; ++res) + { + auto& Resource = GetResource(res); + if (strcmp(Resource.Attribs.Name, Name) == 0) + return &Resource; + } + + return nullptr; +} + IShaderVariable* ShaderResourceLayoutD3D11::GetShaderVariable(const Char* Name) { - for (Uint32 cb = 0; cb < m_NumCBs; ++cb) - if (strcmp(GetCB(cb).Attribs.Name, Name) == 0) - return &GetCB(cb); - for (Uint32 t = 0; t < m_NumTexSRVs; ++t) - if (strcmp(GetTexSRV(t).Attribs.Name, Name) == 0 ) - return &GetTexSRV(t); - for (Uint32 u = 0; u < m_NumTexUAVs; ++u) - if (strcmp(GetTexUAV(u).Attribs.Name, Name) == 0 ) - return &GetTexUAV(u); - for (Uint32 s = 0; s < m_NumBufSRVs; ++s) - if (strcmp(GetBufSRV(s).Attribs.Name, Name) == 0 ) - return &GetBufSRV(s); - for (Uint32 u = 0; u < m_NumBufUAVs; ++u) - if (strcmp(GetBufUAV(u).Attribs.Name, Name) == 0 ) - return &GetBufUAV(u); - + if(auto* pCB = GetResourceByName(Name)) + return pCB; + + if(auto* pTexSRV = GetResourceByName(Name)) + return pTexSRV; + + if(auto* pTexUAV = GetResourceByName(Name)) + return pTexUAV; + + if(auto* pBuffSRV = GetResourceByName(Name)) + return pBuffSRV; + + if(auto* pBuffUAV = GetResourceByName(Name)) + return pBuffUAV; + if (!m_pResources->IsUsingCombinedTextureSamplers()) { - for (Uint32 s = 0; s < m_NumSamplers; ++s) - if (strcmp(GetSampler(s).Attribs.Name, Name) == 0 ) - return &GetSampler(s); + if(auto* pSampler = GetResourceByName(Name)) + return pSampler; } return nullptr; } +class ShaderVariableIndexLocator +{ +public: + ShaderVariableIndexLocator(const ShaderResourceLayoutD3D11& _Layout, const ShaderResourceLayoutD3D11::ShaderVariableD3D11Base& Variable) : + Layout (_Layout), + VarOffset(reinterpret_cast(&Variable) - reinterpret_cast(_Layout.m_ResourceBuffer.get())) + {} + + template + bool TryResource(ShaderResourceLayoutD3D11::OffsetType NextResourceTypeOffset) + { +#ifdef _DEBUG + VERIFY(Layout.GetResourceOffset() >= dbgPreviousResourceOffset, "Resource types are processed out of order!"); + dbgPreviousResourceOffset = Layout.GetResourceOffset(); + VERIFY_EXPR(NextResourceTypeOffset >= Layout.GetResourceOffset()); +#endif + if (VarOffset < NextResourceTypeOffset) + { + auto RelativeOffset = VarOffset - Layout.GetResourceOffset(); + DEV_CHECK_ERR( RelativeOffset % sizeof(ResourceType) == 0, "Offset is not multiple of resource type (", sizeof(ResourceType), ")"); + Index += static_cast(RelativeOffset / sizeof(ResourceType)); + return true; + } + else + { + Index += Layout.GetNumResources(); + return false; + } + } + + Uint32 GetIndex() const {return Index;} + +private: + const ShaderResourceLayoutD3D11& Layout; + const size_t VarOffset; + Uint32 Index = 0; +#ifdef _DEBUG + Uint32 dbgPreviousResourceOffset = 0; +#endif +}; + Uint32 ShaderResourceLayoutD3D11::GetVariableIndex(const ShaderVariableD3D11Base& Variable)const { if (!m_ResourceBuffer) @@ -806,105 +863,94 @@ Uint32 ShaderResourceLayoutD3D11::GetVariableIndex(const ShaderVariableD3D11Base LOG_ERROR("This shader resource layout does not have resources"); return static_cast(-1); } + + ShaderVariableIndexLocator IdxLocator(*this, Variable); + if (IdxLocator.TryResource(m_TexSRVsOffset)) + return IdxLocator.GetIndex(); - auto Offset = reinterpret_cast(&Variable) - reinterpret_cast(m_ResourceBuffer.get()); - Uint32 Index = 0; - if (Offset < m_TexSRVsOffset) - { - DEV_CHECK_ERR(Offset % sizeof(ConstBuffBindInfo) == 0, "Offset is not multiple of sizeof(ConstBuffBindInfo)"); - return Index + static_cast(Offset / sizeof(ConstBuffBindInfo)); - } - else - Index += m_NumCBs; + if (IdxLocator.TryResource(m_TexUAVsOffset)) + return IdxLocator.GetIndex(); - if (Offset < m_TexUAVsOffset) - { - DEV_CHECK_ERR( (Offset - m_TexSRVsOffset) % sizeof(TexSRVBindInfo) == 0, "Offset is not multiple of sizeof(TexSRVBindInfo)"); - return Index + static_cast((Offset - m_TexSRVsOffset) / sizeof(TexSRVBindInfo)); - } - else - Index += m_NumTexSRVs; + if (IdxLocator.TryResource(m_BuffSRVsOffset)) + return IdxLocator.GetIndex(); - if (Offset < m_BuffUAVsOffset) - { - DEV_CHECK_ERR( (Offset - m_TexUAVsOffset) % sizeof(TexUAVBindInfo) == 0, "Offset is not multiple of sizeof(TexUAVBindInfo)"); - return Index + static_cast((Offset - m_TexUAVsOffset) / sizeof(TexUAVBindInfo)); - } - else - Index += m_NumTexUAVs; + if (IdxLocator.TryResource(m_BuffUAVsOffset)) + return IdxLocator.GetIndex(); - if (Offset < m_BuffSRVsOffset) - { - DEV_CHECK_ERR( (Offset - m_BuffUAVsOffset) % sizeof(BuffUAVBindInfo) == 0, "Offset is not multiple of sizeof(BuffUAVBindInfo)" ); - return Index + static_cast((Offset - m_BuffUAVsOffset) / sizeof(BuffUAVBindInfo)); - } - else - Index += m_NumBufUAVs; + if (IdxLocator.TryResource(m_SamplerOffset)) + return IdxLocator.GetIndex(); - if (Offset < static_cast(m_BuffSRVsOffset + m_NumBufSRVs * sizeof(BuffSRVBindInfo))) + if (!m_pResources->IsUsingCombinedTextureSamplers()) { - DEV_CHECK_ERR( (Offset - m_BuffSRVsOffset) % sizeof(BuffSRVBindInfo) == 0, "Offset is not multiple of sizeof(BuffSRVBindInfo)" ); - return Index + static_cast((Offset - m_BuffSRVsOffset) / sizeof(BuffSRVBindInfo)); + if (IdxLocator.TryResource(m_MemorySize)) + return IdxLocator.GetIndex(); } - else - Index += m_NumBufSRVs; - if (!m_pResources->IsUsingCombinedTextureSamplers() && - Offset < static_cast(m_SamplerOffset + m_NumSamplers * sizeof(SamplerBindInfo))) + LOG_ERROR("Failed to get variable index. The variable ", &Variable, " does not belong to this shader resource layout"); + return static_cast(-1); +} + +class ShaderVariableLocator +{ +public: + ShaderVariableLocator(ShaderResourceLayoutD3D11& _Layout, Uint32 _Index) : + Layout(_Layout), + Index (_Index) { - DEV_CHECK_ERR( (Offset - m_SamplerOffset) % sizeof(SamplerBindInfo) == 0, "Offset is not multiple of sizeof(SamplerBindInfo)" ); - return Index + static_cast((Offset - m_SamplerOffset) / sizeof(SamplerBindInfo)); } - else + + template + IShaderVariable* TryResource() { - LOG_ERROR("Failed to get variable index. The variable ", &Variable, " does not belong to this shader resource layout"); - return static_cast(-1); +#ifdef _DEBUG + VERIFY(Layout.GetResourceOffset() >= dbgPreviousResourceOffset, "Resource types are processed out of order!"); + dbgPreviousResourceOffset = Layout.GetResourceOffset(); +#endif + auto NumResources = Layout.GetNumResources(); + if (Index < NumResources) + return &Layout.GetResource(Index); + else + { + Index -= NumResources; + return nullptr; + } } -} + +private: + ShaderResourceLayoutD3D11& Layout; + Uint32 Index; +#ifdef _DEBUG + Uint32 dbgPreviousResourceOffset = 0; +#endif +}; IShaderVariable* ShaderResourceLayoutD3D11::GetShaderVariable( Uint32 Index ) { - if (Index >= GetTotalResourceCount()) - { - LOG_ERROR("Invalid resource index ", Index); - return nullptr; - } + ShaderVariableLocator VarLocator(*this, Index); - if (Index < m_NumCBs) - return &GetCB(Index); - else - Index -= m_NumCBs; + if(auto* pCB = VarLocator.TryResource()) + return pCB; - if (Index < m_NumTexSRVs) - return &GetTexSRV(Index); - else - Index -= m_NumTexSRVs; - - if (Index < m_NumTexUAVs) - return &GetTexUAV(Index); - else - Index -= m_NumTexUAVs; + if(auto* pTexSRV = VarLocator.TryResource()) + return pTexSRV; - if (Index < m_NumBufUAVs) - return &GetBufUAV(Index); - else - Index -= m_NumBufUAVs; + if(auto* pTexUAV = VarLocator.TryResource()) + return pTexUAV; + + if(auto* pBuffSRV = VarLocator.TryResource()) + return pBuffSRV; + + if(auto* pBuffUAV = VarLocator.TryResource()) + return pBuffUAV; - if (Index < m_NumBufSRVs) - return &GetBufSRV(Index); - else - Index -= m_NumBufSRVs; - if (!m_pResources->IsUsingCombinedTextureSamplers()) { - if (Index < m_NumSamplers) - return &GetSampler(Index); - else - Index -= m_NumSamplers; + if(auto* pSampler = VarLocator.TryResource()) + return pSampler; } - + auto TotalResCount = GetTotalResourceCount(); - LOG_ERROR(Index + TotalResCount, " is not a valid variable index. Maximum allowed index: ", TotalResCount); + LOG_ERROR(Index, " is not a valid variable index. Total resource count: ", TotalResCount); return nullptr; } @@ -944,7 +990,7 @@ do{ \ if (ts.ValidSamplerAssigned()) { - const auto& Sampler = GetSampler(ts.SamplerIndex); + const auto& Sampler = GetConstResource(ts.SamplerIndex); VERIFY_EXPR(Sampler.Attribs.BindCount == ts.Attribs.BindCount || Sampler.Attribs.BindCount == 1); // Verify that if single sampler is used for all texture array elements, all samplers set in the resource views are consistent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp index 8d167663..c1f29af4 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp @@ -271,7 +271,11 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device* if (strcmp(Sampler.Attribs.Name, SamplerAttribs.Name) == 0) break; } - VERIFY(SamplerId < SamplerCount, "Unable to find assigned sampler"); + if (SamplerId == SamplerCount) + { + LOG_ERROR("Unable to find sampler '", SamplerAttribs.Name, "' assigned to texture SRV '", TexSRV.Name, "' in the list of already created resources. This seems to be a bug."); + SamplerId = D3D12Resource::InvalidSamplerId; + } VERIFY(SamplerId <= D3D12Resource::MaxSamplerId, "Sampler index excceeds allowed limit"); } } diff --git a/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.h b/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.h index c053d39e..346917ea 100644 --- a/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.h +++ b/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.h @@ -35,6 +35,16 @@ namespace Diligent { + struct D3DShaderResourceCounters + { + Uint32 NumCBs = 0; + Uint32 NumTexSRVs = 0; + Uint32 NumTexUAVs = 0; + Uint32 NumBufSRVs = 0; + Uint32 NumBufUAVs = 0; + Uint32 NumSamplers = 0; + }; + template > TexSRVInds( STD_ALLOCATOR_RAW_MEM(size_t, GetRawAllocator(), "Allocator for vector") ); - TexSRVInds.reserve(NumTexSRVs); + TexSRVInds.reserve(RC.NumTexSRVs); for(size_t ResInd = 0; ResInd < Resources.size(); ++ResInd) { diff --git a/Graphics/GraphicsEngineD3DBase/include/ShaderResources.h b/Graphics/GraphicsEngineD3DBase/include/ShaderResources.h index ec016324..b13e5e18 100644 --- a/Graphics/GraphicsEngineD3DBase/include/ShaderResources.h +++ b/Graphics/GraphicsEngineD3DBase/include/ShaderResources.h @@ -316,15 +316,8 @@ public: const D3DShaderResourceAttribs& GetBufUAV (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumBufUAV(), m_BufUAVOffset); } const D3DShaderResourceAttribs& GetSampler(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSamplers(), m_SamplersOffset); } - - void CountResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumCBs, - Uint32& NumTexSRVs, - Uint32& NumTexUAVs, - Uint32& NumBufSRVs, - Uint32& NumBufUAVs, - Uint32& NumSamplers)const noexcept; + D3DShaderResourceCounters CountResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes)const noexcept; SHADER_TYPE GetShaderType()const noexcept{return m_ShaderType;} @@ -428,14 +421,9 @@ protected: D3DShaderResourceAttribs& GetSampler(Uint32 n)noexcept{ return GetResAttribs(n, GetNumSamplers(), m_SamplersOffset); } private: - void AllocateMemory(IMemoryAllocator& Allocator, - Uint32 NumCBs, - Uint32 NumTexSRVs, - Uint32 NumTexUAVs, - Uint32 NumBufSRVs, - Uint32 NumBufUAVs, - Uint32 NumSamplers, - size_t ResourceNamesPoolSize); + void AllocateMemory(IMemoryAllocator& Allocator, + const D3DShaderResourceCounters& ResCounters, + size_t ResourceNamesPoolSize); Uint32 FindAssignedSamplerId(const D3DShaderResourceAttribs& TexSRV, const char* SamplerSuffix)const; @@ -472,12 +460,12 @@ void ShaderResources::Initialize(ID3DBlob* pShaderByteCode, LoadD3DShaderResources( pShaderByteCode, - [&](Uint32 NumCBs, Uint32 NumTexSRVs, Uint32 NumTexUAVs, Uint32 NumBufSRVs, Uint32 NumBufUAVs, Uint32 NumSamplers, size_t ResourceNamesPoolSize) + [&](const D3DShaderResourceCounters& ResCounters, size_t ResourceNamesPoolSize) { if (CombinedSamplerSuffix != nullptr) ResourceNamesPoolSize += strlen(CombinedSamplerSuffix)+1; - AllocateMemory(GetRawAllocator(), NumCBs, NumTexSRVs, NumTexUAVs, NumBufSRVs, NumBufUAVs, NumSamplers, ResourceNamesPoolSize); + AllocateMemory(GetRawAllocator(), ResCounters, ResourceNamesPoolSize); }, [&](const D3DShaderResourceAttribs& CBAttribs) diff --git a/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp b/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp index 52527697..5b2b2d4e 100644 --- a/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp +++ b/Graphics/GraphicsEngineD3DBase/src/ShaderResources.cpp @@ -51,42 +51,36 @@ ShaderResources::~ShaderResources() GetSampler(n).~D3DShaderResourceAttribs(); } -void ShaderResources::AllocateMemory(IMemoryAllocator& Allocator, - Uint32 NumCBs, - Uint32 NumTexSRVs, - Uint32 NumTexUAVs, - Uint32 NumBufSRVs, - Uint32 NumBufUAVs, - Uint32 NumSamplers, - size_t ResourceNamesPoolSize) +void ShaderResources::AllocateMemory(IMemoryAllocator& Allocator, + const D3DShaderResourceCounters& ResCounters, + size_t ResourceNamesPoolSize) { - const auto MaxOffset = static_cast(std::numeric_limits::max()); - VERIFY(NumCBs <= MaxOffset, "Max offset exceeded"); - m_TexSRVOffset = 0 + static_cast(NumCBs); - - VERIFY(m_TexSRVOffset + NumTexSRVs <= MaxOffset, "Max offset exceeded"); - m_TexUAVOffset = m_TexSRVOffset + static_cast(NumTexSRVs); - - VERIFY(m_TexUAVOffset + NumTexUAVs <= MaxOffset, "Max offset exceeded"); - m_BufSRVOffset = m_TexUAVOffset + static_cast(NumTexUAVs); - - VERIFY(m_BufSRVOffset + NumBufSRVs <= MaxOffset, "Max offset exceeded"); - m_BufUAVOffset = m_BufSRVOffset + static_cast(NumBufSRVs); - - VERIFY(m_BufUAVOffset + NumBufUAVs <= MaxOffset, "Max offset exceeded"); - m_SamplersOffset = m_BufUAVOffset + static_cast(NumBufUAVs); - - VERIFY(m_SamplersOffset + NumSamplers<= MaxOffset, "Max offset exceeded"); - m_TotalResources = m_SamplersOffset + static_cast(NumSamplers); + Uint32 CurrentOffset = 0; + auto AdvanceOffset = [&CurrentOffset](Uint32 NumResources) + { + constexpr Uint32 MaxOffset = std::numeric_limits::max(); + VERIFY(CurrentOffset <= MaxOffset, "Current offser (", CurrentOffset, ") exceeds max allowed value (", MaxOffset, ")"); + auto Offset = static_cast(CurrentOffset); + CurrentOffset += NumResources; + return Offset; + }; + + auto CBOffset = AdvanceOffset(ResCounters.NumCBs); CBOffset; // To suppress warning + m_TexSRVOffset = AdvanceOffset(ResCounters.NumTexSRVs); + m_TexUAVOffset = AdvanceOffset(ResCounters.NumTexUAVs); + m_BufSRVOffset = AdvanceOffset(ResCounters.NumBufSRVs); + m_BufUAVOffset = AdvanceOffset(ResCounters.NumBufUAVs); + m_SamplersOffset = AdvanceOffset(ResCounters.NumSamplers); + m_TotalResources = AdvanceOffset(0); auto MemorySize = m_TotalResources * sizeof(D3DShaderResourceAttribs) + ResourceNamesPoolSize * sizeof(char); - VERIFY_EXPR(GetNumCBs() == NumCBs); - VERIFY_EXPR(GetNumTexSRV() == NumTexSRVs); - VERIFY_EXPR(GetNumTexUAV() == NumTexUAVs); - VERIFY_EXPR(GetNumBufSRV() == NumBufSRVs); - VERIFY_EXPR(GetNumBufUAV() == NumBufUAVs); - VERIFY_EXPR(GetNumSamplers()== NumSamplers); + VERIFY_EXPR(GetNumCBs() == ResCounters.NumCBs); + VERIFY_EXPR(GetNumTexSRV() == ResCounters.NumTexSRVs); + VERIFY_EXPR(GetNumTexUAV() == ResCounters.NumTexUAVs); + VERIFY_EXPR(GetNumBufSRV() == ResCounters.NumBufSRVs); + VERIFY_EXPR(GetNumBufUAV() == ResCounters.NumBufUAVs); + VERIFY_EXPR(GetNumSamplers()== ResCounters.NumSamplers); if( MemorySize ) { @@ -102,59 +96,50 @@ ShaderResources::ShaderResources(SHADER_TYPE ShaderType): { } -void ShaderResources::CountResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumCBs, - Uint32& NumTexSRVs, - Uint32& NumTexUAVs, - Uint32& NumBufSRVs, - Uint32& NumBufUAVs, - Uint32& NumSamplers)const noexcept +D3DShaderResourceCounters ShaderResources::CountResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes)const noexcept { auto AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - NumCBs = 0; - NumTexSRVs = 0; - NumTexUAVs = 0; - NumBufSRVs = 0; - NumBufUAVs = 0; - NumSamplers = 0; + D3DShaderResourceCounters Counters; ProcessResources( AllowedVarTypes, NumAllowedTypes, [&](const D3DShaderResourceAttribs& CB, Uint32) { VERIFY_EXPR(CB.IsAllowedType(AllowedTypeBits)); - ++NumCBs; + ++Counters.NumCBs; }, [&](const D3DShaderResourceAttribs& Sam, Uint32) { VERIFY_EXPR(Sam.IsAllowedType(AllowedTypeBits)); // Skip static samplers if (!Sam.IsStaticSampler()) - ++NumSamplers; + ++Counters.NumSamplers; }, [&](const D3DShaderResourceAttribs& TexSRV, Uint32) { VERIFY_EXPR(TexSRV.IsAllowedType(AllowedTypeBits)); - ++NumTexSRVs; + ++Counters.NumTexSRVs; }, [&](const D3DShaderResourceAttribs& TexUAV, Uint32) { VERIFY_EXPR(TexUAV.IsAllowedType(AllowedTypeBits)); - ++NumTexUAVs; + ++Counters.NumTexUAVs; }, [&](const D3DShaderResourceAttribs& BufSRV, Uint32) { VERIFY_EXPR(BufSRV.IsAllowedType(AllowedTypeBits)); - ++NumBufSRVs; + ++Counters.NumBufSRVs; }, [&](const D3DShaderResourceAttribs& BufUAV, Uint32) { VERIFY_EXPR(BufUAV.IsAllowedType(AllowedTypeBits)); - ++NumBufUAVs; + ++Counters.NumBufUAVs; } ); + + return Counters; } -- cgit v1.2.3 From 1332922262631fb8d601f8636ae783b73e461cad Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Thu, 25 Oct 2018 20:28:05 -0700 Subject: Implemented HLSL to SPIRV compilation and HLSL-style combined samplers in Vulkan --- Graphics/GLSLTools/CMakeLists.txt | 4 +- Graphics/GLSLTools/include/GLSL2SPIRV.h | 37 -- Graphics/GLSLTools/include/SPIRVShaderResources.h | 154 ++++--- Graphics/GLSLTools/include/SPIRVUtils.h | 38 ++ Graphics/GLSLTools/src/GLSL2SPIRV.cpp | 353 --------------- Graphics/GLSLTools/src/SPIRVShaderResources.cpp | 337 +++++++------- Graphics/GLSLTools/src/SPIRVUtils.cpp | 493 +++++++++++++++++++++ .../include/ShaderResourceLayoutVk.h | 28 +- .../src/ShaderResourceLayoutVk.cpp | 143 ++++-- Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp | 35 +- .../src/VulkanUtilities/VulkanInstance.cpp | 2 +- 11 files changed, 964 insertions(+), 660 deletions(-) delete mode 100644 Graphics/GLSLTools/include/GLSL2SPIRV.h create mode 100644 Graphics/GLSLTools/include/SPIRVUtils.h delete mode 100644 Graphics/GLSLTools/src/GLSL2SPIRV.cpp create mode 100644 Graphics/GLSLTools/src/SPIRVUtils.cpp (limited to 'Graphics') diff --git a/Graphics/GLSLTools/CMakeLists.txt b/Graphics/GLSLTools/CMakeLists.txt index 71ead9fb..dd4540a8 100644 --- a/Graphics/GLSLTools/CMakeLists.txt +++ b/Graphics/GLSLTools/CMakeLists.txt @@ -13,11 +13,11 @@ set(SOURCE if(VULKAN_SUPPORTED) list(APPEND SOURCE src/SPIRVShaderResources.cpp - src/GLSL2SPIRV.cpp + src/SPIRVUtils.cpp ) list(APPEND INCLUDE include/SPIRVShaderResources.h - include/GLSL2SPIRV.h + include/SPIRVUtils.h ) endif() diff --git a/Graphics/GLSLTools/include/GLSL2SPIRV.h b/Graphics/GLSLTools/include/GLSL2SPIRV.h deleted file mode 100644 index 5951af2c..00000000 --- a/Graphics/GLSLTools/include/GLSL2SPIRV.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#pragma once - -#include -#include "Shader.h" -#include "DataBlob.h" - -namespace Diligent -{ - -void InitializeGlslang(); -void FinalizeGlslang(); -std::vector GLSLtoSPIRV(const SHADER_TYPE ShaderType, const char* ShaderSource, IDataBlob** ppCompilerOutput); - -} \ No newline at end of file diff --git a/Graphics/GLSLTools/include/SPIRVShaderResources.h b/Graphics/GLSLTools/include/SPIRVShaderResources.h index 9f825c04..27764816 100644 --- a/Graphics/GLSLTools/include/SPIRVShaderResources.h +++ b/Graphics/GLSLTools/include/SPIRVShaderResources.h @@ -30,7 +30,7 @@ // // m_MemoryBuffer m_TotalResources // | | -// | Uniform Buffers | Storage Buffers | Storage Images | Sampled Images | Atomic Counters | Separate Images | Separate Samplers | Static Samplers | Resource Names | +// | Uniform Buffers | Storage Buffers | Storage Images | Sampled Images | Atomic Counters | Separate Samplers | Separate Images | Static Samplers | Resource Names | #include #include @@ -97,16 +97,33 @@ struct SPIRVShaderResourceAttribs const SHADER_VARIABLE_TYPE VarType : VarTypeBits; const Int8 StaticSamplerInd; + static constexpr const Uint32 InvalidSepSmplrOrImgInd = static_cast(-1); + // Used when HLSL shaders are compiled using combined texture samplers. + Uint32 SepSmplrOrImgInd = InvalidSepSmplrOrImgInd; + // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary const uint32_t BindingDecorationOffset; const uint32_t DescriptorSetDecorationOffset; + bool ValidSepSamplerAssigned() const + { + VERIFY_EXPR(Type == SeparateImage); + return SepSmplrOrImgInd != InvalidSepSmplrOrImgInd; + } + + bool ValidSepImageAssigned() const + { + VERIFY_EXPR(Type == SeparateSampler); + return SepSmplrOrImgInd != InvalidSepSmplrOrImgInd; + } + SPIRVShaderResourceAttribs(const spirv_cross::Compiler& Compiler, const spirv_cross::Resource& Res, const char* _Name, ResourceType _Type, SHADER_VARIABLE_TYPE _VarType, - Int32 _StaticSamplerInd)noexcept; + Int32 _StaticSamplerInd, + Uint32 _SamplerOrSepImgId = InvalidSepSmplrOrImgInd)noexcept; String GetPrintName(Uint32 ArrayInd)const { @@ -121,12 +138,13 @@ struct SPIRVShaderResourceAttribs return Name; } - bool IsCompatibleWith(const SPIRVShaderResourceAttribs& Attibs)const + bool IsCompatibleWith(const SPIRVShaderResourceAttribs& Attribs)const { - return ArraySize == Attibs.ArraySize && - Type == Attibs.Type && - VarType == Attibs.VarType && - (StaticSamplerInd < 0 && Attibs.StaticSamplerInd < 0 || StaticSamplerInd >= 0 && Attibs.StaticSamplerInd >= 0); + return ArraySize == Attribs.ArraySize && + Type == Attribs.Type && + VarType == Attribs.VarType && + SepSmplrOrImgInd == Attribs.SepSmplrOrImgInd && + (StaticSamplerInd < 0 && Attribs.StaticSamplerInd < 0 || StaticSamplerInd >= 0 && Attribs.StaticSamplerInd >= 0); } }; static_assert(sizeof(SPIRVShaderResourceAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderResourceAttribs struct must be multiple of sizeof(void*)" ); @@ -138,7 +156,8 @@ public: SPIRVShaderResources(IMemoryAllocator& Allocator, IRenderDevice* pRenderDevice, std::vector spirv_binary, - const ShaderDesc& shaderDesc); + const ShaderDesc& shaderDesc, + const char* CombinedSamplerSuffix); SPIRVShaderResources (const SPIRVShaderResources&) = delete; SPIRVShaderResources (SPIRVShaderResources&&) = delete; @@ -149,43 +168,48 @@ public: using SamplerPtrType = RefCntAutoPtr; - Uint32 GetNumUBs ()const noexcept{ return (m_StorageBufferOffset - 0); } - Uint32 GetNumSBs ()const noexcept{ return (m_StorageImageOffset - m_StorageBufferOffset); } - Uint32 GetNumImgs ()const noexcept{ return (m_SampledImageOffset - m_StorageImageOffset); } - Uint32 GetNumSmplImgs()const noexcept{ return (m_AtomicCounterOffset - m_SampledImageOffset); } - Uint32 GetNumACs ()const noexcept{ return (m_SeparateImageOffset - m_AtomicCounterOffset); } - Uint32 GetNumSepImgs ()const noexcept{ return (m_SeparateSamplerOffset - m_SeparateImageOffset); } - Uint32 GetNumSepSmpls()const noexcept{ return (m_TotalResources - m_SeparateSamplerOffset);} + Uint32 GetNumUBs ()const noexcept{ return (m_StorageBufferOffset - 0); } + Uint32 GetNumSBs ()const noexcept{ return (m_StorageImageOffset - m_StorageBufferOffset); } + Uint32 GetNumImgs ()const noexcept{ return (m_SampledImageOffset - m_StorageImageOffset); } + 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 GetTotalResources() const noexcept { return m_TotalResources; } Uint32 GetNumStaticSamplers()const noexcept { return m_NumStaticSamplers; } - const SPIRVShaderResourceAttribs& GetUB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } - const SPIRVShaderResourceAttribs& GetSB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } - const SPIRVShaderResourceAttribs& GetImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } - const SPIRVShaderResourceAttribs& GetSmplImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSmplImgs(), m_SampledImageOffset ); } - const SPIRVShaderResourceAttribs& GetAC (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } - const SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } - const SPIRVShaderResourceAttribs& GetSepSmpl (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepSmpls(), m_SeparateSamplerOffset); } - const SPIRVShaderResourceAttribs& GetResource(Uint32 n)const noexcept{ return GetResAttribs(n, GetTotalResources(), 0); } + const SPIRVShaderResourceAttribs& GetUB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } + const SPIRVShaderResourceAttribs& GetSB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } + const SPIRVShaderResourceAttribs& GetImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } + const SPIRVShaderResourceAttribs& GetSmpldImg(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } + 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& GetResource(Uint32 n)const noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } + ISampler* GetStaticSampler(const SPIRVShaderResourceAttribs& ResAttribs)const noexcept { if(ResAttribs.StaticSamplerInd < 0) return nullptr; + VERIFY_EXPR(ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); VERIFY(ResAttribs.StaticSamplerInd < m_NumStaticSamplers, "Static sampler index (", ResAttribs.StaticSamplerInd, ") is out of range. Array size: ", m_NumStaticSamplers); auto *ResourceMemoryEnd = reinterpret_cast(m_MemoryBuffer.get()) + m_TotalResources; return reinterpret_cast(ResourceMemoryEnd)[ResAttribs.StaticSamplerInd]; } - void CountResources(const SHADER_VARIABLE_TYPE *AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumUBs, - Uint32& NumSBs, - Uint32& NumImgs, - Uint32& NumSmplImgs, - Uint32& NumACs, - Uint32& NumSepImgs, - Uint32& NumSepSmpls)const noexcept; + struct ResourceCounters + { + Uint32 NumUBs = 0; + Uint32 NumSBs = 0; + Uint32 NumImgs = 0; + Uint32 NumSmpldImgs = 0; + Uint32 NumACs = 0; + Uint32 NumSepSmplrs = 0; + Uint32 NumSepImgs = 0; + }; + ResourceCounters CountResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes)const noexcept; SHADER_TYPE GetShaderType()const noexcept{return m_ShaderType;} @@ -195,8 +219,8 @@ public: typename THandleImg, typename THandleSmplImg, typename THandleAC, - typename THandleSepImg, - typename THandleSepSmpl> + typename THandleSepSmpl, + typename THandleSepImg> void ProcessResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, Uint32 NumAllowedTypes, THandleUB HandleUB, @@ -204,8 +228,8 @@ public: THandleImg HandleImg, THandleSmplImg HandleSmplImg, THandleAC HandleAC, - THandleSepImg HandleSepImg, - THandleSepSmpl HandleSepSmpl)const + THandleSepSmpl HandleSepSmpl, + THandleSepImg HandleSepImg)const { Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); @@ -230,9 +254,9 @@ public: HandleImg(Img, n); } - for (Uint32 n = 0; n < GetNumSmplImgs(); ++n) + for (Uint32 n = 0; n < GetNumSmpldImgs(); ++n) { - const auto& SmplImg = GetSmplImg(n); + const auto& SmplImg = GetSmpldImg(n); if (IsAllowedType(SmplImg.VarType, AllowedTypeBits)) HandleSmplImg(SmplImg, n); } @@ -244,19 +268,19 @@ public: HandleAC(AC, n); } + for (Uint32 n = 0; n < GetNumSepSmplrs(); ++n) + { + const auto& SepSmpl = GetSepSmplr(n); + if (IsAllowedType(SepSmpl.VarType, AllowedTypeBits)) + HandleSepSmpl(SepSmpl, n); + } + for (Uint32 n = 0; n < GetNumSepImgs(); ++n) { const auto& SepImg = GetSepImg(n); if (IsAllowedType(SepImg.VarType, AllowedTypeBits)) HandleSepImg(SepImg, n); } - - for (Uint32 n = 0; n < GetNumSepSmpls(); ++n) - { - const auto& SepSmpl = GetSepSmpl(n); - if (IsAllowedType(SepSmpl.VarType, AllowedTypeBits)) - HandleSepSmpl(SepSmpl, n); - } } template @@ -280,17 +304,14 @@ public: //size_t GetHash()const; + const char* GetCombinedSamplerSuffix() const { return m_CombinedSamplerSuffix; } + bool IsUsingCombinedSamplers() const { return m_CombinedSamplerSuffix != nullptr; } + protected: - void Initialize(IMemoryAllocator& Allocator, - Uint32 NumUBs, - Uint32 NumSBs, - Uint32 NumImgs, - Uint32 NumSmplImgs, - Uint32 NumACs, - Uint32 NumSepImgs, - Uint32 NumSepSmpls, - Uint32 NumStaticSamplers, - size_t ResourceNamesPoolSize); + void Initialize(IMemoryAllocator& Allocator, + const ResourceCounters& Counters, + Uint32 NumStaticSamplers, + size_t ResourceNamesPoolSize); __forceinline SPIRVShaderResourceAttribs& GetResAttribs(Uint32 n, Uint32 NumResources, Uint32 Offset)noexcept { @@ -306,14 +327,15 @@ protected: return reinterpret_cast(m_MemoryBuffer.get())[Offset + n]; } - SPIRVShaderResourceAttribs& GetUB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } - SPIRVShaderResourceAttribs& GetSB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } - SPIRVShaderResourceAttribs& GetImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } - SPIRVShaderResourceAttribs& GetSmplImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSmplImgs(), m_SampledImageOffset ); } - SPIRVShaderResourceAttribs& GetAC (Uint32 n)noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } - SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } - SPIRVShaderResourceAttribs& GetSepSmpl (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepSmpls(), m_SeparateSamplerOffset); } - SPIRVShaderResourceAttribs& GetResource(Uint32 n)noexcept{ return GetResAttribs(n, GetTotalResources(), 0); } + SPIRVShaderResourceAttribs& GetUB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } + SPIRVShaderResourceAttribs& GetSB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } + SPIRVShaderResourceAttribs& GetImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } + SPIRVShaderResourceAttribs& GetSmpldImg(Uint32 n)noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } + 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& GetResource(Uint32 n)noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } + SamplerPtrType& GetStaticSampler(Uint32 n)noexcept { VERIFY(n < m_NumStaticSamplers, "Static sampler index (", n, ") is out of range. Array size: ", m_NumStaticSamplers); @@ -323,17 +345,19 @@ protected: private: // Memory buffer that holds all resources as continuous chunk of memory: - // | UBs | SBs | StrgImgs | SmplImgs | ACs | SepImgs | SepSamplers | Static Samplers | Resource Names | + // | UBs | SBs | StrgImgs | SmplImgs | ACs | SepSamplers | SepImgs | Static Samplers | Resource Names | std::unique_ptr< void, STDDeleterRawMem > m_MemoryBuffer; StringPool m_ResourceNames; + const char* m_CombinedSamplerSuffix = nullptr; + using OffsetType = Uint16; OffsetType m_StorageBufferOffset = 0; OffsetType m_StorageImageOffset = 0; OffsetType m_SampledImageOffset = 0; OffsetType m_AtomicCounterOffset = 0; - OffsetType m_SeparateImageOffset = 0; OffsetType m_SeparateSamplerOffset = 0; + OffsetType m_SeparateImageOffset = 0; OffsetType m_TotalResources = 0; OffsetType m_NumStaticSamplers = 0; diff --git a/Graphics/GLSLTools/include/SPIRVUtils.h b/Graphics/GLSLTools/include/SPIRVUtils.h new file mode 100644 index 00000000..47c33242 --- /dev/null +++ b/Graphics/GLSLTools/include/SPIRVUtils.h @@ -0,0 +1,38 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include +#include "Shader.h" +#include "DataBlob.h" + +namespace Diligent +{ + +void InitializeGlslang(); +void FinalizeGlslang(); +std::vector GLSLtoSPIRV(SHADER_TYPE ShaderType, const char* ShaderSource, int SourceCodeLen, IDataBlob** ppCompilerOutput); +std::vector HLSLtoSPIRV(const ShaderCreationAttribs& Attribs, IDataBlob** ppCompilerOutput); + +} \ No newline at end of file diff --git a/Graphics/GLSLTools/src/GLSL2SPIRV.cpp b/Graphics/GLSLTools/src/GLSL2SPIRV.cpp deleted file mode 100644 index 5ee3d685..00000000 --- a/Graphics/GLSLTools/src/GLSL2SPIRV.cpp +++ /dev/null @@ -1,353 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#if PLATFORM_ANDROID - // Android specific include files. -# include - - // Header files. -# include -# include "shaderc/shaderc.hpp" - // Static variable that keeps ANativeWindow and asset manager instances. - //static android_app *Android_application = nullptr; -#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) -# include -#else -# include "SPIRV/GlslangToSpv.h" -#endif - -#include "GLSL2SPIRV.h" -#include "DebugUtilities.h" -#include "DataBlobImpl.h" - -namespace Diligent -{ - -void InitializeGlslang() -{ -#if !PLATFORM_ANDROID - glslang::InitializeProcess(); -#endif -} - -void FinalizeGlslang() -{ -#if !PLATFORM_ANDROID - glslang::FinalizeProcess(); -#endif -} - -EShLanguage ShaderTypeToShLanguage(SHADER_TYPE ShaderType) -{ - switch(ShaderType) - { - case SHADER_TYPE_VERTEX: return EShLangVertex; - case SHADER_TYPE_HULL: return EShLangTessControl; - case SHADER_TYPE_DOMAIN: return EShLangTessEvaluation; - case SHADER_TYPE_GEOMETRY: return EShLangGeometry; - case SHADER_TYPE_PIXEL: return EShLangFragment; - case SHADER_TYPE_COMPUTE: return EShLangCompute; - - default: - UNEXPECTED("Unexpected shader type"); - return EShLangCount; - } -} - -TBuiltInResource InitResources() -{ - TBuiltInResource Resources; - - Resources.maxLights = 32; - Resources.maxClipPlanes = 6; - Resources.maxTextureUnits = 32; - Resources.maxTextureCoords = 32; - Resources.maxVertexAttribs = 64; - Resources.maxVertexUniformComponents = 4096; - Resources.maxVaryingFloats = 64; - Resources.maxVertexTextureImageUnits = 32; - Resources.maxCombinedTextureImageUnits = 80; - Resources.maxTextureImageUnits = 32; - Resources.maxFragmentUniformComponents = 4096; - Resources.maxDrawBuffers = 32; - Resources.maxVertexUniformVectors = 128; - Resources.maxVaryingVectors = 8; - Resources.maxFragmentUniformVectors = 16; - Resources.maxVertexOutputVectors = 16; - Resources.maxFragmentInputVectors = 15; - Resources.minProgramTexelOffset = -8; - Resources.maxProgramTexelOffset = 7; - Resources.maxClipDistances = 8; - Resources.maxComputeWorkGroupCountX = 65535; - Resources.maxComputeWorkGroupCountY = 65535; - Resources.maxComputeWorkGroupCountZ = 65535; - Resources.maxComputeWorkGroupSizeX = 1024; - Resources.maxComputeWorkGroupSizeY = 1024; - Resources.maxComputeWorkGroupSizeZ = 64; - Resources.maxComputeUniformComponents = 1024; - Resources.maxComputeTextureImageUnits = 16; - Resources.maxComputeImageUniforms = 8; - Resources.maxComputeAtomicCounters = 8; - Resources.maxComputeAtomicCounterBuffers = 1; - Resources.maxVaryingComponents = 60; - Resources.maxVertexOutputComponents = 64; - Resources.maxGeometryInputComponents = 64; - Resources.maxGeometryOutputComponents = 128; - Resources.maxFragmentInputComponents = 128; - Resources.maxImageUnits = 8; - Resources.maxCombinedImageUnitsAndFragmentOutputs = 8; - Resources.maxCombinedShaderOutputResources = 8; - Resources.maxImageSamples = 0; - Resources.maxVertexImageUniforms = 0; - Resources.maxTessControlImageUniforms = 0; - Resources.maxTessEvaluationImageUniforms = 0; - Resources.maxGeometryImageUniforms = 0; - Resources.maxFragmentImageUniforms = 8; - Resources.maxCombinedImageUniforms = 8; - Resources.maxGeometryTextureImageUnits = 16; - Resources.maxGeometryOutputVertices = 256; - Resources.maxGeometryTotalOutputComponents = 1024; - Resources.maxGeometryUniformComponents = 1024; - Resources.maxGeometryVaryingComponents = 64; - Resources.maxTessControlInputComponents = 128; - Resources.maxTessControlOutputComponents = 128; - Resources.maxTessControlTextureImageUnits = 16; - Resources.maxTessControlUniformComponents = 1024; - Resources.maxTessControlTotalOutputComponents = 4096; - Resources.maxTessEvaluationInputComponents = 128; - Resources.maxTessEvaluationOutputComponents = 128; - Resources.maxTessEvaluationTextureImageUnits = 16; - Resources.maxTessEvaluationUniformComponents = 1024; - Resources.maxTessPatchComponents = 120; - Resources.maxPatchVertices = 32; - Resources.maxTessGenLevel = 64; - Resources.maxViewports = 16; - Resources.maxVertexAtomicCounters = 0; - Resources.maxTessControlAtomicCounters = 0; - Resources.maxTessEvaluationAtomicCounters = 0; - Resources.maxGeometryAtomicCounters = 0; - Resources.maxFragmentAtomicCounters = 8; - Resources.maxCombinedAtomicCounters = 8; - Resources.maxAtomicCounterBindings = 1; - Resources.maxVertexAtomicCounterBuffers = 0; - Resources.maxTessControlAtomicCounterBuffers = 0; - Resources.maxTessEvaluationAtomicCounterBuffers = 0; - Resources.maxGeometryAtomicCounterBuffers = 0; - Resources.maxFragmentAtomicCounterBuffers = 1; - Resources.maxCombinedAtomicCounterBuffers = 1; - Resources.maxAtomicCounterBufferSize = 16384; - Resources.maxTransformFeedbackBuffers = 4; - Resources.maxTransformFeedbackInterleavedComponents = 64; - Resources.maxCullDistances = 8; - Resources.maxCombinedClipAndCullDistances = 8; - Resources.maxSamples = 4; - Resources.limits.nonInductiveForLoops = 1; - Resources.limits.whileLoops = 1; - Resources.limits.doWhileLoops = 1; - Resources.limits.generalUniformIndexing = 1; - Resources.limits.generalAttributeMatrixVectorIndexing = 1; - Resources.limits.generalVaryingIndexing = 1; - Resources.limits.generalSamplerIndexing = 1; - Resources.limits.generalVariableIndexing = 1; - Resources.limits.generalConstantMatrixVectorIndexing = 1; - - return Resources; -} - -class IoMapResolver : public glslang::TIoMapResolver -{ -public: - // Should return true if the resulting/current binding would be okay. - // Basic idea is to do aliasing binding checks with this. - virtual bool validateBinding(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - return true; - } - - // Should return a value >= 0 if the current binding should be overridden. - // Return -1 if the current binding (including no binding) should be kept. - virtual int resolveBinding(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - // We do not care about actual binding value here. - // We only need decoration to be present in SPIRV - return 0; - } - - // Should return a value >= 0 if the current set should be overridden. - // Return -1 if the current set (including no set) should be kept. - virtual int resolveSet(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - // We do not care about actual descriptor set value here. - // We only need decoration to be present in SPIRV - return 0; - } - - // Should return a value >= 0 if the current location should be overridden. - // Return -1 if the current location (including no location) should be kept. - virtual int resolveUniformLocation(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - return -1; - } - - // Should return true if the resulting/current setup would be okay. - // Basic idea is to do aliasing checks and reject invalid semantic names. - virtual bool validateInOut(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - return true; - } - - // Should return a value >= 0 if the current location should be overridden. - // Return -1 if the current location (including no location) should be kept. - virtual int resolveInOutLocation(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - return -1; - } - - // Should return a value >= 0 if the current component index should be overridden. - // Return -1 if the current component index (including no index) should be kept. - virtual int resolveInOutComponent(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - return -1; - } - - // Should return a value >= 0 if the current color index should be overridden. - // Return -1 if the current color index (including no index) should be kept. - virtual int resolveInOutIndex(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - return -1; - } - - // Notification of a uniform variable - virtual void notifyBinding(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - } - - // Notification of a in or out variable - virtual void notifyInOut(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) - { - } - - // Called by mapIO when it has finished the notify pass - virtual void endNotifications(EShLanguage stage) - { - } - - // Called by mapIO when it starts its notify pass for the given stage - virtual void beginNotifications(EShLanguage stage) - { - } - - // Called by mipIO when it starts its resolve pass for the given stage - virtual void beginResolve(EShLanguage stage) - { - } - - // Called by mapIO when it has finished the resolve pass - virtual void endResolve(EShLanguage stage) - { - } -}; - -static void InitializeCompilerOutputBlob(const char* ShaderSource, const std::string& ErrorLog, IDataBlob** ppCompilerOutput) -{ - VERIFY_EXPR(ppCompilerOutput != nullptr); - auto SourceLen = strlen(ShaderSource); - auto* pOutputDataBlob = MakeNewRCObj()(SourceLen + 1 + ErrorLog.length() + 1); - char* DataPtr = reinterpret_cast(pOutputDataBlob->GetDataPtr()); - memcpy(DataPtr, ErrorLog.data(), ErrorLog.length() + 1); - memcpy(DataPtr + ErrorLog.length() + 1, ShaderSource, SourceLen + 1); - pOutputDataBlob->QueryInterface(IID_DataBlob, reinterpret_cast(ppCompilerOutput)); -} - -std::vector GLSLtoSPIRV(const SHADER_TYPE ShaderType, const char* ShaderSource, IDataBlob** ppCompilerOutput) -{ -#if PLATFORM_ANDROID - - // On Android, use shaderc instead. - shaderc::Compiler compiler; - shaderc::SpvCompilationResult module = - compiler.CompileGlslToSpv(pshader, strlen(pshader), MapShadercType(shader_type), "shader"); - if (module.GetCompilationStatus() != shaderc_compilation_status_success) { - LOGE("Error: Id=%d, Msg=%s", module.GetCompilationStatus(), module.GetErrorMessage().c_str()); - return false; - } - std::vector spirv; - spirv.assign(module.cbegin(), module.cend()); - -#else - - EShLanguage ShLang = ShaderTypeToShLanguage(ShaderType); - glslang::TShader Shader(ShLang); - TBuiltInResource Resources = InitResources(); - - // Enable SPIR-V and Vulkan rules when parsing GLSL - EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); - - const char* ShaderStrings[] = { ShaderSource }; - Shader.setStrings(ShaderStrings, 1); - - Shader.setAutoMapBindings(true); - if (!Shader.parse(&Resources, 100, false, messages)) - { - std::string Log(Shader.getInfoLog()); - if(*Shader.getInfoDebugLog() != '\0') - { - Log.push_back('\n'); - Log.append(Shader.getInfoDebugLog()); - } - LOG_ERROR_MESSAGE("Failed to parse shader source: \n", Log); - if(ppCompilerOutput != nullptr) - InitializeCompilerOutputBlob(ShaderSource, Log, ppCompilerOutput); - - return {}; - } - - glslang::TProgram Program; - Program.addShader(&Shader); - if (!Program.link(messages)) - { - std::string Log(Shader.getInfoLog()); - if(*Shader.getInfoDebugLog() != '\0') - { - Log.push_back('\n'); - Log.append(Shader.getInfoDebugLog()); - } - LOG_ERROR_MESSAGE("Failed to link program: \n", Log); - if(ppCompilerOutput != nullptr) - InitializeCompilerOutputBlob(ShaderSource, Log, ppCompilerOutput); - - return {}; - } - - IoMapResolver Resovler; - // This step is essential to set bindings and descriptor sets - Program.mapIO(&Resovler); - - std::vector spirv; - glslang::GlslangToSpv(*Program.getIntermediate(ShLang), spirv); -#endif - - return std::move(spirv); -} - -} diff --git a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp index 45a63b07..6b348981 100644 --- a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp +++ b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp @@ -26,6 +26,7 @@ #include "spirv_cross.hpp" #include "ShaderBase.h" #include "GraphicsAccessories.h" +#include "StringTools.h" namespace Diligent { @@ -62,35 +63,38 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const spirv_cross::Compil const char* _Name, ResourceType _Type, SHADER_VARIABLE_TYPE _VarType, - Int32 _StaticSamplerInd)noexcept : - Name(_Name), - ArraySize(GetResourceArraySize(Compiler, Res)), - Type(_Type), - VarType(_VarType), - StaticSamplerInd(static_cast(_StaticSamplerInd)), - BindingDecorationOffset(GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationBinding)), + Int32 _StaticSamplerInd, + Uint32 _SepSmplrOrImgInd)noexcept : + Name (_Name), + ArraySize (GetResourceArraySize(Compiler, Res)), + Type (_Type), + VarType (_VarType), + StaticSamplerInd (static_cast(_StaticSamplerInd)), + SepSmplrOrImgInd (_SepSmplrOrImgInd), + BindingDecorationOffset (GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationBinding)), DescriptorSetDecorationOffset(GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationDescriptorSet)) { VERIFY(_StaticSamplerInd >= std::numeric_limits::min() && _StaticSamplerInd <= std::numeric_limits::max(), "Static sampler index is out of representable range" ); } -static Int32 FindStaticSampler(const ShaderDesc& shaderDesc, const std::string& SamplerName) +static Int32 FindStaticSampler(const ShaderDesc& shaderDesc, const std::string& SamplerName, const char* SamplerSuffix) { for(Uint32 s=0; s < shaderDesc.NumStaticSamplers; ++s) { const auto& StSam = shaderDesc.StaticSamplers[s]; - if (SamplerName.compare(StSam.SamplerOrTextureName) == 0) + if (StreqSuff(SamplerName.c_str(), StSam.SamplerOrTextureName, SamplerSuffix)) return s; } return -1; } -SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, - IRenderDevice* pRenderDevice, - std::vector spirv_binary, - const ShaderDesc& shaderDesc) : +SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, + IRenderDevice* pRenderDevice, + std::vector spirv_binary, + const ShaderDesc& shaderDesc, + const char* CombinedSamplerSuffix) : m_ShaderType(shaderDesc.ShaderType) { // https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide @@ -115,16 +119,20 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, ResourceNamesPoolSize += res.name.length() + 1; } - Initialize(Allocator, - static_cast(resources.uniform_buffers.size()), - static_cast(resources.storage_buffers.size()), - static_cast(resources.storage_images.size()), - static_cast(resources.sampled_images.size()), - static_cast(resources.atomic_counters.size()), - static_cast(resources.separate_images.size()), - static_cast(resources.separate_samplers.size()), - shaderDesc.NumStaticSamplers, - ResourceNamesPoolSize); + if (CombinedSamplerSuffix != nullptr) + { + ResourceNamesPoolSize += strlen(CombinedSamplerSuffix) + 1; + } + + ResourceCounters ResCounters; + ResCounters.NumUBs = static_cast(resources.uniform_buffers.size()); + ResCounters.NumSBs = static_cast(resources.storage_buffers.size()); + ResCounters.NumImgs = static_cast(resources.storage_images.size()); + ResCounters.NumSmpldImgs = static_cast(resources.sampled_images.size()); + ResCounters.NumACs = static_cast(resources.atomic_counters.size()); + ResCounters.NumSepImgs = static_cast(resources.separate_samplers.size()); + ResCounters.NumSepSmplrs = static_cast(resources.separate_images.size()); + Initialize(Allocator, ResCounters, shaderDesc.NumStaticSamplers, ResourceNamesPoolSize); { Uint32 CurrUB = 0; @@ -160,12 +168,12 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, Uint32 CurrSmplImg = 0; for (const auto &SmplImg : resources.sampled_images) { - auto StaticSamplerInd = FindStaticSampler(shaderDesc, SmplImg.name); + auto StaticSamplerInd = FindStaticSampler(shaderDesc, SmplImg.name, nullptr); const auto& type = Compiler.get_type(SmplImg.type_id); auto ResType = type.image.dim == spv::DimBuffer ? SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer : SPIRVShaderResourceAttribs::ResourceType::SampledImage; - new (&GetSmplImg(CurrSmplImg++)) + new (&GetSmpldImg(CurrSmplImg++)) SPIRVShaderResourceAttribs(Compiler, SmplImg, m_ResourceNames.CopyString(SmplImg.name), @@ -173,7 +181,7 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, GetShaderVariableType(SmplImg.name, shaderDesc), StaticSamplerInd); } - VERIFY_EXPR(CurrSmplImg == GetNumSmplImgs()); + VERIFY_EXPR(CurrSmplImg == GetNumSmpldImgs()); } { @@ -210,35 +218,74 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, VERIFY_EXPR(CurrAC == GetNumACs()); } + { + Uint32 CurrSepSmpl = 0; + for (const auto &SepSam : resources.separate_samplers) + { + auto StaticSamplerInd = FindStaticSampler(shaderDesc, SepSam.name, CombinedSamplerSuffix); + // Use texture or sampler name to derive sampler type + auto VarType = GetShaderVariableType(shaderDesc.DefaultVariableType, shaderDesc.VariableDesc, shaderDesc.NumVariables, + [&](const char* VarName) + { + return StreqSuff(SepSam.name.c_str(), VarName, CombinedSamplerSuffix); + }); + + new (&GetSepSmplr(CurrSepSmpl++)) + SPIRVShaderResourceAttribs(Compiler, + SepSam, + m_ResourceNames.CopyString(SepSam.name), + SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, + VarType, + StaticSamplerInd); + } + VERIFY_EXPR(CurrSepSmpl == GetNumSepSmplrs()); + } + { Uint32 CurrSepImg = 0; for (const auto &SepImg : resources.separate_images) { - new (&GetSepImg(CurrSepImg++)) + Uint32 SamplerInd = SPIRVShaderResourceAttribs::InvalidSepSmplrOrImgInd; + if (CombinedSamplerSuffix != nullptr) + { + auto NumSepSmpls = GetNumSepSmplrs(); + for (SamplerInd = 0; SamplerInd < NumSepSmpls; ++SamplerInd) + { + auto& SepSmplr = GetSepSmplr(SamplerInd); + if (StreqSuff(SepSmplr.Name, SepImg.name.c_str(), CombinedSamplerSuffix)) + { + SepSmplr.SepSmplrOrImgInd = static_cast(CurrSepImg); + if (SepSmplr.StaticSamplerInd >= 0) + SamplerInd = NumSepSmpls; + break; + } + } + if (SamplerInd == NumSepSmpls) + SamplerInd = SPIRVShaderResourceAttribs::InvalidSepSmplrOrImgInd; + } + auto* pNewSepImg = new (&GetSepImg(CurrSepImg++)) SPIRVShaderResourceAttribs(Compiler, SepImg, m_ResourceNames.CopyString(SepImg.name), SPIRVShaderResourceAttribs::ResourceType::SeparateImage, GetShaderVariableType(SepImg.name, shaderDesc), - -1); + -1, + SamplerInd); + if (pNewSepImg->ValidSepSamplerAssigned()) + { + const auto& SepSmplr = GetSepSmplr(pNewSepImg->SepSmplrOrImgInd); + DEV_CHECK_ERR(SepSmplr.ArraySize == 1 || SepSmplr.ArraySize == pNewSepImg->ArraySize, + "Array size (", SepSmplr.ArraySize,") of separate sampler variable '", + SepSmplr.Name, "' must be one or same as the array size (", pNewSepImg->ArraySize, + ") of separate image variable '", pNewSepImg->Name, "' it is assigned to"); + } } VERIFY_EXPR(CurrSepImg == GetNumSepImgs()); } - + + if (CombinedSamplerSuffix != nullptr) { - Uint32 CurrSepSmpl = 0; - for (const auto &SepSam : resources.separate_samplers) - { - auto StaticSamplerInd = FindStaticSampler(shaderDesc, SepSam.name); - new (&GetSepSmpl(CurrSepSmpl++)) - SPIRVShaderResourceAttribs(Compiler, - SepSam, - m_ResourceNames.CopyString(SepSam.name), - SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, - GetShaderVariableType(SepSam.name, shaderDesc), - StaticSamplerInd); - } - VERIFY_EXPR(CurrSepSmpl == GetNumSepSmpls()); + m_CombinedSamplerSuffix = m_ResourceNames.CopyString(CombinedSamplerSuffix); } VERIFY(m_ResourceNames.GetRemainingSize() == 0, "Names pool must be empty"); @@ -252,7 +299,7 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, //LOG_INFO_MESSAGE(DumpResources()); -#ifdef _DEBUG +#ifdef DEVELOPMENT if (shaderDesc.NumVariables != 0) { for (Uint32 v = 0; v < shaderDesc.NumVariables; ++v) @@ -281,91 +328,88 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, { for (Uint32 s = 0; s < shaderDesc.NumStaticSamplers; ++s) { - bool SamplerFound = false; const auto* SamName = shaderDesc.StaticSamplers[s].SamplerOrTextureName; - for (Uint32 i = 0; i < GetNumSmplImgs(); ++i) + bool SamplerFound = false; + if (CombinedSamplerSuffix != nullptr) { - const auto &SmplImg = GetSmplImg(i); - if (strcmp(SmplImg.Name, SamName) == 0) + for (Uint32 i = 0; i < GetNumSmpldImgs(); ++i) { - SamplerFound = true; - break; + const auto& SmplImg = GetSmpldImg(i); + SamplerFound = (strcmp(SmplImg.Name, SamName) == 0); + if (SamplerFound) + break; } } - - if(SamplerFound) - continue; - - for (Uint32 i = 0; i < GetNumSepSmpls(); ++i) + else { - const auto &SepSmpl = GetSepSmpl(i); - if (strcmp(SepSmpl.Name, SamName) == 0) + for (Uint32 i = 0; i < GetNumSepSmplrs(); ++i) { - SamplerFound = true; - break; + const auto& SepSmpl = GetSepSmplr(i); + SamplerFound = (strcmp(SepSmpl.Name, SamName) == 0); + if (SamplerFound) + break; } } if (!SamplerFound) { - LOG_WARNING_MESSAGE("Static sampler '", SamName, "' not found in shader \'", shaderDesc.Name, "'"); + LOG_WARNING_MESSAGE("Static sampler '", SamName, "' not found in shader '", shaderDesc.Name, "'"); } } } + + if (CombinedSamplerSuffix != nullptr) + { + for (Uint32 n=0; n < GetNumSepSmplrs(); ++n) + { + const auto& SepSmplr = GetSepSmplr(n); + if (!SepSmplr.ValidSepImageAssigned()) + LOG_ERROR_MESSAGE("Shader '", shaderDesc.Name, "' uses combined texture samplers, but separate sampler '", SepSmplr.Name, "' is not assigned to any texture"); + } + } #endif } -void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, - Uint32 NumUBs, - Uint32 NumSBs, - Uint32 NumImgs, - Uint32 NumSmplImgs, - Uint32 NumACs, - Uint32 NumSepImgs, - Uint32 NumSepSmpls, - Uint32 NumStaticSamplers, - size_t ResourceNamesPoolSize) +void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, + const ResourceCounters& Counters, + Uint32 NumStaticSamplers, + size_t ResourceNamesPoolSize) { - static constexpr OffsetType UniformBufferOffset = 0; - - const auto MaxOffset = static_cast(std::numeric_limits::max()); - VERIFY(UniformBufferOffset + NumUBs <= MaxOffset, "Max offset exceeded"); - m_StorageBufferOffset = UniformBufferOffset + static_cast(NumUBs); - - VERIFY(m_StorageBufferOffset + NumSBs <= MaxOffset, "Max offset exceeded"); - m_StorageImageOffset = m_StorageBufferOffset + static_cast(NumSBs); - - VERIFY(m_StorageImageOffset + NumImgs <= MaxOffset, "Max offset exceeded"); - m_SampledImageOffset = m_StorageImageOffset + static_cast(NumImgs); - - VERIFY(m_SampledImageOffset + NumSmplImgs <= MaxOffset, "Max offset exceeded"); - m_AtomicCounterOffset = m_SampledImageOffset + static_cast(NumSmplImgs); - - VERIFY(m_AtomicCounterOffset + NumACs <= MaxOffset, "Max offset exceeded"); - m_SeparateImageOffset = m_AtomicCounterOffset + static_cast(NumACs); - - VERIFY(m_SeparateImageOffset + NumSepImgs <= MaxOffset, "Max offset exceeded"); - m_SeparateSamplerOffset = m_SeparateImageOffset + static_cast(NumSepImgs); - - VERIFY(m_SeparateSamplerOffset + NumSepSmpls <= MaxOffset, "Max offset exceeded"); - m_TotalResources = m_SeparateSamplerOffset + static_cast(NumSepSmpls); - - VERIFY(m_NumStaticSamplers <= MaxOffset, "Max offset exceeded"); + Uint32 CurrentOffset = 0; + constexpr Uint32 MaxOffset = std::numeric_limits::max(); + auto AdvanceOffset = [&CurrentOffset, MaxOffset](Uint32 NumResources) + { + VERIFY(CurrentOffset <= MaxOffset, "Current offser (", CurrentOffset, ") exceeds max allowed value (", MaxOffset, ")"); + auto Offset = static_cast(CurrentOffset); + CurrentOffset += NumResources; + return Offset; + }; + + auto UniformBufferOffset = AdvanceOffset(Counters.NumUBs); UniformBufferOffset; // To suppress warning + m_StorageBufferOffset = AdvanceOffset(Counters.NumSBs); + m_StorageImageOffset = AdvanceOffset(Counters.NumImgs); + m_SampledImageOffset = AdvanceOffset(Counters.NumSmpldImgs); + m_AtomicCounterOffset = AdvanceOffset(Counters.NumACs); + m_SeparateSamplerOffset = AdvanceOffset(Counters.NumSepSmplrs); + m_SeparateImageOffset = AdvanceOffset(Counters.NumSepImgs); + m_TotalResources = AdvanceOffset(0); + + VERIFY(NumStaticSamplers <= MaxOffset, "Max offset exceeded"); m_NumStaticSamplers = static_cast(NumStaticSamplers); static_assert(sizeof(SPIRVShaderResourceAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderResourceAttribs struct must be multiple of sizeof(void*)"); static_assert(sizeof(SamplerPtrType) % sizeof(void*) == 0, "Size of SamplerPtrType must be multiple of sizeof(void*)"); - auto MemorySize = m_TotalResources * sizeof(SPIRVShaderResourceAttribs) + - m_NumStaticSamplers * sizeof(SamplerPtrType) + + auto MemorySize = m_TotalResources * sizeof(SPIRVShaderResourceAttribs) + + m_NumStaticSamplers * sizeof(SamplerPtrType) + ResourceNamesPoolSize * sizeof(char); - VERIFY_EXPR(GetNumUBs() == NumUBs); - VERIFY_EXPR(GetNumSBs() == NumSBs); - VERIFY_EXPR(GetNumImgs() == NumImgs); - VERIFY_EXPR(GetNumSmplImgs() == NumSmplImgs); - VERIFY_EXPR(GetNumACs() == NumACs); - VERIFY_EXPR(GetNumSepImgs() == NumSepImgs); - VERIFY_EXPR(GetNumSepSmpls() == NumSepSmpls); + VERIFY_EXPR(GetNumUBs() == Counters.NumUBs); + VERIFY_EXPR(GetNumSBs() == Counters.NumSBs); + VERIFY_EXPR(GetNumImgs() == Counters.NumImgs); + VERIFY_EXPR(GetNumSmpldImgs() == Counters.NumSmpldImgs); + VERIFY_EXPR(GetNumACs() == Counters.NumACs); + VERIFY_EXPR(GetNumSepSmplrs() == Counters.NumSepSmplrs); + VERIFY_EXPR(GetNumSepImgs() == Counters.NumSepImgs); if (MemorySize) { @@ -389,88 +433,83 @@ SPIRVShaderResources::~SPIRVShaderResources() for (Uint32 n = 0; n < GetNumImgs(); ++n) GetImg(n).~SPIRVShaderResourceAttribs(); - for (Uint32 n = 0; n < GetNumSmplImgs(); ++n) - GetSmplImg(n).~SPIRVShaderResourceAttribs(); + for (Uint32 n = 0; n < GetNumSmpldImgs(); ++n) + GetSmpldImg(n).~SPIRVShaderResourceAttribs(); for (Uint32 n = 0; n < GetNumACs(); ++n) GetAC(n).~SPIRVShaderResourceAttribs(); + for (Uint32 n = 0; n < GetNumSepSmplrs(); ++n) + GetSepSmplr(n).~SPIRVShaderResourceAttribs(); + for (Uint32 n = 0; n < GetNumSepImgs(); ++n) GetSepImg(n).~SPIRVShaderResourceAttribs(); - for (Uint32 n = 0; n < GetNumSepSmpls(); ++n) - GetSepSmpl(n).~SPIRVShaderResourceAttribs(); - for (Uint32 n = 0; n < GetNumStaticSamplers(); ++n) GetStaticSampler(n).~SamplerPtrType(); } -void SPIRVShaderResources::CountResources(const SHADER_VARIABLE_TYPE *AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumUBs, - Uint32& NumSBs, - Uint32& NumImgs, - Uint32& NumSmplImgs, - Uint32& NumACs, - Uint32& NumSepImgs, - Uint32& NumSepSmpls)const noexcept +SPIRVShaderResources::ResourceCounters SPIRVShaderResources::CountResources(const SHADER_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes)const noexcept { Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - NumUBs = 0; - NumSBs = 0; - NumImgs = 0; - NumSmplImgs = 0; - NumACs = 0; - NumSepImgs = 0; - NumSepSmpls = 0; + ResourceCounters Counters; ProcessResources( AllowedVarTypes, NumAllowedTypes, - [&](const SPIRVShaderResourceAttribs &UB, Uint32) + [&](const SPIRVShaderResourceAttribs& UB, Uint32) { + VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer); VERIFY_EXPR(IsAllowedType(UB.VarType, AllowedTypeBits)); - ++NumUBs; + ++Counters.NumUBs; }, [&](const SPIRVShaderResourceAttribs& SB, Uint32) { + VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::StorageBuffer); VERIFY_EXPR(IsAllowedType(SB.VarType, AllowedTypeBits)); - ++NumSBs; + ++Counters.NumSBs; }, - [&](const SPIRVShaderResourceAttribs &Img, Uint32) + [&](const SPIRVShaderResourceAttribs& Img, Uint32) { + VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); VERIFY_EXPR(IsAllowedType(Img.VarType, AllowedTypeBits)); - ++NumImgs; + ++Counters.NumImgs; }, - [&](const SPIRVShaderResourceAttribs &SmplImg, Uint32) + [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) { + VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); VERIFY_EXPR(IsAllowedType(SmplImg.VarType, AllowedTypeBits)); - ++NumSmplImgs; + ++Counters.NumSmpldImgs; }, - [&](const SPIRVShaderResourceAttribs &AC, Uint32) + [&](const SPIRVShaderResourceAttribs& AC, Uint32) { + VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); VERIFY_EXPR(IsAllowedType(AC.VarType, AllowedTypeBits)); - ++NumACs; + ++Counters.NumACs; }, - [&](const SPIRVShaderResourceAttribs &SepImg, Uint32) + [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) { - VERIFY_EXPR(IsAllowedType(SepImg.VarType, AllowedTypeBits)); - ++NumSepImgs; + VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); + VERIFY_EXPR(IsAllowedType(SepSmpl.VarType, AllowedTypeBits)); + ++Counters.NumSepSmplrs; }, - [&](const SPIRVShaderResourceAttribs &SepSmpl, Uint32) + [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) { - VERIFY_EXPR(IsAllowedType(SepSmpl.VarType, AllowedTypeBits)); - ++NumSepSmpls; + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + VERIFY_EXPR(IsAllowedType(SepImg.VarType, AllowedTypeBits)); + ++Counters.NumSepImgs; } ); + return Counters; } std::string SPIRVShaderResources::DumpResources() { std::stringstream ss; ss << "Resource counters (" << GetTotalResources() << " total):" << std::endl << "UBs: " << GetNumUBs() << "; SBs: " - << GetNumSBs() << "; Imgs: " << GetNumImgs() << "; Smpl Imgs: " << GetNumSmplImgs() << "; ACs: " << GetNumACs() - << "; Sep Imgs: " << GetNumSepImgs() << "; Sep Smpls: " << GetNumSepSmpls() << '.' << std::endl + << GetNumSBs() << "; Imgs: " << GetNumImgs() << "; Smpl Imgs: " << GetNumSmpldImgs() << "; ACs: " << GetNumACs() + << "; Sep Imgs: " << GetNumSepImgs() << "; Sep Smpls: " << GetNumSepSmplrs() << '.' << std::endl << "Num Static Samplers: " << GetNumStaticSamplers() << std::endl << "Resources:"; Uint32 ResNum = 0; @@ -530,17 +569,17 @@ std::string SPIRVShaderResources::DumpResources() ss << std::endl << std::setw(3) << ResNum << " Atomic Cntr "; DumpResource(AC); }, - [&](const SPIRVShaderResourceAttribs &SepImg, Uint32) - { - VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, "Unexpected resource type"); - ss << std::endl << std::setw(3) << ResNum << " Separate Img "; - DumpResource(SepImg); - }, [&](const SPIRVShaderResourceAttribs &SepSmpl, Uint32) { VERIFY(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Unexpected resource type"); ss << std::endl << std::setw(3) << ResNum << " Separate Smpl "; DumpResource(SepSmpl); + }, + [&](const SPIRVShaderResourceAttribs &SepImg, Uint32) + { + VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, "Unexpected resource type"); + ss << std::endl << std::setw(3) << ResNum << " Separate Img "; + DumpResource(SepImg); } ); VERIFY_EXPR(ResNum == GetTotalResources()); @@ -555,10 +594,10 @@ bool SPIRVShaderResources::IsCompatibleWith(const SPIRVShaderResources& Resource if( GetNumUBs() != Resources.GetNumUBs() || GetNumSBs() != Resources.GetNumSBs() || GetNumImgs() != Resources.GetNumImgs() || - GetNumSmplImgs() != Resources.GetNumSmplImgs() || + GetNumSmpldImgs() != Resources.GetNumSmpldImgs() || GetNumACs() != Resources.GetNumACs() || GetNumSepImgs() != Resources.GetNumSepImgs() || - GetNumSepSmpls() != Resources.GetNumSepSmpls() || + GetNumSepSmplrs() != Resources.GetNumSepSmplrs() || GetNumStaticSamplers() != Resources.GetNumStaticSamplers() ) return false; VERIFY_EXPR(GetTotalResources() == Resources.GetTotalResources()); diff --git a/Graphics/GLSLTools/src/SPIRVUtils.cpp b/Graphics/GLSLTools/src/SPIRVUtils.cpp new file mode 100644 index 00000000..64eae1b4 --- /dev/null +++ b/Graphics/GLSLTools/src/SPIRVUtils.cpp @@ -0,0 +1,493 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include +#include +#include +#include + +#if PLATFORM_ANDROID + // Android specific include files. +# include + + // Header files. +# include +# include "shaderc/shaderc.hpp" + // Static variable that keeps ANativeWindow and asset manager instances. + //static android_app *Android_application = nullptr; +#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) +# include +#else +# include "SPIRV/GlslangToSpv.h" +#endif + +#include "SPIRVUtils.h" +#include "DebugUtilities.h" +#include "DataBlobImpl.h" +#include "RefCntAutoPtr.h" + +namespace Diligent +{ + +void InitializeGlslang() +{ +#if !PLATFORM_ANDROID + glslang::InitializeProcess(); +#endif +} + +void FinalizeGlslang() +{ +#if !PLATFORM_ANDROID + glslang::FinalizeProcess(); +#endif +} + +EShLanguage ShaderTypeToShLanguage(SHADER_TYPE ShaderType) +{ + switch(ShaderType) + { + case SHADER_TYPE_VERTEX: return EShLangVertex; + case SHADER_TYPE_HULL: return EShLangTessControl; + case SHADER_TYPE_DOMAIN: return EShLangTessEvaluation; + case SHADER_TYPE_GEOMETRY: return EShLangGeometry; + case SHADER_TYPE_PIXEL: return EShLangFragment; + case SHADER_TYPE_COMPUTE: return EShLangCompute; + + default: + UNEXPECTED("Unexpected shader type"); + return EShLangCount; + } +} + +TBuiltInResource InitResources() +{ + TBuiltInResource Resources; + + Resources.maxLights = 32; + Resources.maxClipPlanes = 6; + Resources.maxTextureUnits = 32; + Resources.maxTextureCoords = 32; + Resources.maxVertexAttribs = 64; + Resources.maxVertexUniformComponents = 4096; + Resources.maxVaryingFloats = 64; + Resources.maxVertexTextureImageUnits = 32; + Resources.maxCombinedTextureImageUnits = 80; + Resources.maxTextureImageUnits = 32; + Resources.maxFragmentUniformComponents = 4096; + Resources.maxDrawBuffers = 32; + Resources.maxVertexUniformVectors = 128; + Resources.maxVaryingVectors = 8; + Resources.maxFragmentUniformVectors = 16; + Resources.maxVertexOutputVectors = 16; + Resources.maxFragmentInputVectors = 15; + Resources.minProgramTexelOffset = -8; + Resources.maxProgramTexelOffset = 7; + Resources.maxClipDistances = 8; + Resources.maxComputeWorkGroupCountX = 65535; + Resources.maxComputeWorkGroupCountY = 65535; + Resources.maxComputeWorkGroupCountZ = 65535; + Resources.maxComputeWorkGroupSizeX = 1024; + Resources.maxComputeWorkGroupSizeY = 1024; + Resources.maxComputeWorkGroupSizeZ = 64; + Resources.maxComputeUniformComponents = 1024; + Resources.maxComputeTextureImageUnits = 16; + Resources.maxComputeImageUniforms = 8; + Resources.maxComputeAtomicCounters = 8; + Resources.maxComputeAtomicCounterBuffers = 1; + Resources.maxVaryingComponents = 60; + Resources.maxVertexOutputComponents = 64; + Resources.maxGeometryInputComponents = 64; + Resources.maxGeometryOutputComponents = 128; + Resources.maxFragmentInputComponents = 128; + Resources.maxImageUnits = 8; + Resources.maxCombinedImageUnitsAndFragmentOutputs = 8; + Resources.maxCombinedShaderOutputResources = 8; + Resources.maxImageSamples = 0; + Resources.maxVertexImageUniforms = 0; + Resources.maxTessControlImageUniforms = 0; + Resources.maxTessEvaluationImageUniforms = 0; + Resources.maxGeometryImageUniforms = 0; + Resources.maxFragmentImageUniforms = 8; + Resources.maxCombinedImageUniforms = 8; + Resources.maxGeometryTextureImageUnits = 16; + Resources.maxGeometryOutputVertices = 256; + Resources.maxGeometryTotalOutputComponents = 1024; + Resources.maxGeometryUniformComponents = 1024; + Resources.maxGeometryVaryingComponents = 64; + Resources.maxTessControlInputComponents = 128; + Resources.maxTessControlOutputComponents = 128; + Resources.maxTessControlTextureImageUnits = 16; + Resources.maxTessControlUniformComponents = 1024; + Resources.maxTessControlTotalOutputComponents = 4096; + Resources.maxTessEvaluationInputComponents = 128; + Resources.maxTessEvaluationOutputComponents = 128; + Resources.maxTessEvaluationTextureImageUnits = 16; + Resources.maxTessEvaluationUniformComponents = 1024; + Resources.maxTessPatchComponents = 120; + Resources.maxPatchVertices = 32; + Resources.maxTessGenLevel = 64; + Resources.maxViewports = 16; + Resources.maxVertexAtomicCounters = 0; + Resources.maxTessControlAtomicCounters = 0; + Resources.maxTessEvaluationAtomicCounters = 0; + Resources.maxGeometryAtomicCounters = 0; + Resources.maxFragmentAtomicCounters = 8; + Resources.maxCombinedAtomicCounters = 8; + Resources.maxAtomicCounterBindings = 1; + Resources.maxVertexAtomicCounterBuffers = 0; + Resources.maxTessControlAtomicCounterBuffers = 0; + Resources.maxTessEvaluationAtomicCounterBuffers = 0; + Resources.maxGeometryAtomicCounterBuffers = 0; + Resources.maxFragmentAtomicCounterBuffers = 1; + Resources.maxCombinedAtomicCounterBuffers = 1; + Resources.maxAtomicCounterBufferSize = 16384; + Resources.maxTransformFeedbackBuffers = 4; + Resources.maxTransformFeedbackInterleavedComponents = 64; + Resources.maxCullDistances = 8; + Resources.maxCombinedClipAndCullDistances = 8; + Resources.maxSamples = 4; + Resources.maxMeshOutputVerticesNV = 256; + Resources.maxMeshOutputPrimitivesNV = 512; + Resources.maxMeshWorkGroupSizeX_NV = 32; + Resources.maxMeshWorkGroupSizeY_NV = 1; + Resources.maxMeshWorkGroupSizeZ_NV = 1; + Resources.maxTaskWorkGroupSizeX_NV = 32; + Resources.maxTaskWorkGroupSizeY_NV = 1; + Resources.maxTaskWorkGroupSizeZ_NV = 1; + Resources.maxMeshViewCountNV = 4; + + Resources.limits.nonInductiveForLoops = 1; + Resources.limits.whileLoops = 1; + Resources.limits.doWhileLoops = 1; + Resources.limits.generalUniformIndexing = 1; + Resources.limits.generalAttributeMatrixVectorIndexing = 1; + Resources.limits.generalVaryingIndexing = 1; + Resources.limits.generalSamplerIndexing = 1; + Resources.limits.generalVariableIndexing = 1; + Resources.limits.generalConstantMatrixVectorIndexing = 1; + + return Resources; +} + +class IoMapResolver : public glslang::TIoMapResolver +{ +public: + // Should return true if the resulting/current binding would be okay. + // Basic idea is to do aliasing binding checks with this. + virtual bool validateBinding(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + return true; + } + + // Should return a value >= 0 if the current binding should be overridden. + // Return -1 if the current binding (including no binding) should be kept. + virtual int resolveBinding(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + // We do not care about actual binding value here. + // We only need decoration to be present in SPIRV + return 0; + } + + // Should return a value >= 0 if the current set should be overridden. + // Return -1 if the current set (including no set) should be kept. + virtual int resolveSet(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + // We do not care about actual descriptor set value here. + // We only need decoration to be present in SPIRV + return 0; + } + + // Should return a value >= 0 if the current location should be overridden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveUniformLocation(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + return -1; + } + + // Should return true if the resulting/current setup would be okay. + // Basic idea is to do aliasing checks and reject invalid semantic names. + virtual bool validateInOut(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + return true; + } + + // Should return a value >= 0 if the current location should be overridden. + // Return -1 if the current location (including no location) should be kept. + virtual int resolveInOutLocation(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + return -1; + } + + // Should return a value >= 0 if the current component index should be overridden. + // Return -1 if the current component index (including no index) should be kept. + virtual int resolveInOutComponent(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + return -1; + } + + // Should return a value >= 0 if the current color index should be overridden. + // Return -1 if the current color index (including no index) should be kept. + virtual int resolveInOutIndex(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + return -1; + } + + // Notification of a uniform variable + virtual void notifyBinding(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + } + + // Notification of a in or out variable + virtual void notifyInOut(EShLanguage stage, const char* name, const glslang::TType& type, bool is_live) + { + } + + // Called by mapIO when it has finished the notify pass + virtual void endNotifications(EShLanguage stage) + { + } + + // Called by mapIO when it starts its notify pass for the given stage + virtual void beginNotifications(EShLanguage stage) + { + } + + // Called by mipIO when it starts its resolve pass for the given stage + virtual void beginResolve(EShLanguage stage) + { + } + + // Called by mapIO when it has finished the resolve pass + virtual void endResolve(EShLanguage stage) + { + } +}; + +static void LogCompilerError(const char* DebugOutputMessage, + const char* InfoLog, + const char* InfoDebugLog, + const char* ShaderSource, + size_t SourceCodeLen, + IDataBlob** ppCompilerOutput) +{ + std::string ErrorLog(InfoLog); + if (*InfoDebugLog != '\0') + { + ErrorLog.push_back('\n'); + ErrorLog.append(InfoDebugLog); + } + LOG_ERROR_MESSAGE(DebugOutputMessage, ErrorLog); + + if (ppCompilerOutput != nullptr) + { + auto* pOutputDataBlob = MakeNewRCObj()(SourceCodeLen + 1 + ErrorLog.length() + 1); + char* DataPtr = reinterpret_cast(pOutputDataBlob->GetDataPtr()); + memcpy(DataPtr, ErrorLog.data(), ErrorLog.length() + 1); + memcpy(DataPtr + ErrorLog.length() + 1, ShaderSource, SourceCodeLen + 1); + pOutputDataBlob->QueryInterface(IID_DataBlob, reinterpret_cast(ppCompilerOutput)); + } +} + +static std::vector CompileShaderInternal(glslang::TShader& Shader, + EShMessages messages, + glslang::TShader::Includer* pIncluder, + const char* ShaderSource, + size_t SourceCodeLen, + IDataBlob** ppCompilerOutput) +{ + Shader.setAutoMapBindings(true); + TBuiltInResource Resources = InitResources(); + auto ParseResult = pIncluder != nullptr ? + Shader.parse(&Resources, 100, false, messages, *pIncluder) : + Shader.parse(&Resources, 100, false, messages); + if (!ParseResult) + { + LogCompilerError("Failed to parse shader source: \n", Shader.getInfoLog(), Shader.getInfoDebugLog(), ShaderSource, SourceCodeLen, ppCompilerOutput); + return {}; + } + + glslang::TProgram Program; + Program.addShader(&Shader); + if (!Program.link(messages)) + { + LogCompilerError("Failed to link program: \n", Program.getInfoLog(), Program.getInfoDebugLog(), ShaderSource, SourceCodeLen, ppCompilerOutput); + return {}; + } + + IoMapResolver Resovler; + // This step is essential to set bindings and descriptor sets + Program.mapIO(&Resovler); + + std::vector spirv; + glslang::GlslangToSpv(*Program.getIntermediate(Shader.getStage()), spirv); + + return std::move(spirv); +} + + +class IncluderImpl : public glslang::TShader::Includer +{ +public: + IncluderImpl(IShaderSourceInputStreamFactory* pInputStreamFactory) : + m_pInputStreamFactory(pInputStreamFactory) + {} + + // For the "system" or <>-style includes; search the "system" paths. + virtual IncludeResult* includeSystem(const char* headerName, + const char* /*includerName*/, + size_t /*inclusionDepth*/) + { + return nullptr; + } + + // For the "local"-only aspect of a "" include. Should not search in the + // "system" paths, because on returning a failure, the parser will + // call includeSystem() to look in the "system" locations. + virtual IncludeResult* includeLocal(const char* headerName, + const char* /*includerName*/, + size_t /*inclusionDepth*/) + { + DEV_CHECK_ERR(m_pInputStreamFactory != nullptr, "The shader source conains #include directives, but no input stream factory was provided"); + RefCntAutoPtr pSourceStream; + m_pInputStreamFactory->CreateInputStream( headerName, &pSourceStream ); + if( pSourceStream == nullptr ) + { + LOG_ERROR( "Failed to open shader include file \"", headerName, "\". Check that the file exists" ); + return nullptr; + } + + RefCntAutoPtr pFileData( MakeNewRCObj()(0) ); + pSourceStream->Read( pFileData ); + auto* pNewInclude = + new IncludeResult + { + headerName, + reinterpret_cast(pFileData->GetDataPtr()), + pFileData->GetSize(), + nullptr + }; + + m_IncludeRes.emplace(pNewInclude); + m_DataBlobs.emplace(pNewInclude, std::move(pFileData)); + return pNewInclude; + } + + // Signals that the parser will no longer use the contents of the + // specified IncludeResult. + virtual void releaseInclude(IncludeResult* IncldRes) + { + m_DataBlobs.erase(IncldRes); + } + +private: + IShaderSourceInputStreamFactory* const m_pInputStreamFactory; + std::unordered_set> m_IncludeRes; + std::unordered_map> m_DataBlobs; +}; + +std::vector HLSLtoSPIRV(const ShaderCreationAttribs& Attribs, IDataBlob** ppCompilerOutput) +{ + EShLanguage ShLang = ShaderTypeToShLanguage(Attribs.Desc.ShaderType); + glslang::TShader Shader(ShLang); + TBuiltInResource Resources = InitResources(); + + EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); + + VERIFY_EXPR(Attribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL); + + Shader.setEnvInput(glslang::EShSourceHlsl, ShLang, glslang::EShClientVulkan, 100); + Shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); + Shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); + messages = (EShMessages)(EShMsgReadHlsl | EShMsgHlslLegalization); + Shader.setHlslIoMapping(true); + Shader.setSourceEntryPoint(Attribs.EntryPoint); + Shader.setEntryPoint("main"); + + RefCntAutoPtr pFileData(MakeNewRCObj()(0)); + const char* SourceCode = 0; + int SourceCodeLen = 0; + if (Attribs.Source) + { + SourceCode = Attribs.Source; + SourceCodeLen = static_cast(strlen(Attribs.Source)); + } + else + { + VERIFY(Attribs.pShaderSourceStreamFactory, "Input stream factory is null"); + RefCntAutoPtr pSourceStream; + Attribs.pShaderSourceStreamFactory->CreateInputStream(Attribs.FilePath, &pSourceStream); + if (pSourceStream == nullptr) + LOG_ERROR_AND_THROW("Failed to open shader source file"); + + pSourceStream->Read(pFileData); + SourceCode = reinterpret_cast(pFileData->GetDataPtr()); + SourceCodeLen = static_cast(pFileData->GetSize()); + } + + int NumShaderStrings = 0; + constexpr size_t MaxShaderStrings = 2; + std::array ShaderStrings; + std::array ShaderStringLenghts; + std::string Defines; + if (Attribs.Macros != nullptr) + { + auto* pMacro = Attribs.Macros; + while (pMacro->Name != nullptr && pMacro->Definition != nullptr) + { + Defines += "#define "; + Defines += pMacro->Name; + Defines += ' '; + Defines += pMacro->Definition; + Defines += "\n"; + ++pMacro; + } + ShaderStrings [NumShaderStrings] = Defines.c_str(); + ShaderStringLenghts[NumShaderStrings] = static_cast(Defines.length()); + ++NumShaderStrings; + } + ShaderStrings [NumShaderStrings] = SourceCode; + ShaderStringLenghts[NumShaderStrings] = SourceCodeLen; + ++NumShaderStrings; + Shader.setStringsWithLengths(ShaderStrings.data(), ShaderStringLenghts.data(), NumShaderStrings); + + IncluderImpl Includer(Attribs.pShaderSourceStreamFactory); + return CompileShaderInternal(Shader, messages, &Includer, SourceCode, SourceCodeLen, ppCompilerOutput); +} + +std::vector GLSLtoSPIRV(const SHADER_TYPE ShaderType, const char* ShaderSource, int SourceCodeLen, IDataBlob** ppCompilerOutput) +{ + EShLanguage ShLang = ShaderTypeToShLanguage(ShaderType); + glslang::TShader Shader(ShLang); + + // Enable SPIR-V and Vulkan rules when parsing GLSL + EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); + + const char* ShaderStrings[] = {ShaderSource }; + int Lenghts[] = {SourceCodeLen}; + Shader.setStringsWithLengths(ShaderStrings, Lenghts, 1); + + return CompileShaderInternal(Shader, messages, nullptr, ShaderSource, SourceCodeLen, ppCompilerOutput); +} + +} diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h index 3ce40f5b..dc72d609 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.h @@ -144,9 +144,15 @@ public: VkResource& operator = (const VkResource&) = delete; VkResource& operator = (VkResource&&) = delete; + static constexpr const Uint32 CacheOffsetBits = 24; + static constexpr const Uint32 SamplerIndBits = 8; + static constexpr const Uint32 InvalidSamplerInd = (1 << SamplerIndBits)-1; + const Uint16 Binding; const Uint16 DescriptorSet; - const Uint32 CacheOffset; // Offset from the beginning of the cached descriptor set + const Uint32 CacheOffset : CacheOffsetBits; // Offset from the beginning of the cached descriptor set + const Uint32 SamplerInd : SamplerIndBits; // When using combined texture samplers, index of the separate sampler + // assigned to separate image const SPIRVShaderResourceAttribs& SpirvAttribs; const ShaderResourceLayoutVk& ParentResLayout; @@ -154,15 +160,19 @@ public: const SPIRVShaderResourceAttribs& _SpirvAttribs, uint32_t _Binding, uint32_t _DescriptorSet, - Uint32 _CacheOffset)noexcept : + Uint32 _CacheOffset, + Uint32 _SamplerInd)noexcept : Binding (static_cast(_Binding)), DescriptorSet (static_cast(_DescriptorSet)), CacheOffset (_CacheOffset), + SamplerInd (_SamplerInd), SpirvAttribs (_SpirvAttribs), ParentResLayout (_ParentLayout) { - VERIFY(_Binding <= std::numeric_limits::max(), "Binding (", _Binding, ") exceeds representable max value", std::numeric_limits::max() ); - VERIFY(_DescriptorSet <= std::numeric_limits::max(), "Descriptor set (", _DescriptorSet, ") exceeds representable max value", std::numeric_limits::max()); + VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits) ); + VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits) ); + VERIFY(_Binding <= std::numeric_limits::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits::max() ); + VERIFY(_DescriptorSet <= std::numeric_limits::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits::max()); } // Checks if a resource is bound in ResourceCache at the given ArrayIndex @@ -193,11 +203,13 @@ public: ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, Uint32 ArrayInd)const; - + + template void CacheImage(IDeviceObject* pTexView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd)const; + Uint32 ArrayInd, + TCacheSampler CacheSampler)const; void CacheSeparateSampler(IDeviceObject* pSampler, ShaderResourceCacheVk::Resource& DstRes, @@ -242,6 +254,8 @@ public: return Resources[GetResourceOffset(VarType,r)]; } + bool IsUsingSeparateSamplers()const {return !m_pResources->IsUsingCombinedSamplers();} + private: Uint32 GetResourceOffset(SHADER_VARIABLE_TYPE VarType, Uint32 r)const { @@ -276,6 +290,8 @@ private: const SHADER_VARIABLE_TYPE* AllowedVarTypes, Uint32 NumAllowedTypes); + Uint32 FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, Uint32 CurrResourceCount)const; + IObject& m_Owner; const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index fc986cf7..9bc21a7e 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -68,7 +68,7 @@ void ShaderResourceLayoutVk::AllocateMemory(std::shared_ptrProcessResources( AllowedVarTypes, NumAllowedTypes, - [&](const SPIRVShaderResourceAttribs &ResAttribs, Uint32) + [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) { VERIFY_EXPR(IsAllowedType(ResAttribs.VarType, AllowedTypeBits)); VERIFY( Uint32{m_NumResources[ResAttribs.VarType]} + 1 <= Uint32{std::numeric_limits::max()}, "Number of resources exceeds max representable value"); @@ -104,13 +104,21 @@ void ShaderResourceLayoutVk::InitializeStaticResourceLayout(std::shared_ptrProcessResources( &AllowedVarType, 1, - [&](const SPIRVShaderResourceAttribs &Attribs, Uint32) + [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) { Uint32 Binding = Attribs.Type; Uint32 DescriptorSet = 0; Uint32 CacheOffset = StaticResCacheSize; StaticResCacheSize += Attribs.ArraySize; - ::new (&GetResource(Attribs.VarType, CurrResInd[Attribs.VarType]++)) VkResource(*this, Attribs, Binding, DescriptorSet, CacheOffset); + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) + { + // Separate samplers are enumerated before separate images, so the sampler + // assigned to this separate image must already be created. + SamplerInd = FindAssignedSampler(Attribs, CurrResInd[Attribs.VarType]); + } + ::new (&GetResource(Attribs.VarType, CurrResInd[Attribs.VarType]++)) VkResource(*this, Attribs, Binding, DescriptorSet, CacheOffset, SamplerInd); } ); @@ -148,10 +156,11 @@ void ShaderResourceLayoutVk::Initialize(Uint32 NumShaders, std::unordered_map> dbgBindings_CacheOffsets; #endif - auto AddResource = [&](Uint32 ShaderInd, - ShaderResourceLayoutVk& ResLayout, - const SPIRVShaderResources& Resources, - const SPIRVShaderResourceAttribs& Attribs) + auto AddResource = [&](Uint32 ShaderInd, + ShaderResourceLayoutVk& ResLayout, + const SPIRVShaderResources& Resources, + const SPIRVShaderResourceAttribs& Attribs, + Uint32 SamplerInd = VkResource::InvalidSamplerInd) { Uint32 Binding = 0; Uint32 DescriptorSet = 0; @@ -179,7 +188,7 @@ void ShaderResourceLayoutVk::Initialize(Uint32 NumShaders, #endif auto& ResInd = CurrResInd[ShaderInd][Attribs.VarType]; - ::new (&ResLayout.GetResource(Attribs.VarType, ResInd++)) VkResource(ResLayout, Attribs, Binding, DescriptorSet, CacheOffset); + ::new (&ResLayout.GetResource(Attribs.VarType, ResInd++)) VkResource(ResLayout, Attribs, Binding, DescriptorSet, CacheOffset, SamplerInd); }; // First process uniform buffers for all shader stages to make sure all UBs go first in every descriptor set @@ -220,41 +229,48 @@ void ShaderResourceLayoutVk::Initialize(Uint32 NumShaders, Resources.ProcessResources( AllowedVarTypes, NumAllowedTypes, - [&](const SPIRVShaderResourceAttribs &UB, Uint32) + [&](const SPIRVShaderResourceAttribs& UB, Uint32) { + VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer); VERIFY_EXPR(IsAllowedType(UB.VarType, AllowedTypeBits)); // Skip }, [&](const SPIRVShaderResourceAttribs& SB, Uint32) { + VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::StorageBuffer); VERIFY_EXPR(IsAllowedType(SB.VarType, AllowedTypeBits)); // Skip }, - [&](const SPIRVShaderResourceAttribs &Img, Uint32) + [&](const SPIRVShaderResourceAttribs& Img, Uint32) { + VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); VERIFY_EXPR(IsAllowedType(Img.VarType, AllowedTypeBits)); AddResource(s, Layout, Resources, Img); }, - [&](const SPIRVShaderResourceAttribs &SmplImg, Uint32) + [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) { + VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); VERIFY_EXPR(IsAllowedType(SmplImg.VarType, AllowedTypeBits)); AddResource(s, Layout, Resources, SmplImg); }, - [&](const SPIRVShaderResourceAttribs &AC, Uint32) + [&](const SPIRVShaderResourceAttribs& AC, Uint32) { + VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); VERIFY_EXPR(IsAllowedType(AC.VarType, AllowedTypeBits)); AddResource(s, Layout, Resources, AC); }, - [&](const SPIRVShaderResourceAttribs &SepImg, Uint32) - { - VERIFY_EXPR(IsAllowedType(SepImg.VarType, AllowedTypeBits)); - AddResource(s, Layout, Resources, SepImg); - }, - - [&](const SPIRVShaderResourceAttribs &SepSmpl, Uint32) + [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) { + VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); VERIFY_EXPR(IsAllowedType(SepSmpl.VarType, AllowedTypeBits)); AddResource(s, Layout, Resources, SepSmpl); + }, + [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) + { + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + VERIFY_EXPR(IsAllowedType(SepImg.VarType, AllowedTypeBits)); + Uint32 SamplerInd = Layout.FindAssignedSampler(SepImg, CurrResInd[s][SepImg.VarType]); + AddResource(s, Layout, Resources, SepImg, SamplerInd); } ); } @@ -271,11 +287,43 @@ void ShaderResourceLayoutVk::Initialize(Uint32 NumShaders, #endif } + +Uint32 ShaderResourceLayoutVk::FindAssignedSampler(const SPIRVShaderResourceAttribs& SepImg, Uint32 CurrResourceCount)const +{ + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (m_pResources->IsUsingCombinedSamplers() && SepImg.ValidSepSamplerAssigned()) + { + const auto& SepSampler = m_pResources->GetSepSmplr(SepImg.SepSmplrOrImgInd); + DEV_CHECK_ERR(SepImg.VarType == SepSampler.VarType, + "The type (", GetShaderVariableTypeLiteralName(SepImg.VarType),") of separate image variable '", SepImg.Name, + "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SepSampler.VarType), + ") of the separate sampler '", SepSampler.Name, "' that is assigned to it."); + + for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) + { + const auto& Res = GetResource(SepSampler.VarType, SamplerInd); + if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) + { + break; + } + } + if (SamplerInd == CurrResourceCount) + { + LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '", SepImg.Name, "' in the list of already created resources. This seems to be a bug."); + SamplerInd = VkResource::InvalidSamplerInd; + } + } + return SamplerInd; +} + #define LOG_RESOURCE_BINDING_ERROR(ResType, pResource, VarName, ShaderName, ...)\ -{ \ - const auto &ResName = pResource->GetDesc().Name; \ - LOG_ERROR_MESSAGE( "Failed to bind ", ResType, " \"", ResName, "\" to variable \"", VarName, \ - "\" in shader \"", ShaderName, "\". ", __VA_ARGS__ ); \ +{ \ + const auto &ResName = pResource->GetDesc().Name; \ + LOG_ERROR_MESSAGE( "Failed to bind ", ResType, " '", ResName, "' to variable '", VarName, \ + "' in shader '", ShaderName, "'. ", __VA_ARGS__ ); \ } void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, @@ -319,7 +367,7 @@ bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCach if (DstRes.pObject != pResource) { auto VarTypeStr = GetShaderVariableTypeLiteralName(SpirvAttribs.VarType); - LOG_ERROR_MESSAGE("Non-null resource is already bound to ", VarTypeStr, " shader variable \"", SpirvAttribs.GetPrintName(ArrayInd), "\" in shader \"", ParentResLayout.GetShaderName(), "\". Attempring to bind another resource is an error and will be ignored. Use another shader resource binding instance or label the variable as dynamic."); + LOG_ERROR_MESSAGE("Non-null resource is already bound to ", VarTypeStr, " shader variable '", SpirvAttribs.GetPrintName(ArrayInd), "' in shader '", ParentResLayout.GetShaderName(), "'. Attempring to bind another resource is an error and will be ignored. Use another shader resource binding instance or label the variable as dynamic."); } // Do not update resource if one is already bound unless it is dynamic. This may be @@ -441,20 +489,23 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* } } +template void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* pTexView, ShaderResourceCacheVk::Resource& DstRes, VkDescriptorSet vkDescrSet, - Uint32 ArrayInd)const + Uint32 ArrayInd, + TCacheSampler CacheSampler)const { - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || + VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage, "Storage image, separate image or sampled image resource is expected"); if (UpdateCachedResource(DstRes, ArrayInd, pTexView, IID_TextureViewVk, "texture view") ) { -#ifdef DEVELOPMENT + // We can do RawPtr here safely since UpdateCachedResource() returned true auto* pTexViewVk = DstRes.pObject.RawPtr(); +#ifdef DEVELOPMENT const auto ViewType = pTexViewVk->GetDesc().ViewType; const bool IsStorageImage = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage; const auto dbgExpectedViewType = IsStorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE; @@ -472,7 +523,7 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* { if(pTexViewVk->GetSampler() == nullptr) { - LOG_RESOURCE_BINDING_ERROR("resource", pTexView, SpirvAttribs.GetPrintName(ArrayInd), ParentResLayout.GetShaderName(), "No sampler assigned to texture view."); + LOG_RESOURCE_BINDING_ERROR("resource", pTexView, SpirvAttribs.GetPrintName(ArrayInd), ParentResLayout.GetShaderName(), "No sampler assigned to texture view '", pTexViewVk->GetDesc().Name, "'"); } } #endif @@ -484,6 +535,24 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* VkDescriptorImageInfo DescrImgInfo = DstRes.GetImageDescriptorWriteInfo(SpirvAttribs.StaticSamplerInd >= 0); UpdateDescriptorHandle(vkDescrSet, ArrayInd, &DescrImgInfo, nullptr, nullptr); } + + if (SamplerInd != InvalidSamplerInd) + { + VERIFY_EXPR(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + VERIFY_EXPR(SpirvAttribs.StaticSamplerInd < 0); + auto* pSampler = pTexViewVk->GetSampler(); + const auto& SamplerAttribs = ParentResLayout.GetResource(SpirvAttribs.VarType, SamplerInd); + if (pSampler != nullptr) + { + CacheSampler(SamplerAttribs, pSampler); + } + else + { + LOG_ERROR_MESSAGE( "Failed to bind sampler to sampler variable '", SamplerAttribs.SpirvAttribs.Name, + "' assigned to separate image '", SpirvAttribs.GetPrintName(ArrayInd), "' in shader '", + ParentResLayout.GetShaderName(), "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\''); \ + } + } } } @@ -554,7 +623,17 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject *pObj, Uint3 case SPIRVShaderResourceAttribs::ResourceType::StorageImage: case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: case SPIRVShaderResourceAttribs::ResourceType::SampledImage: - CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex); + CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex, + [&](const VkResource& SeparateSampler, ISampler* pSampler) + { + DEV_CHECK_ERR(SeparateSampler.SpirvAttribs.ArraySize == 1 || SeparateSampler.SpirvAttribs.ArraySize == SpirvAttribs.ArraySize, + "Array size (", SeparateSampler.SpirvAttribs.ArraySize,") of separate sampler variable '", + SeparateSampler.SpirvAttribs.Name, "' must be one or same as the array size (", SpirvAttribs.ArraySize, + ") of separate image variable '", SpirvAttribs.Name, "' it is assigned to"); + Uint32 SamplerArrInd = SeparateSampler.SpirvAttribs.ArraySize == 0 ? ArrayIndex : 0; + SeparateSampler.BindResource(pSampler, SamplerArrInd, ResourceCache); + } + ); break; case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: @@ -577,7 +656,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject *pObj, Uint3 { if (DstRes.pObject && SpirvAttribs.VarType != SHADER_VARIABLE_TYPE_DYNAMIC) { - LOG_ERROR_MESSAGE( "Shader variable \"", SpirvAttribs.Name, "\" in shader \"", ParentResLayout.GetShaderName(), "\" is not dynamic but being unbound. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource." ); + LOG_ERROR_MESSAGE( "Shader variable '", SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource." ); } DstRes.pObject.Release(); @@ -628,7 +707,7 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou auto SrcOffset = SrcRes.CacheOffset + ArrInd; IDeviceObject* pObject = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet).GetResource(SrcOffset).pObject; if (!pObject) - LOG_ERROR_MESSAGE("No resource assigned to static shader variable \"", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\"."); + LOG_ERROR_MESSAGE("No resource assigned to static shader variable '", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); auto DstOffset = DstRes.CacheOffset + ArrInd; IDeviceObject* pCachedResource = DstResourceCache.GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject; @@ -659,7 +738,7 @@ void ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& Reso if(CachedRes.pObject == nullptr && !(Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.SpirvAttribs.StaticSamplerInd >= 0)) { - LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.SpirvAttribs.VarType), " variable \"", Res.SpirvAttribs.GetPrintName(ArrInd), "\" in shader \"", GetShaderName(), "\""); + LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.SpirvAttribs.VarType), " variable '", Res.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); } #ifdef _DEBUG auto vkDescSet = CachedDescrSet.GetVkDescriptorSet(); diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp index 10ca267f..e27445f9 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp @@ -28,22 +28,27 @@ #include "RenderDeviceVkImpl.h" #include "DataBlobImpl.h" #include "GLSLSourceBuilder.h" -#include "GLSL2SPIRV.h" - -using namespace Diligent; +#include "SPIRVUtils.h" namespace Diligent { - ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pRenderDeviceVk, const ShaderCreationAttribs& CreationAttribs) : - TShaderBase(pRefCounters, pRenderDeviceVk, CreationAttribs.Desc), - m_StaticResLayout(*this, pRenderDeviceVk->GetLogicalDevice()), - m_StaticResCache(ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources), - m_StaticVarsMgr(*this) + TShaderBase (pRefCounters, pRenderDeviceVk, CreationAttribs.Desc), + m_StaticResLayout (*this, pRenderDeviceVk->GetLogicalDevice()), + m_StaticResCache (ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources), + m_StaticVarsMgr (*this) { - auto GLSLSource = BuildGLSLSourceString(CreationAttribs, TargetGLSLCompiler::glslang, "#define TARGET_API_VULKAN 1\n"); - m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str(), CreationAttribs.ppCompilerOutput); + if (CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL) + { + m_SPIRV = HLSLtoSPIRV(CreationAttribs, CreationAttribs.ppCompilerOutput); + } + else + { + auto GLSLSource = BuildGLSLSourceString(CreationAttribs, TargetGLSLCompiler::glslang, "#define TARGET_API_VULKAN 1\n"); + m_SPIRV = GLSLtoSPIRV(m_Desc.ShaderType, GLSLSource.c_str(), static_cast(GLSLSource.length()), CreationAttribs.ppCompilerOutput); + } + if (m_SPIRV.empty()) { LOG_ERROR_AND_THROW("Failed to compile shader"); @@ -51,16 +56,16 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* // We cannot create shader module here because resource bindings are assigned when // pipeline state is created - + // Load shader resources - auto &Allocator = GetRawAllocator(); - auto *pRawMem = ALLOCATE(Allocator, "Allocator for ShaderResources", sizeof(SPIRVShaderResources)); - auto *pResources = new (pRawMem) SPIRVShaderResources(Allocator, pRenderDeviceVk, m_SPIRV, m_Desc); + auto& Allocator = GetRawAllocator(); + auto* pRawMem = ALLOCATE(Allocator, "Allocator for ShaderResources", sizeof(SPIRVShaderResources)); + auto* pResources = new (pRawMem) SPIRVShaderResources(Allocator, pRenderDeviceVk, m_SPIRV, m_Desc, CreationAttribs.UseCombinedTextureSamplers ? CreationAttribs.CombinedSamplerSuffix : nullptr); m_pShaderResources.reset(pResources, STDDeleterRawMem(Allocator)); m_StaticResLayout.InitializeStaticResourceLayout(m_pShaderResources, GetRawAllocator(), m_StaticResCache); // m_StaticResLayout only contains static resources, so reference all of them - m_StaticVarsMgr.Initialize(m_StaticResLayout, GetRawAllocator(), nullptr, 0, m_StaticResCache); + m_StaticVarsMgr.Initialize(m_StaticResLayout, GetRawAllocator(), nullptr, 0, m_StaticResCache); } ShaderVkImpl::~ShaderVkImpl() diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index f084577f..b7f992f4 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -26,7 +26,7 @@ #include "VulkanErrors.h" #include "VulkanUtilities/VulkanInstance.h" #include "VulkanUtilities/VulkanDebug.h" -#include "GLSL2SPIRV.h" +#include "SPIRVUtils.h" namespace VulkanUtilities { -- cgit v1.2.3 From fa7dbbfaf8819f55926285a27f92dfac3fd62a10 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Thu, 25 Oct 2018 20:58:06 -0700 Subject: Fixed false warning about missing static samplers in VK --- Graphics/GLSLTools/src/SPIRVShaderResources.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp index 6b348981..b0b7055f 100644 --- a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp +++ b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp @@ -330,22 +330,21 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, { const auto* SamName = shaderDesc.StaticSamplers[s].SamplerOrTextureName; bool SamplerFound = false; - if (CombinedSamplerSuffix != nullptr) + + for (Uint32 i = 0; i < GetNumSmpldImgs(); ++i) { - for (Uint32 i = 0; i < GetNumSmpldImgs(); ++i) - { - const auto& SmplImg = GetSmpldImg(i); - SamplerFound = (strcmp(SmplImg.Name, SamName) == 0); - if (SamplerFound) - break; - } + const auto& SmplImg = GetSmpldImg(i); + SamplerFound = (strcmp(SmplImg.Name, SamName) == 0); + if (SamplerFound) + break; } - else + + if (!SamplerFound) { for (Uint32 i = 0; i < GetNumSepSmplrs(); ++i) { const auto& SepSmpl = GetSepSmplr(i); - SamplerFound = (strcmp(SepSmpl.Name, SamName) == 0); + SamplerFound = StreqSuff(SepSmpl.Name, SamName, CombinedSamplerSuffix); if (SamplerFound) break; } -- cgit v1.2.3 From 93babb02154b7afbed469904a03acd6666d46ec1 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Thu, 25 Oct 2018 21:22:17 -0700 Subject: Added HLSL definitions to SPIRV compiler + fixed bug in SPIRV shader resources --- Graphics/GLSLTools/src/SPIRVShaderResources.cpp | 4 ++-- Graphics/GLSLTools/src/SPIRVUtils.cpp | 16 +++++++++++++--- Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp index b0b7055f..524a96c6 100644 --- a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp +++ b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp @@ -130,8 +130,8 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, ResCounters.NumImgs = static_cast(resources.storage_images.size()); ResCounters.NumSmpldImgs = static_cast(resources.sampled_images.size()); ResCounters.NumACs = static_cast(resources.atomic_counters.size()); - ResCounters.NumSepImgs = static_cast(resources.separate_samplers.size()); - ResCounters.NumSepSmplrs = static_cast(resources.separate_images.size()); + ResCounters.NumSepSmplrs = static_cast(resources.separate_samplers.size()); + ResCounters.NumSepImgs = static_cast(resources.separate_images.size()); Initialize(Allocator, ResCounters, shaderDesc.NumStaticSamplers, ResourceNamesPoolSize); { diff --git a/Graphics/GLSLTools/src/SPIRVUtils.cpp b/Graphics/GLSLTools/src/SPIRVUtils.cpp index 64eae1b4..a45eaf76 100644 --- a/Graphics/GLSLTools/src/SPIRVUtils.cpp +++ b/Graphics/GLSLTools/src/SPIRVUtils.cpp @@ -46,6 +46,11 @@ #include "DataBlobImpl.h" #include "RefCntAutoPtr.h" +static const char g_HLSLDefinitions[] = +{ + #include "../../GraphicsEngineD3DBase/include/HLSLDefinitions_inc.fxh" +}; + namespace Diligent { @@ -412,14 +417,13 @@ std::vector HLSLtoSPIRV(const ShaderCreationAttribs& Attribs, IDat glslang::TShader Shader(ShLang); TBuiltInResource Resources = InitResources(); - EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); + EShMessages messages = (EShMessages)(EShMsgReadHlsl | EShMsgHlslLegalization); VERIFY_EXPR(Attribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL); Shader.setEnvInput(glslang::EShSourceHlsl, ShLang, glslang::EShClientVulkan, 100); Shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); Shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); - messages = (EShMessages)(EShMsgReadHlsl | EShMsgHlslLegalization); Shader.setHlslIoMapping(true); Shader.setSourceEntryPoint(Attribs.EntryPoint); Shader.setEntryPoint("main"); @@ -446,9 +450,15 @@ std::vector HLSLtoSPIRV(const ShaderCreationAttribs& Attribs, IDat } int NumShaderStrings = 0; - constexpr size_t MaxShaderStrings = 2; + constexpr size_t MaxShaderStrings = 3; std::array ShaderStrings; std::array ShaderStringLenghts; + + std::string HLSLDefinitions(g_HLSLDefinitions); + ShaderStrings [NumShaderStrings] = HLSLDefinitions.c_str(); + ShaderStringLenghts[NumShaderStrings] = HLSLDefinitions.length(); + ++NumShaderStrings; + std::string Defines; if (Attribs.Macros != nullptr) { diff --git a/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp b/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp index 0e70d7fa..177d1f3f 100644 --- a/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp +++ b/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp @@ -33,7 +33,7 @@ namespace Diligent { -const Char* g_HLSLDefinitions = +static const Char* g_HLSLDefinitions = { #include "HLSLDefinitions_inc.fxh" }; -- cgit v1.2.3