diff options
| author | azhirnov <zh1dron@gmail.com> | 2021-02-26 19:33:44 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-03-19 00:38:14 +0000 |
| commit | bef8cae7057fad87afc17f94ea57c6c1119ff3ea (patch) | |
| tree | c6d73acaf574b5547a0101efddc5e94563452684 /Graphics/GraphicsEngineOpenGL | |
| parent | Unified pipeline resource compatibility validation in D3D12 and Vk; added mor... (diff) | |
| download | DiligentCore-bef8cae7057fad87afc17f94ea57c6c1119ff3ea.tar.gz DiligentCore-bef8cae7057fad87afc17f94ea57c6c1119ff3ea.zip | |
OpenGL: added resource signature
Diffstat (limited to 'Graphics/GraphicsEngineOpenGL')
30 files changed, 3236 insertions, 2003 deletions
diff --git a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt index 8002e214..6890b22d 100644 --- a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt +++ b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt @@ -13,12 +13,13 @@ set(INCLUDE include/GLContext.hpp include/GLContextState.hpp include/GLObjectWrapper.hpp - include/GLProgramResourceCache.hpp - include/GLPipelineResourceLayout.hpp - include/GLProgramResources.hpp + include/ShaderResourceCacheGL.hpp + include/ShaderVariableGL.hpp + include/ShaderResourcesGL.hpp include/GLTypeConversions.hpp include/pch.h include/PipelineStateGLImpl.hpp + include/PipelineResourceSignatureGLImpl.hpp include/QueryGLImpl.hpp include/RenderDeviceGLImpl.hpp include/RenderPassGLImpl.hpp @@ -67,11 +68,12 @@ set(SOURCE src/FramebufferGLImpl.cpp src/GLContextState.cpp src/GLObjectWrapper.cpp - src/GLProgramResourceCache.cpp - src/GLPipelineResourceLayout.cpp - src/GLProgramResources.cpp + src/ShaderResourceCacheGL.cpp + src/ShaderVariableGL.cpp + src/ShaderResourcesGL.cpp src/GLTypeConversions.cpp src/PipelineStateGLImpl.cpp + src/PipelineResourceSignatureGLImpl.cpp src/QueryGLImpl.cpp src/RenderDeviceGLImpl.cpp src/RenderPassGLImpl.cpp diff --git a/Graphics/GraphicsEngineOpenGL/include/AsyncWritableResource.hpp b/Graphics/GraphicsEngineOpenGL/include/AsyncWritableResource.hpp index a5cdefcb..3802afe1 100644 --- a/Graphics/GraphicsEngineOpenGL/include/AsyncWritableResource.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/AsyncWritableResource.hpp @@ -30,40 +30,63 @@ namespace Diligent { +enum MEMORY_BARRIER : Uint32 +{ + MEMORY_BARRIER_NONE = 0, + MEMORY_BARRIER_ALL = GL_ALL_BARRIER_BITS, + + // Buffer barriers. + // Driver does not handle buffer write access in shader and write/read access to a persistent mapped memory. + MEMORY_BARRIER_VERTEX_BUFFER = GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT, // map/storage -> vertex + MEMORY_BARRIER_INDEX_BUFFER = GL_ELEMENT_ARRAY_BARRIER_BIT, // map/storage -> index + MEMORY_BARRIER_UNIFORM_BUFFER = GL_UNIFORM_BARRIER_BIT, // map/storage -> uniform + MEMORY_BARRIER_BUFFER_UPDATE = GL_BUFFER_UPDATE_BARRIER_BIT, // map/storage -> host read/write/map or copy + MEMORY_BARRIER_CLIENT_MAPPED_BUFFER = GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT, // map/storage -> map, only for persistent mapped memory without GL_MAP_COHERENT_BIT + MEMORY_BARRIER_STORAGE_BUFFER = GL_SHADER_STORAGE_BARRIER_BIT, // map/storage -> storage + MEMORY_BARRIER_INDIRECT_BUFFER = GL_COMMAND_BARRIER_BIT, // map/storage -> indirect + MEMORY_BARRIER_TEXEL_BUFFER = GL_TEXTURE_FETCH_BARRIER_BIT, // map/storage -> texel buffer fetch + MEMORY_BARRIER_PIXEL_BUFFER = GL_PIXEL_BUFFER_BARRIER_BIT, // map/storage -> copy to/from texture + MEMORY_BARRIER_IMAGE_BUFFER = GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, // map/storage -> image buffer + MEMORY_BARRIER_ALL_BUFFER_BARRIERS = + MEMORY_BARRIER_VERTEX_BUFFER | + MEMORY_BARRIER_INDEX_BUFFER | + MEMORY_BARRIER_UNIFORM_BUFFER | + MEMORY_BARRIER_BUFFER_UPDATE | + MEMORY_BARRIER_CLIENT_MAPPED_BUFFER | + MEMORY_BARRIER_STORAGE_BUFFER | + MEMORY_BARRIER_INDIRECT_BUFFER | + MEMORY_BARRIER_TEXEL_BUFFER | + MEMORY_BARRIER_IMAGE_BUFFER, + + + // Texture barriers + MEMORY_BARRIER_TEXTURE_FETCH = GL_TEXTURE_FETCH_BARRIER_BIT, // storage -> fetch + MEMORY_BARRIER_STORAGE_IMAGE = GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, // storage -> storage + MEMORY_BARRIER_TEXTURE_UPDATE = GL_TEXTURE_UPDATE_BARRIER_BIT, // storage -> host read/write or copy + MEMORY_BARRIER_FRAMEBUFFER = GL_FRAMEBUFFER_BARRIER_BIT, // storage -> framebuffer + MEMORY_BARRIER_ALL_TEXTURE_BARRIERS = + MEMORY_BARRIER_TEXTURE_FETCH | + MEMORY_BARRIER_STORAGE_IMAGE | + MEMORY_BARRIER_TEXTURE_UPDATE | + MEMORY_BARRIER_FRAMEBUFFER, +}; +DEFINE_FLAG_ENUM_OPERATORS(MEMORY_BARRIER); + + class AsyncWritableResource { public: AsyncWritableResource() noexcept {} - void SetPendingMemoryBarriers(Uint32 Barriers) { m_PendingMemoryBarriers |= Barriers; } - Uint32 GetPendingMemortBarriers() { return m_PendingMemoryBarriers; } + void SetPendingMemoryBarriers(MEMORY_BARRIER Barriers) { m_PendingMemoryBarriers |= Barriers; } + MEMORY_BARRIER GetPendingMemortBarriers() { return m_PendingMemoryBarriers; } private: friend class GLContextState; - void ResetPendingMemoryBarriers(Uint32 Barriers) { m_PendingMemoryBarriers = Barriers; } - void ClearPendingMemoryBarriers(Uint32 Barriers) { m_PendingMemoryBarriers &= ~Barriers; } - - // Buffer barriers: - // GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT - // GL_ELEMENT_ARRAY_BARRIER_BIT - // GL_UNIFORM_BARRIER_BIT - // GL_BUFFER_UPDATE_BARRIER_BIT - // GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT - // GL_SHADER_STORAGE_BARRIER_BIT - - // Texture barriers: - // GL_TEXTURE_FETCH_BARRIER_BIT - // GL_SHADER_IMAGE_ACCESS_BARRIER_BIT - // GL_PIXEL_BUFFER_BARRIER_BIT - // GL_TEXTURE_UPDATE_BARRIER_BIT - - // Misc barriers: - // GL_FRAMEBUFFER_BARRIER_BIT - // GL_TRANSFORM_FEEDBACK_BARRIER_BIT - // GL_ATOMIC_COUNTER_BARRIER_BIT - // GL_QUERY_BUFFER_BARRIER_BIT + void ResetPendingMemoryBarriers(MEMORY_BARRIER Barriers) { m_PendingMemoryBarriers = Barriers; } + void ClearPendingMemoryBarriers(MEMORY_BARRIER Barriers) { m_PendingMemoryBarriers &= ~Barriers; } - Uint32 m_PendingMemoryBarriers = 0; + MEMORY_BARRIER m_PendingMemoryBarriers = MEMORY_BARRIER_NONE; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.hpp index cd060f30..9074f887 100644 --- a/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.hpp @@ -74,7 +74,7 @@ public: void MapRange(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, Uint32 Offset, Uint32 Length, PVoid& pMappedData); void Unmap(GLContextState& CtxState); - void BufferMemoryBarrier(Uint32 RequiredBarriers, class GLContextState& GLContextState); + void BufferMemoryBarrier(MEMORY_BARRIER RequiredBarriers, class GLContextState& GLContextState); const GLObjectWrappers::GLBufferObj& GetGLHandle() { return m_GlBuffer; } diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp index c59a968a..dc27008f 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp @@ -42,6 +42,7 @@ #include "PipelineStateGLImpl.hpp" #include "BottomLevelASBase.hpp" #include "TopLevelASBase.hpp" +#include "ShaderResourceBindingGLImpl.hpp" namespace Diligent { @@ -272,8 +273,6 @@ public: /// Implementation of IDeviceContextGL::UpdateCurrentGLContext(). virtual bool DILIGENT_CALL_TYPE UpdateCurrentGLContext() override final; - void BindProgramResources(Uint32& NewMemoryBarriers, IShaderResourceBinding* pResBinding); - GLContextState& GetContextState() { return m_ContextState; } void CommitRenderTargets(); @@ -296,10 +295,44 @@ private: __forceinline void PrepareForIndirectDraw(IBuffer* pAttribsBuffer); __forceinline void PostDraw(); + using TBindings = PipelineResourceSignatureGLImpl::TBindings; + void BindProgramResources(MEMORY_BARRIER& NewMemoryBarriers, const ShaderResourceBindingGLImpl* pShaderResBindingGL, TBindings& Bindings); + void BindProgramResources(); + +#ifdef DILIGENT_DEVELOPMENT + void DvpValidateCommittedShaderResources(); +#endif + void BeginSubpass(); void EndSubpass(); - Uint32 m_CommitedResourcesTentativeBarriers = 0; + struct SRBState + { + // Do not use strong references! + std::array<ShaderResourceBindingGLImpl*, MAX_RESOURCE_SIGNATURES> SRBs = {}; + + using Bitfield = Uint8; + static_assert(sizeof(Bitfield) * 8 >= MAX_RESOURCE_SIGNATURES, "not enought space to store MAX_RESOURCE_SIGNATURES bits"); + + Bitfield ActiveSRBMask = 0; // Indicates which SRBs are active in current PSO + Bitfield StaleSRBMask = 0; // Indicates stale SRBs that have descriptor sets that need to be bound + +#ifdef DILIGENT_DEVELOPMENT + bool CommittedResourcesValidated = false; + + // Binding offsets that was used at last BindProgramResources() call. + std::array<TBindings, MAX_RESOURCE_SIGNATURES> BoundResOffsets = {}; +#endif + + SRBState() + {} + + void SetStaleSRBBit(Uint32 Index) { StaleSRBMask |= static_cast<Bitfield>(1u << Index); } + void ClearStaleSRBBit(Uint32 Index) { StaleSRBMask &= static_cast<Bitfield>(~(1u << Index)); } + + } m_BindInfo; + + MEMORY_BARRIER m_CommitedResourcesTentativeBarriers = MEMORY_BARRIER_NONE; std::vector<class TextureBaseGL*> m_BoundWritableTextures; std::vector<class BufferGLImpl*> m_BoundWritableBuffers; diff --git a/Graphics/GraphicsEngineOpenGL/include/GLContextState.hpp b/Graphics/GraphicsEngineOpenGL/include/GLContextState.hpp index 31e08912..084125a3 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLContextState.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/GLContextState.hpp @@ -31,6 +31,7 @@ #include "GLObjectWrapper.hpp" #include "UniqueIdentifier.hpp" #include "GLContext.hpp" +#include "AsyncWritableResource.hpp" namespace Diligent { @@ -55,8 +56,8 @@ public: void BindImage (Uint32 Index, class BufferViewGLImpl* pBuffView, GLenum Access, GLenum Format); void BindStorageBlock (Int32 Index, const GLObjectWrappers::GLBufferObj& Buff, GLintptr Offset, GLsizeiptr Size); - void EnsureMemoryBarrier(Uint32 RequiredBarriers, class AsyncWritableResource *pRes = nullptr); - void SetPendingMemoryBarriers(Uint32 PendingBarriers); + void EnsureMemoryBarrier(MEMORY_BARRIER RequiredBarriers, class AsyncWritableResource *pRes = nullptr); + void SetPendingMemoryBarriers(MEMORY_BARRIER PendingBarriers); void EnableDepthTest (bool bEnable); void EnableDepthWrites (bool bEnable); @@ -202,7 +203,7 @@ private: }; std::vector<BoundSSBOInfo> m_BoundStorageBlocks; - Uint32 m_PendingMemoryBarriers = 0; + MEMORY_BARRIER m_PendingMemoryBarriers = MEMORY_BARRIER_NONE; class EnableStateHelper { diff --git a/Graphics/GraphicsEngineOpenGL/include/GLStubsAndroid.h b/Graphics/GraphicsEngineOpenGL/include/GLStubsAndroid.h index cedc6e6c..e413d0a6 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLStubsAndroid.h +++ b/Graphics/GraphicsEngineOpenGL/include/GLStubsAndroid.h @@ -516,6 +516,10 @@ extern PFNGLMEMORYBARRIERPROC glMemoryBarrier; # define GL_ARB_shader_image_load_store 1 #endif +#ifndef GL_MAX_IMAGE_UNITS +# define GL_MAX_IMAGE_UNITS 0x8F38 +#endif + #ifndef GL_ARB_shader_storage_buffer_object # define GL_ARB_shader_storage_buffer_object 1 #endif diff --git a/Graphics/GraphicsEngineOpenGL/include/PipelineResourceSignatureGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/PipelineResourceSignatureGLImpl.hpp new file mode 100644 index 00000000..852e24e6 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/include/PipelineResourceSignatureGLImpl.hpp @@ -0,0 +1,222 @@ +/* + * Copyright 2019-2021 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::PipelineResourceSignatureGLImpl class + +#include <array> + +#include "PipelineResourceSignatureBase.hpp" +#include "ShaderResourceCacheGL.hpp" +#include "ShaderResourcesGL.hpp" + +namespace Diligent +{ +class RenderDeviceGLImpl; +class ShaderVariableGL; + +enum BINDING_RANGE : Uint32 +{ + BINDING_RANGE_UNIFORM_BUFFER = 0, + BINDING_RANGE_TEXTURE, + BINDING_RANGE_IMAGE, + BINDING_RANGE_STORAGE_BUFFER, + BINDING_RANGE_COUNT, + BINDING_RANGE_UNKNOWN = ~0u +}; +BINDING_RANGE PipelineResourceToBindingRange(const PipelineResourceDesc& Desc); +const char* GetBindingRangeName(BINDING_RANGE Range); + + +/// Implementation of the Diligent::PipelineResourceSignatureGLImpl class +class PipelineResourceSignatureGLImpl final : public PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceGLImpl> +{ +public: + using TPipelineResourceSignatureBase = PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceGLImpl>; + + PipelineResourceSignatureGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDevice, + const PipelineResourceSignatureDesc& Desc, + bool bIsDeviceInternal = false); + ~PipelineResourceSignatureGLImpl(); + + // sizeof(ResourceAttribs) == 8, x64 + struct ResourceAttribs + { + private: + static constexpr Uint32 _SamplerIndBits = 31; + static constexpr Uint32 _SamplerAssignedBits = 1; + + public: + static constexpr Uint32 InvalidCacheOffset = ~0u; + static constexpr Uint32 InvalidSamplerInd = (1u << _SamplerIndBits) - 1; + + // clang-format off + const Uint32 CacheOffset; // SRB and Signature has the same cache offsets for static resources. + // Binding = m_FirstBinding[Range] + CacheOffset + const Uint32 SamplerInd : _SamplerIndBits; // ImtblSamplerAssigned == true: index of the immutable sampler in m_ImmutableSamplers. + // ImtblSamplerAssigned == false: index of the assigned sampler in m_Desc.Resources. + const Uint32 ImtblSamplerAssigned : _SamplerAssignedBits; // Immutable sampler flag + // clang-format on + + ResourceAttribs(Uint32 _CacheOffset, + Uint32 _SamplerInd, + bool _ImtblSamplerAssigned) noexcept : + // clang-format off + CacheOffset {_CacheOffset }, + SamplerInd {_SamplerInd }, + ImtblSamplerAssigned{_ImtblSamplerAssigned ? 1u : 0u} + // clang-format on + { + VERIFY(SamplerInd == _SamplerInd, "Sampler index (", _SamplerInd, ") exceeds maximum representable value"); + VERIFY(!_ImtblSamplerAssigned || SamplerInd != InvalidSamplerInd, "Immutable sampler assigned, but sampler index is not valid"); + } + + bool IsSamplerAssigned() const { return SamplerInd != InvalidSamplerInd; } + bool IsImmutableSamplerAssigned() const { return ImtblSamplerAssigned != 0; } + }; + + const ResourceAttribs& GetResourceAttribs(Uint32 ResIndex) const + { + VERIFY_EXPR(ResIndex < m_Desc.NumResources); + return m_pResourceAttribs[ResIndex]; + } + + const PipelineResourceDesc& GetResourceDesc(Uint32 ResIndex) const + { + VERIFY_EXPR(ResIndex < m_Desc.NumResources); + return m_Desc.Resources[ResIndex]; + } + + bool HasDynamicResources() const + { + auto IndexRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC); + return IndexRange.second > IndexRange.first; + } + + using TBindings = std::array<Uint32, BINDING_RANGE_COUNT>; + + void ApplyBindings(GLObjectWrappers::GLProgramObj& GLProgram, + class GLContextState& State, + SHADER_TYPE Stages, + const TBindings& Bindings) const; + + void AddBindings(TBindings& Bindings) const; + + /// Implementation of IPipelineResourceSignature::CreateShaderResourceBinding. + virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, + bool InitStaticResources) override final; + + /// Implementation of IPipelineResourceSignature::GetStaticVariableByName. + virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) override final; + + /// Implementation of IPipelineResourceSignature::GetStaticVariableByIndex. + virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final; + + /// Implementation of IPipelineResourceSignature::GetStaticVariableCount. + virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final; + + /// Implementation of IPipelineResourceSignature::BindStaticResources. + virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, + IResourceMapping* pResourceMapping, + Uint32 Flags) override final; + + /// Implementation of IPipelineResourceSignature::IsCompatibleWith. + virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineResourceSignature* pPRS) const override final + { + if (pPRS == nullptr) + { + return GetHash() == 0; + } + return IsCompatibleWith(*ValidatedCast<const PipelineResourceSignatureGLImpl>(pPRS)); + } + + /// Implementation of IPipelineResourceSignature::InitializeStaticSRBResources. + virtual void DILIGENT_CALL_TYPE InitializeStaticSRBResources(IShaderResourceBinding* pSRB) const override final; + + bool IsCompatibleWith(const PipelineResourceSignatureGLImpl& Other) const; + + bool IsIncompatibleWith(const PipelineResourceSignatureGLImpl& Other) const + { + return GetHash() != Other.GetHash() || m_BindingCount != Other.m_BindingCount; + } + + void InitSRBResourceCache(ShaderResourceCacheGL& ResourceCache) const; + +#ifdef DILIGENT_DEVELOPMENT + /// Verifies committed resource attribs using the SPIRV resource attributes from the PSO. + bool DvpValidateCommittedResource(const ShaderResourcesGL::GLResourceAttribs& GLAttribs, + RESOURCE_DIMENSION ResourceDim, + bool IsMultisample, + Uint32 ResIndex, + const ShaderResourceCacheGL& ResourceCache, + const char* ShaderName, + const char* PSOName) const; +#endif + +private: + PipelineResourceSignatureGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDevice, + const PipelineResourceSignatureDesc& Desc, + bool bIsDeviceInternal, + int Internal); + + // Copies static resources from the static resource cache to the destination cache + void CopyStaticResources(ShaderResourceCacheGL& ResourceCache) const; + + void CreateLayouts(); + + void Destruct(); + + size_t CalculateHash() const; + +private: + TBindings m_BindingCount = {}; + + ResourceAttribs* m_pResourceAttribs = nullptr; // [m_Desc.NumResources] + + // Resource cache for static resource variables only + ShaderResourceCacheGL* m_pStaticResCache = nullptr; + + ShaderVariableGL* m_StaticVarsMgrs = nullptr; // [GetNumStaticResStages()] + + using SamplerPtr = RefCntAutoPtr<ISampler>; + SamplerPtr* m_ImmutableSamplers = nullptr; // [m_Desc.NumImmutableSamplers] +}; + + +__forceinline void PipelineResourceSignatureGLImpl::AddBindings(TBindings& Bindings) const +{ + for (Uint32 i = 0; i < Bindings.size(); ++i) + { + Bindings[i] += m_BindingCount[i]; + } +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp index 554ed41c..40c536e6 100644 --- a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.hpp @@ -34,10 +34,9 @@ #include "GLObjectWrapper.hpp" #include "GLContext.hpp" #include "RenderDeviceGLImpl.hpp" -#include "GLProgramResources.hpp" -#include "GLPipelineResourceLayout.hpp" -#include "GLProgramResourceCache.hpp" +#include "ShaderVariableGL.hpp" #include "ShaderGLImpl.hpp" +#include "PipelineResourceSignatureGLImpl.hpp" namespace Diligent { @@ -63,79 +62,126 @@ public: /// Queries the specific interface, see IObject::QueryInterface() for details virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override; - /// Implementation of IPipelineState::BindStaticResources() in OpenGL backend. - virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, - IResourceMapping* pResourceMapping, - Uint32 Flags) override final; + /// Implementation of IPipelineState::GetResourceSignatureCount() in OpenGL backend. + virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_SignatureCount; } - /// Implementation of IPipelineState::GetStaticVariableCount() in OpenGL backend. - virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final; - - /// Implementation of IPipelineState::GetStaticVariableByName() in OpenGL backend. - virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) override final; - - /// Implementation of IPipelineState::GetStaticVariableByIndex() in OpenGL backend. - virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final; - - /// Implementation of IPipelineState::CreateShaderResourceBinding() in OpenGL backend. - virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, - bool InitStaticResources) override final; + /// Implementation of IPipelineState::GetResourceSignature() in OpenGL backend. + virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final + { + VERIFY_EXPR(Index < m_SignatureCount); + return m_Signatures[Index].RawPtr<IPipelineResourceSignature>(); + } /// Implementation of IPipelineState::IsCompatibleWith() in OpenGL backend. virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final; void CommitProgram(GLContextState& State); - void InitializeSRBResourceCache(GLProgramResourceCache& ResourceCache) const; + Uint32 GetSignatureCount() const { return m_SignatureCount; } - const GLPipelineResourceLayout& GetResourceLayout() const { return m_ResourceLayout; } - const GLPipelineResourceLayout& GetStaticResourceLayout() const { return m_StaticResourceLayout; } - const GLProgramResourceCache& GetStaticResourceCache() const { return m_StaticResourceCache; } + PipelineResourceSignatureGLImpl* GetSignature(Uint32 index) const + { + VERIFY_EXPR(index < m_SignatureCount); + return m_Signatures[index].RawPtr<PipelineResourceSignatureGLImpl>(); + } + +#ifdef DILIGENT_DEVELOPMENT + using TBindings = PipelineResourceSignatureGLImpl::TBindings; + void DvpVerifySRBResources(class ShaderResourceBindingGLImpl* pSRBs[], const TBindings BoundResOffsets[], Uint32 NumSRBs) const; +#endif private: - GLObjectWrappers::GLPipelineObj& GetGLProgramPipeline(GLContext::NativeGLContextType Context); + using ShaderStageInfo = ShaderGLImpl::ShaderStageInfo; + using TShaderStages = std::vector<ShaderStageInfo>; - void InitImmutableSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache) const; + GLObjectWrappers::GLPipelineObj& GetGLProgramPipeline(GLContext::NativeGLContextType Context); template <typename PSOCreateInfoType> - void Initialize(const PSOCreateInfoType& CreateInfo, std::vector<ShaderGLImpl*>& Shaders); + void InitInternalObjects(const PSOCreateInfoType& CreateInfo, const TShaderStages& ShaderStages); + + void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + const TShaderStages& ShaderStages, + SHADER_TYPE ActiveStages); - void InitResourceLayouts(std::vector<ShaderGLImpl*>& Shaders, - FixedLinearAllocator& MemPool); + void CreateDefaultSignature(const PipelineStateCreateInfo& CreateInfo, + const TShaderStages& ShaderStages, + SHADER_TYPE ActiveStages, + IPipelineResourceSignature** ppSignature); void Destruct(); + SHADER_TYPE GetShaderStageType(Uint32 Index) const; + Uint32 GetNumShaderStages() const { return m_NumPrograms; } + +#ifdef DILIGENT_DEVELOPMENT + struct ResourceAttribution + { + static constexpr Uint32 InvalidSignatureIndex = ~0u; + static constexpr Uint32 InvalidResourceIndex = PipelineResourceSignatureGLImpl::InvalidResourceIndex; + static constexpr Uint32 InvalidSamplerIndex = InvalidImmutableSamplerIndex; + + const PipelineResourceSignatureGLImpl* pSignature = nullptr; + + Uint32 SignatureIndex = InvalidSignatureIndex; + Uint32 ResourceIndex = InvalidResourceIndex; + Uint32 ImmutableSamplerIndex = InvalidSamplerIndex; + + ResourceAttribution() noexcept {} + ResourceAttribution(const PipelineResourceSignatureGLImpl* _pSignature, + Uint32 _SignatureIndex, + Uint32 _ResourceIndex, + Uint32 _ImmutableSamplerIndex = InvalidResourceIndex) noexcept : + pSignature{_pSignature}, + SignatureIndex{_SignatureIndex}, + ResourceIndex{_ResourceIndex}, + ImmutableSamplerIndex{_ImmutableSamplerIndex} + { + VERIFY_EXPR(pSignature == nullptr || pSignature->GetDesc().BindingIndex == SignatureIndex); + VERIFY_EXPR((ResourceIndex == InvalidResourceIndex) || (ImmutableSamplerIndex == InvalidSamplerIndex)); + } + + explicit operator bool() const + { + return SignatureIndex != InvalidSignatureIndex && (ResourceIndex != InvalidResourceIndex || ImmutableSamplerIndex != InvalidSamplerIndex); + } + + bool IsImmutableSampler() const + { + return operator bool() && ImmutableSamplerIndex != InvalidSamplerIndex; + } + }; + ResourceAttribution GetResourceAttribution(const char* Name, SHADER_TYPE Stage) const; + + void DvpValidateShaderResources(const std::shared_ptr<const ShaderResourcesGL>& pShaderResources, const char* ShaderName, SHADER_TYPE ShaderStages); +#endif + +private: // Linked GL programs for every shader stage. Every pipeline needs to have its own programs - // because resource bindings assigned by GLProgramResources::LoadUniforms depend on other + // because resource bindings assigned by PipelineResourceSignatureGLImpl::ApplyBindings depend on other // shader stages. using GLProgramObj = GLObjectWrappers::GLProgramObj; - GLProgramObj* m_GLPrograms = nullptr; // [m_NumShaderStages] + GLProgramObj* m_GLPrograms = nullptr; // [m_NumPrograms] ThreadingTools::LockFlag m_ProgPipelineLockFlag; std::vector<std::pair<GLContext::NativeGLContextType, GLObjectWrappers::GLPipelineObj>> m_GLProgPipelines; - // Resource layout that keeps variables of all types, but does not reference a - // resource cache. - // This layout is used by SRB objects to initialize only mutable and dynamic variables and by - // DeviceContextGLImpl::BindProgramResources to verify resource bindings. - GLPipelineResourceLayout m_ResourceLayout; - - // Resource layout that only keeps static variables - GLPipelineResourceLayout m_StaticResourceLayout; - // Resource cache for static resource variables only - GLProgramResourceCache m_StaticResourceCache; + using SignatureArrayType = std::array<RefCntAutoPtr<PipelineResourceSignatureGLImpl>, MAX_RESOURCE_SIGNATURES>; + SignatureArrayType m_Signatures = {}; + Uint8 m_SignatureCount = 0; - // Program resources for all shader stages in the pipeline - GLProgramResources* m_ProgramResources = nullptr; // [m_NumShaderStages] + Uint8 m_NumPrograms = 0; + bool m_IsProgramPipelineSupported = false; + std::array<SHADER_TYPE, 5> m_ShaderTypes = {}; - Uint32 m_TotalUniformBufferBindings = 0; - Uint32 m_TotalSamplerBindings = 0; - Uint32 m_TotalImageBindings = 0; - Uint32 m_TotalStorageBufferBindings = 0; +#ifdef DILIGENT_DEVELOPMENT + // Shader resources for all shaders in all shader stages in the pipeline. + std::vector<std::shared_ptr<const ShaderResourcesGL>> m_ShaderResources; + std::vector<String> m_ShaderNames; - using SamplerPtr = RefCntAutoPtr<ISampler>; - SamplerPtr* m_ImmutableSamplers = nullptr; // [m_Desc.ResourceLayout.NumImmutableSamplers] + // Shader resource attributions for every resource in m_ShaderResources, in the same order. + std::vector<ResourceAttribution> m_ResourceAttibutions; +#endif }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp index 35c12a24..e6d9557f 100644 --- a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.hpp @@ -131,6 +131,14 @@ public: virtual void DILIGENT_CALL_TYPE CreateSBT(const ShaderBindingTableDesc& Desc, IShaderBindingTable** ppSBT) override final; + /// Implementation of IRenderDevice::CreatePipelineResourceSignature() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature) override final; + + void CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature, + bool IsDeviceInternal); + /// Implementation of IRenderDeviceGL::CreateTextureFromGLHandle(). virtual void DILIGENT_CALL_TYPE CreateTextureFromGLHandle(Uint32 GLHandle, Uint32 GLBindTarget, @@ -167,6 +175,15 @@ public: void InitTexRegionRender(); + struct DeviceLimits + { + GLint MaxUniformBlocks; + GLint MaxTextureUnits; + GLint MaxStorageBlock; + GLint MaxImagesUnits; + }; + const DeviceLimits& GetDeviceLimits() const { return m_DeviceLimits; } + protected: friend class DeviceContextGLImpl; friend class TextureBaseGL; @@ -199,6 +216,8 @@ private: void FlagSupportedTexFormats(); int m_ShowDebugGLOutput = 1; + + DeviceLimits m_DeviceLimits = {}; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp index d76cac2f..263d0518 100644 --- a/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.hpp @@ -33,7 +33,7 @@ #include "RenderDevice.h" #include "GLObjectWrapper.hpp" #include "RenderDeviceGLImpl.hpp" -#include "GLProgramResources.hpp" +#include "ShaderResourcesGL.hpp" namespace Diligent { @@ -92,11 +92,20 @@ public: /// Implementation of IShader::GetResource() in OpenGL backend. virtual void DILIGENT_CALL_TYPE GetResourceDesc(Uint32 Index, ShaderResourceDesc& ResourceDesc) const override final; - static GLObjectWrappers::GLProgramObj LinkProgram(ShaderGLImpl** ppShaders, Uint32 NumShaders, bool IsSeparableProgram); + struct ShaderStageInfo + { + ShaderStageInfo(const ShaderGLImpl* _pShader); + + SHADER_TYPE Type = SHADER_TYPE_UNKNOWN; + const ShaderGLImpl* pShader = nullptr; + }; + static GLObjectWrappers::GLProgramObj LinkProgram(const ShaderStageInfo* pShaderStagess, Uint32 NumShaders, bool IsSeparableProgram); + + const std::shared_ptr<const ShaderResourcesGL>& GetShaderResources() const { return m_pShaderResources; } private: - GLObjectWrappers::GLShaderObj m_GLShaderObj; - GLProgramResources m_Resources; + GLObjectWrappers::GLShaderObj m_GLShaderObj; + std::shared_ptr<const ShaderResourcesGL> m_pShaderResources; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.hpp index 1420ed42..6442b7ee 100644 --- a/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.hpp @@ -33,26 +33,22 @@ #include "ShaderResourceBindingGL.h" #include "RenderDeviceGL.h" #include "ShaderResourceBindingBase.hpp" -#include "GLProgramResources.hpp" -#include "ShaderBase.hpp" -#include "GLProgramResourceCache.hpp" -#include "GLPipelineResourceLayout.hpp" +#include "ShaderResourcesGL.hpp" +#include "ShaderResourceCacheGL.hpp" +#include "ShaderVariableGL.hpp" +#include "PipelineResourceSignatureGLImpl.hpp" namespace Diligent { -class PipelineStateGLImpl; - /// Shader resource binding object implementation in OpenGL backend. -class ShaderResourceBindingGLImpl final : public ShaderResourceBindingBase<IShaderResourceBindingGL, PipelineStateGLImpl> +class ShaderResourceBindingGLImpl final : public ShaderResourceBindingBase<IShaderResourceBindingGL, PipelineResourceSignatureGLImpl> { public: - using TBase = ShaderResourceBindingBase<IShaderResourceBindingGL, PipelineStateGLImpl>; + using TBase = ShaderResourceBindingBase<IShaderResourceBindingGL, PipelineResourceSignatureGLImpl>; - ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters, - PipelineStateGLImpl* pPSO, - GLProgramResources* ProgramResources, - Uint32 NumPrograms); + ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters, + PipelineResourceSignatureGLImpl* pPRS); ~ShaderResourceBindingGLImpl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; @@ -71,19 +67,17 @@ public: /// Implementation of IShaderResourceBinding::GetVariableByIndex() in OpenGL backend. virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final; - /// Implementation of IShaderResourceBinding::InitializeStaticResources() in OpenGL backend. - virtual void DILIGENT_CALL_TYPE InitializeStaticResources(const IPipelineState* pPipelineState) override final; - - const GLProgramResourceCache& GetResourceCache(PipelineStateGLImpl* pdbgPSO); + ShaderResourceCacheGL& GetResourceCache() { return m_ShaderResourceCache; } + ShaderResourceCacheGL const& GetResourceCache() const { return m_ShaderResourceCache; } private: - // The resource layout only references mutable and dynamic variables - GLPipelineResourceLayout m_ResourceLayout; + void Destruct(); // The resource cache holds resource bindings for all variables - GLProgramResourceCache m_ResourceCache; + ShaderResourceCacheGL m_ShaderResourceCache; - bool m_bIsStaticResourcesBound = false; + // The resource layout only references mutable and dynamic variables + ShaderVariableGL* m_pShaderVarMgrs = nullptr; // [GetNumShaders()] }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.hpp b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceCacheGL.hpp index ebff4fed..be86d3c3 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceCacheGL.hpp @@ -37,24 +37,31 @@ namespace Diligent /// The class implements a cache that holds resources bound to a specific GL program // All resources are stored in the continuous memory using the following layout: // -// | Cached UBs | Cached Samplers | Cached Images | Cached Storage Blocks | +// | Cached UBs | Cached Textures | Cached Images | Cached Storage Blocks | // |----------------------------------------------------|--------------------------|---------------------------| // | 0 | 1 | ... | UBCount-1 | 0 | 1 | ...| SmpCount-1 | 0 | 1 | ... | ImgCount-1 | 0 | 1 | ... | SBOCount-1 | // ----------------------------------------------------------------------------------------------------------- // -class GLProgramResourceCache +class ShaderResourceCacheGL { public: - GLProgramResourceCache() noexcept + enum class CacheContentType : Uint8 + { + Signature = 0, // The cache is used by the pipeline resource signature to hold static resources. + SRB = 1 // The cache is used by SRB to hold resources of all types (static, mutable, dynamic). + }; + + explicit ShaderResourceCacheGL(CacheContentType ContentType) noexcept : + m_ContentType{ContentType} {} - ~GLProgramResourceCache(); + ~ShaderResourceCacheGL(); // clang-format off - GLProgramResourceCache (const GLProgramResourceCache&) = delete; - GLProgramResourceCache& operator = (const GLProgramResourceCache&) = delete; - GLProgramResourceCache (GLProgramResourceCache&&) = delete; - GLProgramResourceCache& operator = (GLProgramResourceCache&&) = delete; + ShaderResourceCacheGL (const ShaderResourceCacheGL&) = delete; + ShaderResourceCacheGL& operator = (const ShaderResourceCacheGL&) = delete; + ShaderResourceCacheGL (ShaderResourceCacheGL&&) = delete; + ShaderResourceCacheGL& operator = (ShaderResourceCacheGL&&) = delete; // clang-format on /// Describes a resource bound to a uniform buffer or a shader storage block slot @@ -113,123 +120,123 @@ public: }; - static size_t GetRequriedMemorySize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount); + static size_t GetRequriedMemorySize(Uint32 UBCount, Uint32 TextureCount, Uint32 ImageCount, Uint32 SSBOCount); - void Initialize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount, IMemoryAllocator& MemAllocator); + void Initialize(Uint32 UBCount, Uint32 TextureCount, Uint32 ImageCount, Uint32 SSBOCount, IMemoryAllocator& MemAllocator); void Destroy(IMemoryAllocator& MemAllocator); - void SetUniformBuffer(Uint32 Binding, RefCntAutoPtr<BufferGLImpl>&& pBuff) + void SetUniformBuffer(Uint32 CacheOffset, RefCntAutoPtr<BufferGLImpl>&& pBuff) { - GetUB(Binding).pBuffer = std::move(pBuff); + GetUB(CacheOffset).pBuffer = std::move(pBuff); } - void SetTexSampler(Uint32 Binding, RefCntAutoPtr<TextureViewGLImpl>&& pTexView, bool SetSampler) + void SetTexture(Uint32 CacheOffset, RefCntAutoPtr<TextureViewGLImpl>&& pTexView, bool SetSampler) { - GetSampler(Binding).Set(std::move(pTexView), SetSampler); + GetTexture(CacheOffset).Set(std::move(pTexView), SetSampler); } - void SetImmutableSampler(Uint32 Binding, ISampler* pImtblSampler) + void SetSampler(Uint32 CacheOffset, ISampler* pSampler) { - GetSampler(Binding).pSampler = ValidatedCast<SamplerGLImpl>(pImtblSampler); + GetTexture(CacheOffset).pSampler = ValidatedCast<SamplerGLImpl>(pSampler); } - void CopySampler(Uint32 Binding, const CachedResourceView& SrcSam) + void SetTexelBuffer(Uint32 CacheOffset, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView) { - GetSampler(Binding) = SrcSam; + GetTexture(CacheOffset).Set(std::move(pBuffView)); } - void SetBufSampler(Uint32 Binding, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView) + void SetTexImage(Uint32 CacheOffset, RefCntAutoPtr<TextureViewGLImpl>&& pTexView) { - GetSampler(Binding).Set(std::move(pBuffView)); + GetImage(CacheOffset).Set(std::move(pTexView), false); } - void SetTexImage(Uint32 Binding, RefCntAutoPtr<TextureViewGLImpl>&& pTexView) + void SetBufImage(Uint32 CacheOffset, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView) { - GetImage(Binding).Set(std::move(pTexView), false); + GetImage(CacheOffset).Set(std::move(pBuffView)); } - void SetBufImage(Uint32 Binding, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView) + void SetSSBO(Uint32 CacheOffset, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView) { - GetImage(Binding).Set(std::move(pBuffView)); + GetSSBO(CacheOffset).pBufferView = std::move(pBuffView); } - void CopyImage(Uint32 Binding, const CachedResourceView& SrcImg) + void CopyTexture(Uint32 Binding, const CachedResourceView& SrcSam) { - GetImage(Binding) = SrcImg; + GetTexture(Binding) = SrcSam; } - void SetSSBO(Uint32 Binding, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView) + void CopyImage(Uint32 CacheOffset, const CachedResourceView& SrcImg) { - GetSSBO(Binding).pBufferView = std::move(pBuffView); + GetImage(CacheOffset) = SrcImg; } - bool IsUBBound(Uint32 Binding) const + bool IsUBBound(Uint32 CacheOffset) const { - if (Binding >= GetUBCount()) + if (CacheOffset >= GetUBCount()) return false; - const auto& UB = GetConstUB(Binding); + const auto& UB = GetConstUB(CacheOffset); return UB.pBuffer; } - bool IsSamplerBound(Uint32 Binding, bool dbgIsTextureView) const + bool IsTextureBound(Uint32 CacheOffset, bool dbgIsTextureView) const { - if (Binding >= GetSamplerCount()) + if (CacheOffset >= GetTextureCount()) return false; - const auto& Sampler = GetConstSampler(Binding); - VERIFY_EXPR(dbgIsTextureView || Sampler.pTexture == nullptr); - return Sampler.pView; + const auto& Texture = GetConstTexture(CacheOffset); + VERIFY_EXPR(dbgIsTextureView || Texture.pTexture == nullptr); + return Texture.pView; } - bool IsImageBound(Uint32 Binding, bool dbgIsTextureView) const + bool IsImageBound(Uint32 CacheOffset, bool dbgIsTextureView) const { - if (Binding >= GetImageCount()) + if (CacheOffset >= GetImageCount()) return false; - const auto& Image = GetConstImage(Binding); + const auto& Image = GetConstImage(CacheOffset); VERIFY_EXPR(dbgIsTextureView || Image.pTexture == nullptr); return Image.pView; } - bool IsSSBOBound(Uint32 Binding) const + bool IsSSBOBound(Uint32 CacheOffset) const { - if (Binding >= GetSSBOCount()) + if (CacheOffset >= GetSSBOCount()) return false; - const auto& SSBO = GetConstSSBO(Binding); + const auto& SSBO = GetConstSSBO(CacheOffset); return SSBO.pBufferView; } // clang-format off - Uint32 GetUBCount() const { return (m_SmplrsOffset - m_UBsOffset) / sizeof(CachedUB); } - Uint32 GetSamplerCount() const { return (m_ImgsOffset - m_SmplrsOffset) / sizeof(CachedResourceView); } - Uint32 GetImageCount() const { return (m_SSBOsOffset - m_ImgsOffset) / sizeof(CachedResourceView); } - Uint32 GetSSBOCount() const { return (m_MemoryEndOffset - m_SSBOsOffset) / sizeof(CachedSSBO); } + Uint32 GetUBCount() const { return (m_TexturesOffset - m_UBsOffset) / sizeof(CachedUB); } + Uint32 GetTextureCount() const { return (m_ImagesOffset - m_TexturesOffset) / sizeof(CachedResourceView); } + Uint32 GetImageCount() const { return (m_SSBOsOffset - m_ImagesOffset) / sizeof(CachedResourceView); } + Uint32 GetSSBOCount() const { return (m_MemoryEndOffset - m_SSBOsOffset) / sizeof(CachedSSBO); } // clang-format on - const CachedUB& GetConstUB(Uint32 Binding) const + const CachedUB& GetConstUB(Uint32 CacheOffset) const { - VERIFY(Binding < GetUBCount(), "Uniform buffer binding (", Binding, ") is out of range"); - return reinterpret_cast<CachedUB*>(m_pResourceData + m_UBsOffset)[Binding]; + VERIFY(CacheOffset < GetUBCount(), "Uniform buffer index (", CacheOffset, ") is out of range"); + return reinterpret_cast<CachedUB*>(m_pResourceData + m_UBsOffset)[CacheOffset]; } - const CachedResourceView& GetConstSampler(Uint32 Binding) const + const CachedResourceView& GetConstTexture(Uint32 CacheOffset) const { - VERIFY(Binding < GetSamplerCount(), "Sampler binding (", Binding, ") is out of range"); - return reinterpret_cast<CachedResourceView*>(m_pResourceData + m_SmplrsOffset)[Binding]; + VERIFY(CacheOffset < GetTextureCount(), "Texture index (", CacheOffset, ") is out of range"); + return reinterpret_cast<CachedResourceView*>(m_pResourceData + m_TexturesOffset)[CacheOffset]; } - const CachedResourceView& GetConstImage(Uint32 Binding) const + const CachedResourceView& GetConstImage(Uint32 CacheOffset) const { - VERIFY(Binding < GetImageCount(), "Image buffer binding (", Binding, ") is out of range"); - return reinterpret_cast<CachedResourceView*>(m_pResourceData + m_ImgsOffset)[Binding]; + VERIFY(CacheOffset < GetImageCount(), "Image buffer index (", CacheOffset, ") is out of range"); + return reinterpret_cast<CachedResourceView*>(m_pResourceData + m_ImagesOffset)[CacheOffset]; } - const CachedSSBO& GetConstSSBO(Uint32 Binding) const + const CachedSSBO& GetConstSSBO(Uint32 CacheOffset) const { - VERIFY(Binding < GetSSBOCount(), "Shader storage block binding (", Binding, ") is out of range"); - return reinterpret_cast<CachedSSBO*>(m_pResourceData + m_SSBOsOffset)[Binding]; + VERIFY(CacheOffset < GetSSBOCount(), "Shader storage block index (", CacheOffset, ") is out of range"); + return reinterpret_cast<CachedSSBO*>(m_pResourceData + m_SSBOsOffset)[CacheOffset]; } bool IsInitialized() const @@ -237,40 +244,56 @@ public: return m_MemoryEndOffset != InvalidResourceOffset; } + CacheContentType GetContentType() const { return m_ContentType; } + +#ifdef DILIGENT_DEVELOPMENT + void SetStaticResourcesInitialized() + { + m_bStaticResourcesInitialized = true; + } + bool StaticResourcesInitialized() const { return m_bStaticResourcesInitialized; } +#endif + private: - CachedUB& GetUB(Uint32 Binding) + CachedUB& GetUB(Uint32 CacheOffset) { - return const_cast<CachedUB&>(const_cast<const GLProgramResourceCache*>(this)->GetConstUB(Binding)); + return const_cast<CachedUB&>(const_cast<const ShaderResourceCacheGL*>(this)->GetConstUB(CacheOffset)); } - CachedResourceView& GetSampler(Uint32 Binding) + CachedResourceView& GetTexture(Uint32 CacheOffset) { - return const_cast<CachedResourceView&>(const_cast<const GLProgramResourceCache*>(this)->GetConstSampler(Binding)); + return const_cast<CachedResourceView&>(const_cast<const ShaderResourceCacheGL*>(this)->GetConstTexture(CacheOffset)); } - CachedResourceView& GetImage(Uint32 Binding) + CachedResourceView& GetImage(Uint32 CacheOffset) { - return const_cast<CachedResourceView&>(const_cast<const GLProgramResourceCache*>(this)->GetConstImage(Binding)); + return const_cast<CachedResourceView&>(const_cast<const ShaderResourceCacheGL*>(this)->GetConstImage(CacheOffset)); } - CachedSSBO& GetSSBO(Uint32 Binding) + CachedSSBO& GetSSBO(Uint32 CacheOffset) { - return const_cast<CachedSSBO&>(const_cast<const GLProgramResourceCache*>(this)->GetConstSSBO(Binding)); + return const_cast<CachedSSBO&>(const_cast<const ShaderResourceCacheGL*>(this)->GetConstSSBO(CacheOffset)); } static constexpr const Uint16 InvalidResourceOffset = 0xFFFF; static constexpr const Uint16 m_UBsOffset = 0; - Uint16 m_SmplrsOffset = InvalidResourceOffset; - Uint16 m_ImgsOffset = InvalidResourceOffset; + Uint16 m_TexturesOffset = InvalidResourceOffset; + Uint16 m_ImagesOffset = InvalidResourceOffset; Uint16 m_SSBOsOffset = InvalidResourceOffset; Uint16 m_MemoryEndOffset = InvalidResourceOffset; Uint8* m_pResourceData = nullptr; + // Indicates what types of resources are stored in the cache + const CacheContentType m_ContentType; + #ifdef DILIGENT_DEBUG IMemoryAllocator* m_pdbgMemoryAllocator = nullptr; #endif +#ifdef DILIGENT_DEVELOPMENT + bool m_bStaticResourcesInitialized = false; +#endif }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.hpp b/Graphics/GraphicsEngineOpenGL/include/ShaderResourcesGL.hpp index 5b60cec2..602bd107 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/ShaderResourcesGL.hpp @@ -27,12 +27,12 @@ #pragma once -// GLProgramResources class allocates single continuous chunk of memory to store all program resources, as follows: +// ShaderResourcesGL class allocates single continuous chunk of memory to store all program resources, as follows: // // -// m_UniformBuffers m_Samplers m_Images m_StorageBlocks +// m_UniformBuffers m_Textures m_Images m_StorageBlocks // | | | | | | -// | UB[0] ... UB[Nu-1] | Sam[0] ... Sam[Ns-1] | Img[0] ... Img[Ni-1] | SB[0] ... SB[Nsb-1] | Resource Names | +// | UB[0] ... UB[Nu-1] | Tex[0] ... Tex[Ns-1] | Img[0] ... Img[Ni-1] | SB[0] ... SB[Nsb-1] | Resource Names | // // Nu - number of uniform buffers // Ns - number of samplers @@ -49,27 +49,23 @@ namespace Diligent { -class GLProgramResources +class ShaderResourcesGL { public: - GLProgramResources() {} - ~GLProgramResources(); + ShaderResourcesGL() {} + ~ShaderResourcesGL(); // clang-format off - GLProgramResources (GLProgramResources&& Program)noexcept; + ShaderResourcesGL (ShaderResourcesGL&& Program)noexcept; - GLProgramResources (const GLProgramResources&) = delete; - GLProgramResources& operator = (const GLProgramResources&) = delete; - GLProgramResources& operator = ( GLProgramResources&&) = delete; + ShaderResourcesGL (const ShaderResourcesGL&) = delete; + ShaderResourcesGL& operator = (const ShaderResourcesGL&) = delete; + ShaderResourcesGL& operator = ( ShaderResourcesGL&&) = delete; // clang-format on /// Loads program uniforms and assigns bindings void LoadUniforms(SHADER_TYPE ShaderStages, const GLObjectWrappers::GLProgramObj& GLProgram, - class GLContextState& State, - Uint32& UniformBufferBinding, - Uint32& SamplerBinding, - Uint32& ImageBinding, - Uint32& StorageBufferBinding); + class GLContextState& State); struct GLResourceAttribs { @@ -77,21 +73,18 @@ public: /* 0 */ const Char* Name; /* 8 */ const SHADER_TYPE ShaderStages; /* 12 */ const SHADER_RESOURCE_TYPE ResourceType; -/* 16 */ const Uint32 Binding; -/* 20 */ Uint32 ArraySize; -/* 24 */ // End of data +/* 16 */ Uint32 ArraySize; +/* 20 */ // End of data // clang-format on GLResourceAttribs(const Char* _Name, SHADER_TYPE _ShaderStages, SHADER_RESOURCE_TYPE _ResourceType, - Uint32 _Binding, Uint32 _ArraySize) noexcept : // clang-format off Name {_Name }, ShaderStages {_ShaderStages}, ResourceType {_ResourceType}, - Binding {_Binding }, ArraySize {_ArraySize } // clang-format on { @@ -108,37 +101,12 @@ public: NamesPool.CopyString(Attribs.Name), Attribs.ShaderStages, Attribs.ResourceType, - Attribs.Binding, Attribs.ArraySize } // clang-format on { } - bool IsCompatibleWith(const GLResourceAttribs& Var)const - { - // clang-format off - return ShaderStages == Var.ShaderStages && - ResourceType == Var.ResourceType && - Binding == Var.Binding && - ArraySize == Var.ArraySize; - // clang-format on - } - - size_t GetHash() const - { - return ComputeHash(static_cast<Uint32>(ShaderStages), static_cast<Uint32>(ResourceType), Binding, ArraySize); - } - - String GetPrintName(Uint32 ArrayInd) const - { - VERIFY_EXPR(ArrayInd < ArraySize); - if (ArraySize > 1) - return String(Name) + '[' + std::to_string(ArrayInd) + ']'; - else - return Name; - } - ShaderResourceDesc GetResourceDesc() const { ShaderResourceDesc ResourceDesc; @@ -147,16 +115,6 @@ public: ResourceDesc.Type = ResourceType; return ResourceDesc; } - - RESOURCE_DIMENSION GetResourceDimension() const - { - return RESOURCE_DIM_UNDEFINED; - } - - bool IsMultisample() const - { - return false; - } }; struct UniformBufferInfo final : GLResourceAttribs @@ -170,10 +128,9 @@ public: UniformBufferInfo(const Char* _Name, SHADER_TYPE _ShaderStages, SHADER_RESOURCE_TYPE _ResourceType, - Uint32 _Binding, Uint32 _ArraySize, GLuint _UBIndex)noexcept : - GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _Binding, _ArraySize}, + GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _ArraySize}, UBIndex {_UBIndex} {} @@ -184,66 +141,46 @@ public: {} // clang-format on - bool IsCompatibleWith(const UniformBufferInfo& UB) const - { - return UBIndex == UB.UBIndex && - GLResourceAttribs::IsCompatibleWith(UB); - } - - size_t GetHash() const - { - return ComputeHash(UBIndex, GLResourceAttribs::GetHash()); - } - const GLuint UBIndex; }; static_assert((sizeof(UniformBufferInfo) % sizeof(void*)) == 0, "sizeof(UniformBufferInfo) must be multiple of sizeof(void*)"); - struct SamplerInfo final : GLResourceAttribs + struct TextureInfo final : GLResourceAttribs { // clang-format off - SamplerInfo (const SamplerInfo&) = delete; - SamplerInfo& operator= (const SamplerInfo&) = delete; - SamplerInfo ( SamplerInfo&&) = default; - SamplerInfo& operator= ( SamplerInfo&&) = delete; - - SamplerInfo(const Char* _Name, - SHADER_TYPE _ShaderStages, - SHADER_RESOURCE_TYPE _ResourceType, - Uint32 _Binding, - Uint32 _ArraySize, - GLint _Location, - GLenum _SamplerType)noexcept : - GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _Binding, _ArraySize}, - Location {_Location }, - SamplerType {_SamplerType} + TextureInfo (const TextureInfo&) = delete; + TextureInfo& operator= (const TextureInfo&) = delete; + TextureInfo ( TextureInfo&&) = default; + TextureInfo& operator= ( TextureInfo&&) = delete; + + TextureInfo(const Char* _Name, + SHADER_TYPE _ShaderStages, + SHADER_RESOURCE_TYPE _ResourceType, + Uint32 _ArraySize, + GLenum _TextureType, + RESOURCE_DIMENSION _ResourceDim, + bool _IsMultisample) noexcept : + GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _ArraySize}, + TextureType {_TextureType}, + ResourceDim {_ResourceDim}, + IsMultisample {_IsMultisample} {} - SamplerInfo(const SamplerInfo& Sam, - StringPool& NamesPool)noexcept : - GLResourceAttribs{Sam, NamesPool}, - Location {Sam.Location }, - SamplerType {Sam.SamplerType} + TextureInfo(const TextureInfo& Tex, + StringPool& NamesPool) noexcept : + GLResourceAttribs{Tex, NamesPool}, + TextureType {Tex.TextureType}, + ResourceDim {Tex.ResourceDim}, + IsMultisample {Tex.IsMultisample} {} - - bool IsCompatibleWith(const SamplerInfo& Sam)const - { - return Location == Sam.Location && - SamplerType == Sam.SamplerType && - GLResourceAttribs::IsCompatibleWith(Sam); - } // clang-format on - size_t GetHash() const - { - return ComputeHash(Location, SamplerType, GLResourceAttribs::GetHash()); - } - - const GLint Location; - const GLenum SamplerType; + const GLenum TextureType; + const RESOURCE_DIMENSION ResourceDim; + const bool IsMultisample; }; - static_assert((sizeof(SamplerInfo) % sizeof(void*)) == 0, "sizeof(SamplerInfo) must be multiple of sizeof(void*)"); + static_assert((sizeof(TextureInfo) % sizeof(void*)) == 0, "sizeof(TextureInfo) must be multiple of sizeof(void*)"); struct ImageInfo final : GLResourceAttribs @@ -257,37 +194,28 @@ public: ImageInfo(const Char* _Name, SHADER_TYPE _ShaderStages, SHADER_RESOURCE_TYPE _ResourceType, - Uint32 _Binding, Uint32 _ArraySize, - GLint _Location, - GLenum _ImageType)noexcept : - GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _Binding, _ArraySize}, - Location {_Location }, - ImageType {_ImageType} + GLenum _ImageType, + RESOURCE_DIMENSION _ResourceDim, + bool _IsMultisample) noexcept : + GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _ArraySize}, + ImageType {_ImageType}, + ResourceDim {_ResourceDim}, + IsMultisample {_IsMultisample} {} ImageInfo(const ImageInfo& Img, - StringPool& NamesPool)noexcept : + StringPool& NamesPool) noexcept : GLResourceAttribs{Img, NamesPool}, - Location {Img.Location }, - ImageType {Img.ImageType} + ImageType {Img.ImageType}, + ResourceDim {Img.ResourceDim}, + IsMultisample {Img.IsMultisample} {} - - bool IsCompatibleWith(const ImageInfo& Img)const - { - return Location == Img.Location && - ImageType == Img.ImageType && - GLResourceAttribs::IsCompatibleWith(Img); - } // clang-format on - size_t GetHash() const - { - return ComputeHash(Location, ImageType, GLResourceAttribs::GetHash()); - } - - const GLint Location; - const GLenum ImageType; + const GLenum ImageType; + const RESOURCE_DIMENSION ResourceDim; + const bool IsMultisample; }; static_assert((sizeof(ImageInfo) % sizeof(void*)) == 0, "sizeof(ImageInfo) must be multiple of sizeof(void*)"); @@ -303,10 +231,9 @@ public: StorageBlockInfo(const Char* _Name, SHADER_TYPE _ShaderStages, SHADER_RESOURCE_TYPE _ResourceType, - Uint32 _Binding, Uint32 _ArraySize, GLint _SBIndex)noexcept : - GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _Binding, _ArraySize}, + GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _ArraySize}, SBIndex {_SBIndex} {} @@ -315,19 +242,8 @@ public: GLResourceAttribs{SB, NamesPool}, SBIndex {SB.SBIndex} {} - - bool IsCompatibleWith(const StorageBlockInfo& SB)const - { - return SBIndex == SB.SBIndex && - GLResourceAttribs::IsCompatibleWith(SB); - } // clang-format on - size_t GetHash() const - { - return ComputeHash(SBIndex, GLResourceAttribs::GetHash()); - } - const GLint SBIndex; }; static_assert((sizeof(StorageBlockInfo) % sizeof(void*)) == 0, "sizeof(StorageBlockInfo) must be multiple of sizeof(void*)"); @@ -335,7 +251,7 @@ public: // clang-format off Uint32 GetNumUniformBuffers()const { return m_NumUniformBuffers; } - Uint32 GetNumSamplers() const { return m_NumSamplers; } + Uint32 GetNumTextures() const { return m_NumTextures; } Uint32 GetNumImages() const { return m_NumImages; } Uint32 GetNumStorageBlocks() const { return m_NumStorageBlocks; } // clang-format on @@ -346,10 +262,10 @@ public: return m_UniformBuffers[Index]; } - SamplerInfo& GetSampler(Uint32 Index) + TextureInfo& GetTexture(Uint32 Index) { - VERIFY(Index < m_NumSamplers, "Sampler index (", Index, ") is out of range"); - return m_Samplers[Index]; + VERIFY(Index < m_NumTextures, "Texture index (", Index, ") is out of range"); + return m_Textures[Index]; } ImageInfo& GetImage(Uint32 Index) @@ -371,10 +287,10 @@ public: return m_UniformBuffers[Index]; } - const SamplerInfo& GetSampler(Uint32 Index) const + const TextureInfo& GetTexture(Uint32 Index) const { - VERIFY(Index < m_NumSamplers, "Sampler index (", Index, ") is out of range"); - return m_Samplers[Index]; + VERIFY(Index < m_NumTextures, "Texture index (", Index, ") is out of range"); + return m_Textures[Index]; } const ImageInfo& GetImage(Uint32 Index) const @@ -391,22 +307,19 @@ public: Uint32 GetVariableCount() const { - return m_NumUniformBuffers + m_NumSamplers + m_NumImages + m_NumStorageBlocks; + return m_NumUniformBuffers + m_NumTextures + m_NumImages + m_NumStorageBlocks; } ShaderResourceDesc GetResourceDesc(Uint32 Index) const; - bool IsCompatibleWith(const GLProgramResources& Res) const; - size_t GetHash() const; - SHADER_TYPE GetShaderStages() const { return m_ShaderStages; } template <typename THandleUB, - typename THandleSampler, + typename THandleTexture, typename THandleImg, typename THandleSB> void ProcessConstResources(THandleUB HandleUB, - THandleSampler HandleSampler, + THandleTexture HandleTexture, THandleImg HandleImg, THandleSB HandleSB, const PipelineResourceLayoutDesc* pResourceLayout = nullptr, @@ -433,11 +346,11 @@ public: HandleUB(UB); } - for (Uint32 s = 0; s < m_NumSamplers; ++s) + for (Uint32 s = 0; s < m_NumTextures; ++s) { - const auto& Sam = GetSampler(s); + const auto& Sam = GetTexture(s); if (CheckResourceType(Sam.Name)) - HandleSampler(Sam); + HandleTexture(Sam); } for (Uint32 img = 0; img < m_NumImages; ++img) @@ -456,19 +369,19 @@ public: } template <typename THandleUB, - typename THandleSampler, + typename THandleTexture, typename THandleImg, typename THandleSB> void ProcessResources(THandleUB HandleUB, - THandleSampler HandleSampler, + THandleTexture HandleTexture, THandleImg HandleImg, THandleSB HandleSB) { for (Uint32 ub = 0; ub < m_NumUniformBuffers; ++ub) HandleUB(GetUniformBuffer(ub)); - for (Uint32 s = 0; s < m_NumSamplers; ++s) - HandleSampler(GetSampler(s)); + for (Uint32 s = 0; s < m_NumTextures; ++s) + HandleTexture(GetTexture(s)); for (Uint32 img = 0; img < m_NumImages; ++img) HandleImg(GetImage(img)); @@ -477,22 +390,9 @@ public: HandleSB(GetStorageBlock(sb)); } - struct ResourceCounters - { - Uint32 NumUBs = 0; - Uint32 NumSamplers = 0; - Uint32 NumImages = 0; - Uint32 NumStorageBlocks = 0; - }; - void CountResources(const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ResourceCounters& Counters) const; - - private: void AllocateResources(std::vector<UniformBufferInfo>& UniformBlocks, - std::vector<SamplerInfo>& Samplers, + std::vector<TextureInfo>& Textures, std::vector<ImageInfo>& Images, std::vector<StorageBlockInfo>& StorageBlocks); @@ -502,20 +402,20 @@ private: // Memory layout: // - // | Uniform buffers | Samplers | Images | Storage Blocks | String Pool Data | + // | Uniform buffers | Textures | Images | Storage Blocks | String Pool Data | // UniformBufferInfo* m_UniformBuffers = nullptr; - SamplerInfo* m_Samplers = nullptr; + TextureInfo* m_Textures = nullptr; ImageInfo* m_Images = nullptr; StorageBlockInfo* m_StorageBlocks = nullptr; Uint32 m_NumUniformBuffers = 0; - Uint32 m_NumSamplers = 0; + Uint32 m_NumTextures = 0; Uint32 m_NumImages = 0; Uint32 m_NumStorageBlocks = 0; // clang-format on - // When adding new member DO NOT FORGET TO UPDATE GLProgramResources( GLProgramResources&& ProgramResources )!!! + // When adding new member DO NOT FORGET TO UPDATE ShaderResourcesGL( ShaderResourcesGL&& ProgramResources )!!! }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.hpp b/Graphics/GraphicsEngineOpenGL/include/ShaderVariableGL.hpp index 701d2492..18fd9665 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/ShaderVariableGL.hpp @@ -27,7 +27,7 @@ #pragma once -// GLPipelineResourceLayout class manages resource bindings for all stages in a pipeline +// ShaderVariableGL class manages resource bindings for all stages in a pipeline // // @@ -38,32 +38,32 @@ // Binding Binding Binding Binding Binding Binding Binding Binding // ___________________ ____|__________|__________________|________|______________|___________|______________|____________|____________ // | | | | | | | | | | | | | | | -// |GLProgramResources |--------------->| UB[0] | UB[1] | ... | Sam[0] | Sam[1] | ... | Img[0] | Img[1] | ... | SSBOs[0] | SSBOs[1] | ... | +// | ShaderResourcesGL |--------------->| UB[0] | UB[1] | ... | Sam[0] | Sam[1] | ... | Img[0] | Img[1] | ... | SSBOs[0] | SSBOs[1] | ... | // |___________________| |__________|__________|_______|________|________|_______|________|________|_______|__________|__________|_______| // A A A A // | | | | // Ref Ref Ref Ref // .-==========================-. _____|____________________________________|________________________|____________________________|______________ // || || | | | | | | | | | | | -// __|| GLPipelineResourceLayout ||------->| UBInfo[0] | UBInfo[1] | ... | SamInfo[0] | SamInfo[1] | ... | ImgInfo[0] | ... | SSBO[0] | ... | +// __|| ShaderVariableGL ||------->| UBInfo[0] | UBInfo[1] | ... | SamInfo[0] | SamInfo[1] | ... | ImgInfo[0] | ... | SSBO[0] | ... | // | || || |___________|___________|_______|____________|____________|_______|____________|_________|___________|__________| // | '-==========================-' / \ // | Ref Ref // | / \ // | ___________________ ________V________________________________________________V_____________________________________________________ // | | | | | | | | | | | | | | | | -// | |GLProgramResources |--------------->| UB[0] | UB[1] | ... | Sam[0] | Sam[1] | ... | Img[0] | Img[1] | ... | SSBOs[0] | SSBOs[1] | ... | +// | | ShaderResourcesGL |--------------->| UB[0] | UB[1] | ... | Sam[0] | Sam[1] | ... | Img[0] | Img[1] | ... | SSBOs[0] | SSBOs[1] | ... | // | |___________________| |__________|__________|_______|________|________|_______|________|________|_______|__________|__________|_______| // | | | | | | | | | // | Binding Binding Binding Binding Binding Binding Binding Binding // | | | | | | | | | // | _______________________ ____V___________V________________V_________V________________V________V________________V___________V_____________ // | | | | | | | | -// '-->|GLProgramResourceCache |----------->| Uinform Buffers | Samplers | Images | Storge Buffers | +// '-->| ShaderResourceCacheGL |----------->| Uinform Buffers | Textures | Images | Storge Buffers | // |_______________________| |___________________________|___________________________|___________________________|___________________________| // // -// Note that GLProgramResources are kept by PipelineStateGLImpl. GLPipelineResourceLayout class is either part of the same PSO class, +// Note that ShaderResourcesGL are kept by PipelineStateGLImpl. ShaderVariableGL class is either part of the same PSO class, // or part of ShaderResourceBindingGLImpl object that keeps a strong reference to the pipeline. So all references from GLVariableBase // are always valid. @@ -71,91 +71,92 @@ #include "Object.h" #include "ShaderResourceVariableBase.hpp" -#include "GLProgramResources.hpp" -#include "GLProgramResourceCache.hpp" +#include "ShaderResourceCacheGL.hpp" +#include "PipelineResourceSignatureGLImpl.hpp" namespace Diligent { -class GLPipelineResourceLayout +// sizeof(ShaderVariableGL) == 48 (x64, msvc, Release) +class ShaderVariableGL { public: - GLPipelineResourceLayout(IObject& Owner) : - m_Owner(Owner) - { - m_ProgramIndex.fill(-1); - } + ShaderVariableGL(IObject& Owner, ShaderResourceCacheGL& ResourceCache) noexcept : + m_Owner(Owner), + m_ResourceCache{ResourceCache} + {} - ~GLPipelineResourceLayout(); + ~ShaderVariableGL(); // No copies, only moves are allowed // clang-format off - GLPipelineResourceLayout (const GLPipelineResourceLayout&) = delete; - GLPipelineResourceLayout& operator = (const GLPipelineResourceLayout&) = delete; - GLPipelineResourceLayout ( GLPipelineResourceLayout&&) = default; - GLPipelineResourceLayout& operator = ( GLPipelineResourceLayout&&) = delete; + ShaderVariableGL (const ShaderVariableGL&) = delete; + ShaderVariableGL& operator = (const ShaderVariableGL&) = delete; + ShaderVariableGL ( ShaderVariableGL&&) = default; + ShaderVariableGL& operator = ( ShaderVariableGL&&) = delete; // clang-format on - void Initialize(GLProgramResources* ProgramResources, - Uint32 NumPrograms, - PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - GLProgramResourceCache* pResourceCache); + void Initialize(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType); - static size_t GetRequiredMemorySize(GLProgramResources* ProgramResources, - Uint32 NumPrograms, - const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes); + static size_t GetRequiredMemorySize(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType); - void CopyResources(GLProgramResourceCache& DstCache) const; + using ResourceAttribs = PipelineResourceSignatureGLImpl::ResourceAttribs; - struct GLVariableBase : public ShaderVariableBase<GLPipelineResourceLayout> + const PipelineResourceDesc& GetResourceDesc(Uint32 Index) const { - using TBase = ShaderVariableBase<GLPipelineResourceLayout>; - GLVariableBase(const GLProgramResources::GLResourceAttribs& ResourceAttribs, - GLPipelineResourceLayout& ParentLayout, - SHADER_RESOURCE_VARIABLE_TYPE VariableType, - Int32 ImtblSamplerIdx) : - // clang-format off - TBase {ParentLayout}, - m_Attribs {ResourceAttribs }, - m_VariableType {VariableType }, - m_ImtblSamplerIdx {ImtblSamplerIdx} - // clang-format on - { - VERIFY_EXPR(ImtblSamplerIdx < 0 || ResourceAttribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); - } + VERIFY_EXPR(m_pSignature); + return m_pSignature->GetResourceDesc(Index); + } + const ResourceAttribs& GetAttribs(Uint32 Index) const + { + VERIFY_EXPR(m_pSignature); + return m_pSignature->GetResourceAttribs(Index); + } + + + struct GLVariableBase : public ShaderVariableBase<ShaderVariableGL> + { + using TBase = ShaderVariableBase<ShaderVariableGL>; + GLVariableBase(ShaderVariableGL& ParentLayout, Uint32 ResIndex) : + TBase{ParentLayout}, + m_ResIndex{ResIndex} + {} + + const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResourceDesc(m_ResIndex); } + const ResourceAttribs& GetAttribs() const { return m_ParentManager.GetAttribs(m_ResIndex); } virtual SHADER_RESOURCE_VARIABLE_TYPE DILIGENT_CALL_TYPE GetType() const override final { - return m_VariableType; + return GetDesc().VarType; } virtual void DILIGENT_CALL_TYPE GetResourceDesc(ShaderResourceDesc& ResourceDesc) const override final { - ResourceDesc = m_Attribs.GetResourceDesc(); + const auto& Desc = GetDesc(); + ResourceDesc.Name = Desc.Name; + ResourceDesc.Type = Desc.ResourceType; + ResourceDesc.ArraySize = Desc.ArraySize; } virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final { - return m_ParentResLayout.GetVariableIndex(*this); + return m_ParentManager.GetVariableIndex(*this); } - const GLProgramResources::GLResourceAttribs& m_Attribs; - const SHADER_RESOURCE_VARIABLE_TYPE m_VariableType; - const Int32 m_ImtblSamplerIdx; + const Uint32 m_ResIndex; }; struct UniformBuffBindInfo final : GLVariableBase { - UniformBuffBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs, - GLPipelineResourceLayout& ParentResLayout, - SHADER_RESOURCE_VARIABLE_TYPE VariableType) : - GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, -1} + UniformBuffBindInfo(ShaderVariableGL& ParentLayout, Uint32 ResIndex) : + GLVariableBase{ParentLayout, ResIndex} {} // Non-virtual function @@ -170,26 +171,24 @@ public: Uint32 FirstElement, Uint32 NumElements) override final { - VerifyAndCorrectSetArrayArguments(m_Attribs.Name, m_Attribs.ArraySize, FirstElement, NumElements); + const auto& Desc = GetDesc(); + VerifyAndCorrectSetArrayArguments(Desc.Name, Desc.ArraySize, FirstElement, NumElements); for (Uint32 elem = 0; elem < NumElements; ++elem) BindResource(ppObjects[elem], FirstElement + elem); } virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final { - VERIFY_EXPR(ArrayIndex < m_Attribs.ArraySize); - return m_ParentResLayout.m_pResourceCache->IsUBBound(m_Attribs.Binding + ArrayIndex); + VERIFY_EXPR(ArrayIndex < GetDesc().ArraySize); + return m_ParentManager.m_ResourceCache.IsUBBound(GetAttribs().CacheOffset + ArrayIndex); } }; struct SamplerBindInfo final : GLVariableBase { - SamplerBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs, - GLPipelineResourceLayout& ParentResLayout, - SHADER_RESOURCE_VARIABLE_TYPE VariableType, - Int32 ImtblSamplerIdx) : - GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, ImtblSamplerIdx} + SamplerBindInfo(ShaderVariableGL& ParentLayout, Uint32 ResIndex) : + GLVariableBase{ParentLayout, ResIndex} {} // Non-virtual function @@ -204,25 +203,24 @@ public: Uint32 FirstElement, Uint32 NumElements) override final { - VerifyAndCorrectSetArrayArguments(m_Attribs.Name, m_Attribs.ArraySize, FirstElement, NumElements); + const auto& Desc = GetDesc(); + VerifyAndCorrectSetArrayArguments(Desc.Name, Desc.ArraySize, FirstElement, NumElements); for (Uint32 elem = 0; elem < NumElements; ++elem) BindResource(ppObjects[elem], FirstElement + elem); } virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final { - VERIFY_EXPR(ArrayIndex < m_Attribs.ArraySize); - return m_ParentResLayout.m_pResourceCache->IsSamplerBound(m_Attribs.Binding + ArrayIndex, m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); + VERIFY_EXPR(ArrayIndex < GetDesc().ArraySize); + return m_ParentManager.m_ResourceCache.IsTextureBound(GetAttribs().CacheOffset + ArrayIndex, GetDesc().ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); } }; struct ImageBindInfo final : GLVariableBase { - ImageBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs, - GLPipelineResourceLayout& ParentResLayout, - SHADER_RESOURCE_VARIABLE_TYPE VariableType) : - GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, -1} + ImageBindInfo(ShaderVariableGL& ParentLayout, Uint32 ResIndex) : + GLVariableBase{ParentLayout, ResIndex} {} // Provide non-virtual function @@ -237,25 +235,24 @@ public: Uint32 FirstElement, Uint32 NumElements) override final { - VerifyAndCorrectSetArrayArguments(m_Attribs.Name, m_Attribs.ArraySize, FirstElement, NumElements); + const auto& Desc = GetDesc(); + VerifyAndCorrectSetArrayArguments(Desc.Name, Desc.ArraySize, FirstElement, NumElements); for (Uint32 elem = 0; elem < NumElements; ++elem) BindResource(ppObjects[elem], FirstElement + elem); } virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final { - VERIFY_EXPR(ArrayIndex < m_Attribs.ArraySize); - return m_ParentResLayout.m_pResourceCache->IsImageBound(m_Attribs.Binding + ArrayIndex, m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV); + VERIFY_EXPR(ArrayIndex < GetDesc().ArraySize); + return m_ParentManager.m_ResourceCache.IsImageBound(GetAttribs().CacheOffset + ArrayIndex, GetDesc().ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV); } }; struct StorageBufferBindInfo final : GLVariableBase { - StorageBufferBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs, - GLPipelineResourceLayout& ParentResLayout, - SHADER_RESOURCE_VARIABLE_TYPE VariableType) : - GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, -1} + StorageBufferBindInfo(ShaderVariableGL& ParentLayout, Uint32 ResIndex) : + GLVariableBase{ParentLayout, ResIndex} {} // Non-virtual function @@ -270,37 +267,38 @@ public: Uint32 FirstElement, Uint32 NumElements) override final { - VerifyAndCorrectSetArrayArguments(m_Attribs.Name, m_Attribs.ArraySize, FirstElement, NumElements); + const auto& Desc = GetDesc(); + VerifyAndCorrectSetArrayArguments(Desc.Name, Desc.ArraySize, FirstElement, NumElements); for (Uint32 elem = 0; elem < NumElements; ++elem) BindResource(ppObjects[elem], FirstElement + elem); } virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final { - VERIFY_EXPR(ArrayIndex < m_Attribs.ArraySize); - return m_ParentResLayout.m_pResourceCache->IsSSBOBound(m_Attribs.Binding + ArrayIndex); + VERIFY_EXPR(ArrayIndex < GetDesc().ArraySize); + return m_ParentManager.m_ResourceCache.IsSSBOBound(GetAttribs().CacheOffset + ArrayIndex); } }; // dbgResourceCache is only used for sanity check and as a remainder that the resource cache must be alive // while Layout is alive - void BindResources(SHADER_TYPE ShaderStage, IResourceMapping* pResourceMapping, Uint32 Flags, const GLProgramResourceCache& dbgResourceCache); + void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags); #ifdef DILIGENT_DEVELOPMENT - bool dvpVerifyBindings(const GLProgramResourceCache& ResourceCache) const; + bool dvpVerifyBindings(const ShaderResourceCacheGL& ResourceCache) const; #endif - IShaderResourceVariable* GetShaderVariable(SHADER_TYPE ShaderStage, const Char* Name); - IShaderResourceVariable* GetShaderVariable(SHADER_TYPE ShaderStage, Uint32 Index); + IShaderResourceVariable* GetVariable(const Char* Name) const; + IShaderResourceVariable* GetVariable(Uint32 Index) const; IObject& GetOwner() { return m_Owner; } - Uint32 GetNumVariables(SHADER_TYPE ShaderStage) const; + Uint32 GetVariableCount() const; // clang-format off - Uint32 GetNumUBs() const { return (m_SamplerOffset - m_UBOffset) / sizeof(UniformBuffBindInfo); } - Uint32 GetNumSamplers() const { return (m_ImageOffset - m_SamplerOffset) / sizeof(SamplerBindInfo); } + Uint32 GetNumUBs() const { return (m_TextureOffset - m_UBOffset) / sizeof(UniformBuffBindInfo); } + Uint32 GetNumTextures() const { return (m_ImageOffset - m_TextureOffset) / sizeof(SamplerBindInfo); } Uint32 GetNumImages() const { return (m_StorageBufferOffset - m_ImageOffset) / sizeof(ImageBindInfo) ; } Uint32 GetNumStorageBuffers() const { return (m_VariableEndOffset - m_StorageBufferOffset) / sizeof(StorageBufferBindInfo); } // clang-format on @@ -318,51 +316,41 @@ public: Uint32 GetVariableIndex(const GLVariableBase& Var) const; private: - // clang-format off -/* 0*/ IObject& m_Owner; - // No need to use shared pointer, as the resource cache is either part of the same - // ShaderGLImpl object, or ShaderResourceBindingGLImpl object -/* 8*/ GLProgramResourceCache* m_pResourceCache = nullptr; -/*16*/ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; - - // Offsets in bytes - using OffsetType = Uint16; - static constexpr OffsetType m_UBOffset = 0; -/*32*/ OffsetType m_SamplerOffset = 0; -/*34*/ OffsetType m_ImageOffset = 0; -/*36*/ OffsetType m_StorageBufferOffset = 0; -/*38*/ OffsetType m_VariableEndOffset = 0; -/*40*/ std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ProgramIndex = {}; -/*45*/ Uint8 m_NumPrograms = 0; -/*46*/ Uint8 m_PipelineType = 255u; -/*47*/ -/*48*/ // End of structure - // clang-format on + struct ResourceCounters + { + Uint32 NumUBs = 0; + Uint32 NumTextures = 0; + Uint32 NumImages = 0; + Uint32 NumStorageBlocks = 0; + }; + static void CountResources(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType, + ResourceCounters& Counters); + + template <typename HandlerType> + static void ProcessSignatureResources(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType, + HandlerType Handler); + + // Offsets in bytes + using OffsetType = Uint16; template <typename ResourceType> OffsetType GetResourceOffset() const; template <typename ResourceType> - ResourceType& GetResource(Uint32 ResIndex) + ResourceType& GetResource(Uint32 ResIndex) const { VERIFY(ResIndex < GetNumResources<ResourceType>(), "Resource index (", ResIndex, ") exceeds max allowed value (", GetNumResources<ResourceType>() - 1, ")"); auto Offset = GetResourceOffset<ResourceType>(); return reinterpret_cast<ResourceType*>(reinterpret_cast<Uint8*>(m_ResourceBuffer.get()) + Offset)[ResIndex]; } - GLProgramResources::ResourceCounters& GetProgramVarEndOffsets(Uint32 prog) - { - VERIFY_EXPR(prog < m_NumPrograms); - return reinterpret_cast<GLProgramResources::ResourceCounters*>(reinterpret_cast<Uint8*>(m_ResourceBuffer.get()) + m_VariableEndOffset)[prog]; - } - - const GLProgramResources::ResourceCounters& GetProgramVarEndOffsets(Uint32 prog) const - { - VERIFY_EXPR(prog < m_NumPrograms); - return reinterpret_cast<GLProgramResources::ResourceCounters*>(reinterpret_cast<Uint8*>(m_ResourceBuffer.get()) + m_VariableEndOffset)[prog]; - } - template <typename ResourceType> - IShaderResourceVariable* GetResourceByName(SHADER_TYPE ShaderStage, const Char* Name); + IShaderResourceVariable* GetResourceByName(const Char* Name) const; template <typename THandleUB, typename THandleSampler, @@ -410,30 +398,44 @@ private: friend class ShaderVariableIndexLocator; friend class ShaderVariableLocator; -}; +private: + PipelineResourceSignatureGLImpl const* m_pSignature = nullptr; + + IObject& m_Owner; + // No need to use shared pointer, as the resource cache is either part of the same + // ShaderGLImpl object, or ShaderResourceBindingGLImpl object + ShaderResourceCacheGL& m_ResourceCache; + std::unique_ptr<void, STDDeleterRawMem<void>> m_ResourceBuffer; + + static constexpr OffsetType m_UBOffset = 0; + OffsetType m_TextureOffset = 0; + OffsetType m_ImageOffset = 0; + OffsetType m_StorageBufferOffset = 0; + OffsetType m_VariableEndOffset = 0; +}; template <> -inline Uint32 GLPipelineResourceLayout::GetNumResources<GLPipelineResourceLayout::UniformBuffBindInfo>() const +inline Uint32 ShaderVariableGL::GetNumResources<ShaderVariableGL::UniformBuffBindInfo>() const { return GetNumUBs(); } template <> -inline Uint32 GLPipelineResourceLayout::GetNumResources<GLPipelineResourceLayout::SamplerBindInfo>() const +inline Uint32 ShaderVariableGL::GetNumResources<ShaderVariableGL::SamplerBindInfo>() const { - return GetNumSamplers(); + return GetNumTextures(); } template <> -inline Uint32 GLPipelineResourceLayout::GetNumResources<GLPipelineResourceLayout::ImageBindInfo>() const +inline Uint32 ShaderVariableGL::GetNumResources<ShaderVariableGL::ImageBindInfo>() const { return GetNumImages(); } template <> -inline Uint32 GLPipelineResourceLayout::GetNumResources<GLPipelineResourceLayout::StorageBufferBindInfo>() const +inline Uint32 ShaderVariableGL::GetNumResources<ShaderVariableGL::StorageBufferBindInfo>() const { return GetNumStorageBuffers(); } @@ -441,29 +443,29 @@ inline Uint32 GLPipelineResourceLayout::GetNumResources<GLPipelineResourceLayout template <> -inline GLPipelineResourceLayout::OffsetType GLPipelineResourceLayout:: - GetResourceOffset<GLPipelineResourceLayout::UniformBuffBindInfo>() const +inline ShaderVariableGL::OffsetType ShaderVariableGL:: + GetResourceOffset<ShaderVariableGL::UniformBuffBindInfo>() const { return m_UBOffset; } template <> -inline GLPipelineResourceLayout::OffsetType GLPipelineResourceLayout:: - GetResourceOffset<GLPipelineResourceLayout::SamplerBindInfo>() const +inline ShaderVariableGL::OffsetType ShaderVariableGL:: + GetResourceOffset<ShaderVariableGL::SamplerBindInfo>() const { - return m_SamplerOffset; + return m_TextureOffset; } template <> -inline GLPipelineResourceLayout::OffsetType GLPipelineResourceLayout:: - GetResourceOffset<GLPipelineResourceLayout::ImageBindInfo>() const +inline ShaderVariableGL::OffsetType ShaderVariableGL:: + GetResourceOffset<ShaderVariableGL::ImageBindInfo>() const { return m_ImageOffset; } template <> -inline GLPipelineResourceLayout::OffsetType GLPipelineResourceLayout:: - GetResourceOffset<GLPipelineResourceLayout::StorageBufferBindInfo>() const +inline ShaderVariableGL::OffsetType ShaderVariableGL:: + GetResourceOffset<ShaderVariableGL::StorageBufferBindInfo>() const { return m_StorageBufferOffset; } diff --git a/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp b/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp index 805cfc50..6b507c67 100644 --- a/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp @@ -84,7 +84,7 @@ public: GLenum GetGLTexFormat() const { return m_GLTexFormat; } - void TextureMemoryBarrier(Uint32 RequiredBarriers, class GLContextState& GLContextState); + void TextureMemoryBarrier(MEMORY_BARRIER RequiredBarriers, class GLContextState& GLContextState); virtual void AttachToFramebuffer(const struct TextureViewDesc& ViewDesc, GLenum AttachmentPoint) = 0; diff --git a/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp index 6c418533..d5812133 100644 --- a/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp @@ -220,7 +220,7 @@ IMPLEMENT_QUERY_INTERFACE(BufferGLImpl, IID_BufferGL, TBufferBase) void BufferGLImpl::UpdateData(GLContextState& CtxState, Uint32 Offset, Uint32 Size, const void* pData) { BufferMemoryBarrier( - GL_BUFFER_UPDATE_BARRIER_BIT, // Reads or writes to buffer objects via any OpenGL API functions that allow + MEMORY_BARRIER_BUFFER_UPDATE, // Reads or writes to buffer objects via any OpenGL API functions that allow // modifying their contents will reflect data written by shaders prior to the barrier. // Additionally, writes via these commands issued after the barrier will wait on // the completion of any shader writes to the same memory initiated prior to the barrier. @@ -240,13 +240,13 @@ void BufferGLImpl::UpdateData(GLContextState& CtxState, Uint32 Offset, Uint32 Si void BufferGLImpl::CopyData(GLContextState& CtxState, BufferGLImpl& SrcBufferGL, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size) { BufferMemoryBarrier( - GL_BUFFER_UPDATE_BARRIER_BIT, // Reads or writes to buffer objects via any OpenGL API functions that allow + MEMORY_BARRIER_BUFFER_UPDATE, // Reads or writes to buffer objects via any OpenGL API functions that allow // modifying their contents will reflect data written by shaders prior to the barrier. // Additionally, writes via these commands issued after the barrier will wait on // the completion of any shader writes to the same memory initiated prior to the barrier. CtxState); SrcBufferGL.BufferMemoryBarrier( - GL_BUFFER_UPDATE_BARRIER_BIT, + MEMORY_BARRIER_BUFFER_UPDATE, CtxState); // Whilst glCopyBufferSubData() can be used to copy data between buffers bound to any two targets, @@ -271,7 +271,7 @@ void BufferGLImpl::Map(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFla void BufferGLImpl::MapRange(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, Uint32 Offset, Uint32 Length, PVoid& pMappedData) { BufferMemoryBarrier( - GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT, // Access by the client to persistent mapped regions of buffer + MEMORY_BARRIER_CLIENT_MAPPED_BUFFER, // Access by the client to persistent mapped regions of buffer // objects will reflect data written by shaders prior to the barrier. // Note that this may cause additional synchronization operations. CtxState); @@ -346,23 +346,12 @@ void BufferGLImpl::Unmap(GLContextState& CtxState) (void)Result; } -void BufferGLImpl::BufferMemoryBarrier(Uint32 RequiredBarriers, GLContextState& GLContextState) +void BufferGLImpl::BufferMemoryBarrier(MEMORY_BARRIER RequiredBarriers, GLContextState& GLContextState) { #if GL_ARB_shader_image_load_store # ifdef DILIGENT_DEBUG { - // clang-format off - constexpr Uint32 BufferBarriers = - GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | - GL_ELEMENT_ARRAY_BARRIER_BIT | - GL_UNIFORM_BARRIER_BIT | - GL_COMMAND_BARRIER_BIT | - GL_BUFFER_UPDATE_BARRIER_BIT | - GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT | - GL_SHADER_STORAGE_BARRIER_BIT | - GL_TEXTURE_FETCH_BARRIER_BIT | - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; - // clang-format on + constexpr Uint32 BufferBarriers = MEMORY_BARRIER_ALL_BUFFER_BARRIERS; VERIFY((RequiredBarriers & BufferBarriers) != 0, "At least one buffer memory barrier flag should be set"); VERIFY((RequiredBarriers & ~BufferBarriers) == 0, "Inappropriate buffer memory barrier flag"); } diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index 530bc006..1c20b5bb 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -64,9 +64,8 @@ DeviceContextGLImpl::DeviceContextGLImpl(IReferenceCounters* pRefCounters, class pDeviceGL, bIsDeferred }, - m_ContextState {pDeviceGL}, - m_CommitedResourcesTentativeBarriers {0 }, - m_DefaultFBO {false } + m_ContextState{pDeviceGL}, + m_DefaultFBO {false } // clang-format on { m_BoundWritableTextures.reserve(16); @@ -78,6 +77,8 @@ IMPLEMENT_QUERY_INTERFACE(DeviceContextGLImpl, IID_DeviceContextGL, TDeviceConte void DeviceContextGLImpl::SetPipelineState(IPipelineState* pPipelineState) { + VERIFY_EXPR(pPipelineState != nullptr); + auto* pPipelineStateGLImpl = ValidatedCast<PipelineStateGLImpl>(pPipelineState); if (PipelineStateGLImpl::IsSameObject(m_pPipelineState, pPipelineStateGLImpl)) return; @@ -151,9 +152,53 @@ void DeviceContextGLImpl::SetPipelineState(IPipelineState* pPipelineState) } // Note that the program may change if a shader is created after the call - // (GLProgramResources needs to bind a program to load uniforms), but before + // (ShaderResourcesGL needs to bind a program to load uniforms), but before // the draw command. m_pPipelineState->CommitProgram(m_ContextState); + + const auto SignCount = m_pPipelineState->GetSignatureCount(); + + m_BindInfo.ActiveSRBMask = 0; + for (Uint32 s = 0; s < SignCount; ++s) + { + const auto* pLayoutSign = m_pPipelineState->GetSignature(s); + if (pLayoutSign == nullptr || pLayoutSign->GetTotalResourceCount() == 0) + continue; + + m_BindInfo.ActiveSRBMask |= (1u << s); + } + +#ifdef DILIGENT_DEVELOPMENT + // Find the first incompatible shader resource bindings + Uint32 sign = 0; + for (; sign < SignCount; ++sign) + { + const auto* pLayoutSign = m_pPipelineState->GetSignature(sign); + const auto* pSRBSign = m_BindInfo.SRBs[sign] != nullptr ? m_BindInfo.SRBs[sign]->GetSignature() : nullptr; + + if ((pLayoutSign == nullptr || pLayoutSign->GetTotalResourceCount() == 0) != (pSRBSign == nullptr || pSRBSign->GetTotalResourceCount() == 0)) + { + // One signature is null or empty while the other is not - SRB is not compatible with the layout. + break; + } + + if (pLayoutSign != nullptr && pSRBSign != nullptr && pLayoutSign->IsIncompatibleWith(*pSRBSign)) + { + // Signatures are incompatible + break; + } + } + + // Unbind incompatible SRB and SRB with a higher binding index. + // This is the same behavior that used in Vulkan backend. + for (; sign < SignCount; ++sign) + { + m_BindInfo.SRBs[sign] = nullptr; + m_BindInfo.ClearStaleSRBBit(sign); + } + + m_BindInfo.CommittedResourcesValidated = false; +#endif } void DeviceContextGLImpl::TransitionShaderResources(IPipelineState* pPipelineState, IShaderResourceBinding* pShaderResourceBinding) @@ -170,13 +215,15 @@ void DeviceContextGLImpl::CommitShaderResources(IShaderResourceBinding* pShaderR if (!DeviceContextBase::CommitShaderResources(pShaderResourceBinding, StateTransitionMode, 0)) return; - if (m_CommitedResourcesTentativeBarriers != 0) - LOG_INFO_MESSAGE("Not all tentative resource barriers have been executed since the last call to CommitShaderResources(). Did you forget to call Draw()/DispatchCompute() ?"); + auto* pShaderResBindingGL = ValidatedCast<ShaderResourceBindingGLImpl>(pShaderResourceBinding); + const auto SRBIndex = pShaderResBindingGL->GetBindingIndex(); + + m_BindInfo.SRBs[SRBIndex] = pShaderResBindingGL; + m_BindInfo.SetStaleSRBBit(SRBIndex); - m_CommitedResourcesTentativeBarriers = 0; - BindProgramResources(m_CommitedResourcesTentativeBarriers, pShaderResourceBinding); - // m_CommitedResourcesTentativeBarriers will contain memory barriers that will be required - // AFTER the actual draw/dispatch command is executed. Before that they have no meaning +#ifdef DILIGENT_DEVELOPMENT + m_BindInfo.CommittedResourcesValidated = false; +#endif } void DeviceContextGLImpl::SetStencilRef(Uint32 StencilRef) @@ -464,7 +511,7 @@ void DeviceContextGLImpl::BeginSubpass() auto* const pColorTexGL = pRTV->GetTexture<TextureBaseGL>(); pColorTexGL->TextureMemoryBarrier( - GL_FRAMEBUFFER_BARRIER_BIT, // Reads and writes via framebuffer object attachments after the + MEMORY_BARRIER_FRAMEBUFFER, // Reads and writes via framebuffer object attachments after the // barrier will reflect data written by shaders prior to the barrier. // Additionally, framebuffer writes issued after the barrier will wait // on the completion of all shader writes issued prior to the barrier. @@ -488,7 +535,7 @@ void DeviceContextGLImpl::BeginSubpass() if (pDSV != nullptr) { auto* pDepthTexGL = pDSV->GetTexture<TextureBaseGL>(); - pDepthTexGL->TextureMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT, m_ContextState); + pDepthTexGL->TextureMemoryBarrier(MEMORY_BARRIER_FRAMEBUFFER, m_ContextState); const auto& AttachmentDesc = RPDesc.pAttachments[DepthAttachmentIndex]; auto FirstLastUse = m_pActiveRenderPass->GetAttachmentFirstLastUse(DepthAttachmentIndex); @@ -634,27 +681,65 @@ void DeviceContextGLImpl::EndRenderPass() m_ContextState.InvalidateFBO(); } -void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShaderResourceBinding* pResBinding) +#ifdef DILIGENT_DEVELOPMENT +void DeviceContextGLImpl::DvpValidateCommittedShaderResources() { - if (!m_pPipelineState) - { - LOG_ERROR_MESSAGE("No pipeline state is bound"); + if (m_BindInfo.CommittedResourcesValidated) return; - } - if (pResBinding == nullptr) + m_pPipelineState->DvpVerifySRBResources(m_BindInfo.SRBs.data(), m_BindInfo.BoundResOffsets.data(), static_cast<Uint32>(m_BindInfo.SRBs.size())); + m_BindInfo.CommittedResourcesValidated = true; +} +#endif + +void DeviceContextGLImpl::BindProgramResources() +{ + //if (m_CommitedResourcesTentativeBarriers != 0) + // LOG_INFO_MESSAGE("Not all tentative resource barriers have been executed since the last call to CommitShaderResources(). Did you forget to call Draw()/DispatchCompute() ?"); + + if ((m_BindInfo.StaleSRBMask & m_BindInfo.ActiveSRBMask) == 0) return; - auto* pShaderResBindingGL = ValidatedCast<ShaderResourceBindingGLImpl>(pResBinding); - const auto& ResourceCache = pShaderResBindingGL->GetResourceCache(m_pPipelineState); + m_CommitedResourcesTentativeBarriers = MEMORY_BARRIER_NONE; + TBindings Bindings = {}; + + auto ActiveSRBMask = Uint32{m_BindInfo.ActiveSRBMask}; + while (ActiveSRBMask != 0) + { + Uint32 sign = PlatformMisc::GetLSB(ActiveSRBMask); + Uint32 SigBit = (1u << sign); + VERIFY_EXPR(sign < m_pPipelineState->GetSignatureCount()); + + ActiveSRBMask &= ~SigBit; + + const auto* pSRB = m_BindInfo.SRBs[sign]; + VERIFY_EXPR(pSRB); + + //if (m_BindInfo.StaleSRBMask & SigBit) + { + BindProgramResources(m_CommitedResourcesTentativeBarriers, pSRB, Bindings); + #ifdef DILIGENT_DEVELOPMENT - m_pPipelineState->GetResourceLayout().dvpVerifyBindings(ResourceCache); + m_BindInfo.BoundResOffsets[sign] = Bindings; #endif + } + + pSRB->GetSignature()->AddBindings(Bindings); + } + + m_BindInfo.StaleSRBMask &= ~m_BindInfo.ActiveSRBMask; +} + +void DeviceContextGLImpl::BindProgramResources(MEMORY_BARRIER& NewMemoryBarriers, const ShaderResourceBindingGLImpl* pShaderResBindingGL, TBindings& Bindings) +{ + const auto SRBIndex = pShaderResBindingGL->GetBindingIndex(); + const auto& ResourceCache = pShaderResBindingGL->GetResourceCache(); + VERIFY_EXPR(m_BoundWritableTextures.empty()); VERIFY_EXPR(m_BoundWritableBuffers.empty()); - for (Uint32 ub = 0; ub < ResourceCache.GetUBCount(); ++ub) + for (Uint32 ub = 0, binding = Bindings[BINDING_RANGE_UNIFORM_BUFFER]; ub < ResourceCache.GetUBCount(); ++ub, ++binding) { const auto& UB = ResourceCache.GetConstUB(ub); if (!UB.pBuffer) @@ -662,17 +747,17 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade auto* pBufferGL = UB.pBuffer.RawPtr<BufferGLImpl>(); pBufferGL->BufferMemoryBarrier( - GL_UNIFORM_BARRIER_BIT, // Shader uniforms sourced from buffer objects after the barrier - // will reflect data written by shaders prior to the barrier + MEMORY_BARRIER_UNIFORM_BUFFER, // Shader uniforms sourced from buffer objects after the barrier + // will reflect data written by shaders prior to the barrier m_ContextState); - m_ContextState.BindUniformBuffer(ub, pBufferGL->m_GlBuffer); + m_ContextState.BindUniformBuffer(binding, pBufferGL->m_GlBuffer); //glBindBufferRange(GL_UNIFORM_BUFFER, it->Index, pBufferGL->m_GlBuffer, 0, pBufferGL->GetDesc().uiSizeInBytes); } - for (Uint32 s = 0; s < ResourceCache.GetSamplerCount(); ++s) + for (Uint32 s = 0, binding = Bindings[BINDING_RANGE_TEXTURE]; s < ResourceCache.GetTextureCount(); ++s, ++binding) { - const auto& Sam = ResourceCache.GetConstSampler(s); + const auto& Sam = ResourceCache.GetConstTexture(s); if (!Sam.pView) continue; @@ -682,21 +767,21 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade auto* pTexViewGL = Sam.pView.RawPtr<TextureViewGLImpl>(); auto* pTextureGL = ValidatedCast<TextureBaseGL>(Sam.pTexture); VERIFY_EXPR(pTextureGL == pTexViewGL->GetTexture()); - m_ContextState.BindTexture(s, pTexViewGL->GetBindTarget(), pTexViewGL->GetHandle()); + m_ContextState.BindTexture(binding, pTexViewGL->GetBindTarget(), pTexViewGL->GetHandle()); pTextureGL->TextureMemoryBarrier( - GL_TEXTURE_FETCH_BARRIER_BIT, // Texture fetches from shaders, including fetches from buffer object + MEMORY_BARRIER_TEXTURE_FETCH, // Texture fetches from shaders, including fetches from buffer object // memory via buffer textures, after the barrier will reflect data // written by shaders prior to the barrier m_ContextState); if (Sam.pSampler) { - m_ContextState.BindSampler(s, Sam.pSampler->GetHandle()); + m_ContextState.BindSampler(binding, Sam.pSampler->GetHandle()); } else { - m_ContextState.BindSampler(s, GLObjectWrappers::GLSamplerObj(false)); + m_ContextState.BindSampler(binding, GLObjectWrappers::GLSamplerObj(false)); } } else if (Sam.pBuffer != nullptr) @@ -705,19 +790,19 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade auto* pBufferGL = ValidatedCast<BufferGLImpl>(Sam.pBuffer); VERIFY_EXPR(pBufferGL == pBufViewGL->GetBuffer()); - m_ContextState.BindTexture(s, GL_TEXTURE_BUFFER, pBufViewGL->GetTexBufferHandle()); - m_ContextState.BindSampler(s, GLObjectWrappers::GLSamplerObj(false)); // Use default texture sampling parameters + m_ContextState.BindTexture(binding, GL_TEXTURE_BUFFER, pBufViewGL->GetTexBufferHandle()); + m_ContextState.BindSampler(binding, GLObjectWrappers::GLSamplerObj(false)); // Use default texture sampling parameters pBufferGL->BufferMemoryBarrier( - GL_TEXTURE_FETCH_BARRIER_BIT, // Texture fetches from shaders, including fetches from buffer object - // memory via buffer textures, after the barrier will reflect data - // written by shaders prior to the barrier + MEMORY_BARRIER_TEXEL_BUFFER, // Texture fetches from shaders, including fetches from buffer object + // memory via buffer textures, after the barrier will reflect data + // written by shaders prior to the barrier m_ContextState); } } #if GL_ARB_shader_image_load_store - for (Uint32 img = 0; img < ResourceCache.GetImageCount(); ++img) + for (Uint32 img = 0, binding = Bindings[BINDING_RANGE_IMAGE]; img < ResourceCache.GetImageCount(); ++img, ++binding) { const auto& Img = ResourceCache.GetConstImage(img); if (!Img.pView) @@ -736,12 +821,12 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade if (ViewDesc.AccessFlags & UAV_ACCESS_FLAG_WRITE) { pTextureGL->TextureMemoryBarrier( - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, // Memory accesses using shader image load, store, and atomic built-in - // functions issued after the barrier will reflect data written by shaders - // prior to the barrier. Additionally, image stores and atomics issued after - // the barrier will not execute until all memory accesses (e.g., loads, - // stores, texture fetches, vertex fetches) initiated prior to the barrier - // complete. + MEMORY_BARRIER_STORAGE_IMAGE, // Memory accesses using shader image load, store, and atomic built-in + // functions issued after the barrier will reflect data written by shaders + // prior to the barrier. Additionally, image stores and atomics issued after + // the barrier will not execute until all memory accesses (e.g., loads, + // stores, texture fetches, vertex fetches) initiated prior to the barrier + // complete. m_ContextState); // We cannot set pending memory barriers here, because // if some texture is bound twice, the logic will fail @@ -774,7 +859,7 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade // That means that if an integer texture is being bound, its // GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER must be NEAREST, // otherwise it will be incomplete - m_ContextState.BindImage(img, pTexViewGL, ViewDesc.MostDetailedMip, Layered, Layer, GLAccess, GlTexFormat); + m_ContextState.BindImage(binding, pTexViewGL, ViewDesc.MostDetailedMip, Layered, Layer, GLAccess, GlTexFormat); // Do not use binding points from reflection as they may not be initialized } else if (Img.pBuffer != nullptr) @@ -787,25 +872,25 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade VERIFY(ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Unexpected buffer view type"); pBufferGL->BufferMemoryBarrier( - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, // Memory accesses using shader image load, store, and atomic built-in - // functions issued after the barrier will reflect data written by shaders - // prior to the barrier. Additionally, image stores and atomics issued after - // the barrier will not execute until all memory accesses (e.g., loads, - // stores, texture fetches, vertex fetches) initiated prior to the barrier - // complete. + MEMORY_BARRIER_IMAGE_BUFFER, // Memory accesses using shader image load, store, and atomic built-in + // functions issued after the barrier will reflect data written by shaders + // prior to the barrier. Additionally, image stores and atomics issued after + // the barrier will not execute until all memory accesses (e.g., loads, + // stores, texture fetches, vertex fetches) initiated prior to the barrier + // complete. m_ContextState); m_BoundWritableBuffers.push_back(pBufferGL); auto GlFormat = TypeToGLTexFormat(ViewDesc.Format.ValueType, ViewDesc.Format.NumComponents, ViewDesc.Format.IsNormalized); - m_ContextState.BindImage(img, pBuffViewGL, GL_READ_WRITE, GlFormat); + m_ContextState.BindImage(binding, pBuffViewGL, GL_READ_WRITE, GlFormat); } } #endif #if GL_ARB_shader_storage_buffer_object - for (Uint32 ssbo = 0; ssbo < ResourceCache.GetSSBOCount(); ++ssbo) + for (Uint32 ssbo = 0, binding = Bindings[BINDING_RANGE_STORAGE_BUFFER]; ssbo < ResourceCache.GetSSBOCount(); ++ssbo, ++binding) { const auto& SSBO = ResourceCache.GetConstSSBO(ssbo); if (!SSBO.pBufferView) @@ -817,11 +902,11 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade auto* pBufferGL = pBufferViewGL->GetBuffer<BufferGLImpl>(); pBufferGL->BufferMemoryBarrier( - GL_SHADER_STORAGE_BARRIER_BIT, // Accesses to shader storage blocks after the barrier + MEMORY_BARRIER_STORAGE_BUFFER, // Accesses to shader storage blocks after the barrier // will reflect writes prior to the barrier m_ContextState); - m_ContextState.BindStorageBlock(ssbo, pBufferGL->m_GlBuffer, ViewDesc.ByteOffset, ViewDesc.ByteWidth); + m_ContextState.BindStorageBlock(binding, pBufferGL->m_GlBuffer, ViewDesc.ByteOffset, ViewDesc.ByteWidth); if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS) m_BoundWritableBuffers.push_back(pBufferGL); @@ -833,26 +918,7 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade // Go through the list of textures bound as AUVs and set the required memory barriers for (auto* pWritableTex : m_BoundWritableTextures) { - Uint32 TextureMemBarriers = - GL_TEXTURE_UPDATE_BARRIER_BIT // Writes to a texture via glTex(Sub)Image*, glCopyTex(Sub)Image*, - // glClearTex*Image, glCompressedTex(Sub)Image*, and reads via - // glGetTexImage() after the barrier will reflect data written by - // shaders prior to the barrier - - | GL_TEXTURE_FETCH_BARRIER_BIT // Texture fetches from shaders, including fetches from buffer object - // memory via buffer textures, after the barrier will reflect data - // written by shaders prior to the barrier - - | GL_PIXEL_BUFFER_BARRIER_BIT // Reads and writes of buffer objects via the GL_PIXEL_PACK_BUFFER and - // GL_PIXEL_UNPACK_BUFFER bidnings after the barrier will reflect data - // written by shaders prior to the barrier - - | GL_FRAMEBUFFER_BARRIER_BIT // Reads and writes via framebuffer object attachments after the - // barrier will reflect data written by shaders prior to the barrier. - // Additionally, framebuffer writes issued after the barrier will wait - // on the completion of all shader writes issued prior to the barrier. - - | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; + constexpr MEMORY_BARRIER TextureMemBarriers = MEMORY_BARRIER_ALL_TEXTURE_BARRIERS; NewMemoryBarriers |= TextureMemBarriers; @@ -863,18 +929,7 @@ void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShade for (auto* pWritableBuff : m_BoundWritableBuffers) { - // clang-format off - Uint32 BufferMemoryBarriers = - GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | - GL_ELEMENT_ARRAY_BARRIER_BIT | - GL_UNIFORM_BARRIER_BIT | - GL_COMMAND_BARRIER_BIT | - GL_BUFFER_UPDATE_BARRIER_BIT | - GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT | - GL_SHADER_STORAGE_BARRIER_BIT | - GL_TEXTURE_FETCH_BARRIER_BIT | - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; - // clang-format on + constexpr MEMORY_BARRIER BufferMemoryBarriers = MEMORY_BARRIER_ALL_BUFFER_BARRIERS; NewMemoryBarriers |= BufferMemoryBarriers; // Set new required barriers for the time when buffer is used next time @@ -892,8 +947,9 @@ void DeviceContextGLImpl::PrepareForDraw(DRAW_FLAGS Flags, bool IsIndexed, GLenu #endif // The program might have changed since the last SetPipelineState call if a shader was - // created after the call (GLProgramResources needs to bind a program to load uniforms). + // created after the call (ShaderResourcesGL needs to bind a program to load uniforms). m_pPipelineState->CommitProgram(m_ContextState); + BindProgramResources(); auto CurrNativeGLContext = m_pDevice->m_GLContext.GetCurrentNativeGLContext(); const auto& PipelineDesc = m_pPipelineState->GetGraphicsPipelineDesc(); @@ -931,6 +987,10 @@ void DeviceContextGLImpl::PrepareForDraw(DRAW_FLAGS Flags, bool IsIndexed, GLenu { GlTopology = PrimitiveTopologyToGLTopology(Topology); } + +#ifdef DILIGENT_DEVELOPMENT + DvpValidateCommittedShaderResources(); +#endif } void DeviceContextGLImpl::PrepareForIndexedDraw(VALUE_TYPE IndexType, Uint32 FirstIndexLocation, GLenum& GLIndexType, Uint32& FirstIndexByteOffset) @@ -949,7 +1009,7 @@ void DeviceContextGLImpl::PostDraw() // m_CommitedResourcesTentativeBarriers contains memory barriers that will be required // AFTER the actual draw/dispatch command is executed. m_ContextState.SetPendingMemoryBarriers(m_CommitedResourcesTentativeBarriers); - m_CommitedResourcesTentativeBarriers = 0; + m_CommitedResourcesTentativeBarriers = MEMORY_BARRIER_NONE; } void DeviceContextGLImpl::Draw(const DrawAttribs& Attribs) @@ -1029,11 +1089,11 @@ void DeviceContextGLImpl::PrepareForIndirectDraw(IBuffer* pAttribsBuffer) // GL_DRAW_INDIRECT_BUFFER binding. Thus, any of indirect draw functions will fail if no buffer is // bound to that binding. pIndirectDrawAttribsGL->BufferMemoryBarrier( - GL_COMMAND_BARRIER_BIT, // Command data sourced from buffer objects by - // Draw*Indirect and DispatchComputeIndirect commands after the barrier - // will reflect data written by shaders prior to the barrier.The buffer - // objects affected by this bit are derived from the DRAW_INDIRECT_BUFFER - // and DISPATCH_INDIRECT_BUFFER bindings. + MEMORY_BARRIER_INDIRECT_BUFFER, // Command data sourced from buffer objects by + // Draw*Indirect and DispatchComputeIndirect commands after the barrier + // will reflect data written by shaders prior to the barrier.The buffer + // objects affected by this bit are derived from the DRAW_INDIRECT_BUFFER + // and DISPATCH_INDIRECT_BUFFER bindings. m_ContextState); constexpr bool ResetVAO = false; // GL_DRAW_INDIRECT_BUFFER does not affect VAO m_ContextState.BindBuffer(GL_DRAW_INDIRECT_BUFFER, pIndirectDrawAttribsGL->m_GlBuffer, ResetVAO); @@ -1122,10 +1182,15 @@ void DeviceContextGLImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) if (!DvpVerifyDispatchArguments(Attribs)) return; +#ifdef DILIGENT_DEVELOPMENT + DvpValidateCommittedShaderResources(); +#endif + #if GL_ARB_compute_shader // The program might have changed since the last SetPipelineState call if a shader was - // created after the call (GLProgramResources needs to bind a program to load uniforms). + // created after the call (ShaderResourcesGL needs to bind a program to load uniforms). m_pPipelineState->CommitProgram(m_ContextState); + BindProgramResources(); glDispatchCompute(Attribs.ThreadGroupCountX, Attribs.ThreadGroupCountY, Attribs.ThreadGroupCountZ); DEV_CHECK_GL_ERROR("glDispatchCompute() failed"); @@ -1140,18 +1205,23 @@ void DeviceContextGLImpl::DispatchComputeIndirect(const DispatchComputeIndirectA if (!DvpVerifyDispatchIndirectArguments(Attribs, pAttribsBuffer)) return; +#ifdef DILIGENT_DEVELOPMENT + DvpValidateCommittedShaderResources(); +#endif + #if GL_ARB_compute_shader // The program might have changed since the last SetPipelineState call if a shader was - // created after the call (GLProgramResources needs to bind a program to load uniforms). + // created after the call (ShaderResourcesGL needs to bind a program to load uniforms). m_pPipelineState->CommitProgram(m_ContextState); + BindProgramResources(); auto* pBufferGL = ValidatedCast<BufferGLImpl>(pAttribsBuffer); pBufferGL->BufferMemoryBarrier( - GL_COMMAND_BARRIER_BIT, // Command data sourced from buffer objects by - // Draw*Indirect and DispatchComputeIndirect commands after the barrier - // will reflect data written by shaders prior to the barrier.The buffer - // objects affected by this bit are derived from the DRAW_INDIRECT_BUFFER - // and DISPATCH_INDIRECT_BUFFER bindings. + MEMORY_BARRIER_INDIRECT_BUFFER, // Command data sourced from buffer objects by + // Draw*Indirect and DispatchComputeIndirect commands after the barrier + // will reflect data written by shaders prior to the barrier.The buffer + // objects affected by this bit are derived from the DRAW_INDIRECT_BUFFER + // and DISPATCH_INDIRECT_BUFFER bindings. m_ContextState); constexpr bool ResetVAO = false; // GL_DISPATCH_INDIRECT_BUFFER does not affect VAO @@ -1270,6 +1340,8 @@ void DeviceContextGLImpl::Flush() } glFlush(); + + m_BindInfo.SRBs.fill(nullptr); } void DeviceContextGLImpl::FinishFrame() diff --git a/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp b/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp index 25c9bd5f..e09712e0 100644 --- a/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/FBOCache.cpp @@ -246,7 +246,7 @@ const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetFBO(Uint32 Nu auto* pColorTexGL = pRTView->GetTexture<TextureBaseGL>(); pColorTexGL->TextureMemoryBarrier( - GL_FRAMEBUFFER_BARRIER_BIT, // Reads and writes via framebuffer object attachments after the + MEMORY_BARRIER_FRAMEBUFFER, // Reads and writes via framebuffer object attachments after the // barrier will reflect data written by shaders prior to the barrier. // Additionally, framebuffer writes issued after the barrier will wait // on the completion of all shader writes issued prior to the barrier. @@ -259,7 +259,7 @@ const GLObjectWrappers::GLFrameBufferObj& FBOCache::GetFBO(Uint32 Nu if (pDSV) { auto* pDepthTexGL = pDSV->GetTexture<TextureBaseGL>(); - pDepthTexGL->TextureMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT, ContextState); + pDepthTexGL->TextureMemoryBarrier(MEMORY_BARRIER_FRAMEBUFFER, ContextState); Key.DSId = pDepthTexGL->GetUniqueID(); Key.DSVDesc = pDSV->GetDesc(); } diff --git a/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp b/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp index 21220f32..fa60c34a 100644 --- a/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp @@ -80,7 +80,7 @@ void GLContextState::Invalidate() // executed next frame when needed if (m_PendingMemoryBarriers != 0) EnsureMemoryBarrier(m_PendingMemoryBarriers); - m_PendingMemoryBarriers = 0; + m_PendingMemoryBarriers = MEMORY_BARRIER_NONE; #endif // Unity messes up at least VAO left in the context, @@ -378,7 +378,7 @@ void GLContextState::BindBuffer(GLenum BindTarget, const GLObjectWrappers::GLBuf DEV_CHECK_GL_ERROR("Failed to bind buffer ", static_cast<GLint>(Buff), " to target ", BindTarget); } -void GLContextState::EnsureMemoryBarrier(Uint32 RequiredBarriers, AsyncWritableResource* pRes /* = nullptr */) +void GLContextState::EnsureMemoryBarrier(MEMORY_BARRIER RequiredBarriers, AsyncWritableResource* pRes /* = nullptr */) { #if GL_ARB_shader_image_load_store // Every resource tracks its own pending memory barriers. @@ -401,7 +401,7 @@ void GLContextState::EnsureMemoryBarrier(Uint32 RequiredBarriers, AsyncWritableR // This situation does not seem to be a problem though since a barier cannot be executed // twice in any situation - Uint32 ResourcePendingBarriers = 0; + MEMORY_BARRIER ResourcePendingBarriers = MEMORY_BARRIER_NONE; if (pRes) { // If resource is specified, only set up memory barriers @@ -427,7 +427,7 @@ void GLContextState::EnsureMemoryBarrier(Uint32 RequiredBarriers, AsyncWritableR #endif } -void GLContextState::SetPendingMemoryBarriers(Uint32 PendingBarriers) +void GLContextState::SetPendingMemoryBarriers(MEMORY_BARRIER PendingBarriers) { m_PendingMemoryBarriers |= PendingBarriers; } diff --git a/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp b/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp deleted file mode 100644 index a6c09f06..00000000 --- a/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp +++ /dev/null @@ -1,838 +0,0 @@ -/* - * Copyright 2019-2021 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include "pch.h" -#include <array> -#include "GLPipelineResourceLayout.hpp" -#include "Align.hpp" -#include "PlatformMisc.hpp" -#include "ShaderBase.hpp" - -namespace Diligent -{ - - -size_t GLPipelineResourceLayout::GetRequiredMemorySize(GLProgramResources* ProgramResources, - Uint32 NumPrograms, - const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes) -{ - GLProgramResources::ResourceCounters Counters; - for (Uint32 prog = 0; prog < NumPrograms; ++prog) - { - ProgramResources[prog].CountResources(ResourceLayout, AllowedVarTypes, NumAllowedTypes, Counters); - } - - // clang-format off - size_t RequiredSize = Counters.NumUBs * sizeof(UniformBuffBindInfo) + - Counters.NumSamplers * sizeof(SamplerBindInfo) + - Counters.NumImages * sizeof(ImageBindInfo) + - Counters.NumStorageBlocks * sizeof(StorageBufferBindInfo) + - NumPrograms * sizeof(GLProgramResources::ResourceCounters); - // clang-format on - return RequiredSize; -} - -void GLPipelineResourceLayout::Initialize(GLProgramResources* ProgramResources, - Uint32 NumPrograms, - PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - GLProgramResourceCache* pResourceCache) -{ - GLProgramResources::ResourceCounters Counters; - - for (Uint32 prog = 0; prog < NumPrograms; ++prog) - { - ProgramResources[prog].CountResources(ResourceLayout, AllowedVarTypes, NumAllowedTypes, Counters); - } - - // Initialize offsets - size_t CurrentOffset = 0; - - auto AdvanceOffset = [&CurrentOffset](size_t NumBytes) // - { - constexpr size_t MaxOffset = std::numeric_limits<OffsetType>::max(); - VERIFY(CurrentOffset <= MaxOffset, "Current offser (", CurrentOffset, ") exceeds max allowed value (", MaxOffset, ")"); - (void)MaxOffset; - auto Offset = static_cast<OffsetType>(CurrentOffset); - CurrentOffset += NumBytes; - return Offset; - }; - - // clang-format off - auto UBOffset = AdvanceOffset(Counters.NumUBs * sizeof(UniformBuffBindInfo) ); (void)UBOffset; // To suppress warning - m_SamplerOffset = AdvanceOffset(Counters.NumSamplers * sizeof(SamplerBindInfo) ); - m_ImageOffset = AdvanceOffset(Counters.NumImages * sizeof(ImageBindInfo) ); - m_StorageBufferOffset = AdvanceOffset(Counters.NumStorageBlocks * sizeof(StorageBufferBindInfo)); - m_VariableEndOffset = AdvanceOffset(0); - // clang-format off - m_NumPrograms = static_cast<Uint8>(NumPrograms); - VERIFY_EXPR(m_NumPrograms == NumPrograms); - auto TotalMemorySize = m_VariableEndOffset + m_NumPrograms * sizeof(GLProgramResources::ResourceCounters); - VERIFY_EXPR(TotalMemorySize == GetRequiredMemorySize(ProgramResources, NumPrograms, ResourceLayout, AllowedVarTypes, NumAllowedTypes)); - - m_PipelineType = PipelineType; - - auto& ResLayoutDataAllocator = GetRawAllocator(); - if (TotalMemorySize) - { - auto* pRawMem = ALLOCATE_RAW(ResLayoutDataAllocator, "Raw memory buffer for shader resource layout resources", TotalMemorySize); - m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void> >(pRawMem, ResLayoutDataAllocator); - } - - // clang-format off - VERIFY_EXPR(Counters.NumUBs == GetNumUBs() ); - VERIFY_EXPR(Counters.NumSamplers == GetNumSamplers() ); - VERIFY_EXPR(Counters.NumImages == GetNumImages() ); - VERIFY_EXPR(Counters.NumStorageBlocks == GetNumStorageBuffers()); - // clang-format on - - // Current resource index for every resource type - GLProgramResources::ResourceCounters VarCounters = {}; - - Uint32 UniformBindingSlots = 0; - Uint32 SamplerBindingSlots = 0; - Uint32 ImageBindingSlots = 0; - Uint32 SSBOBindingSlots = 0; - -#ifdef DILIGENT_DEBUG - const Uint32 DbgAllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); -#endif - for (Uint32 prog = 0; prog < NumPrograms; ++prog) - { - const auto& Resources = ProgramResources[prog]; - auto ShaderStages = Resources.GetShaderStages(); - Resources.ProcessConstResources( - [&](const GLProgramResources::UniformBufferInfo& UB) // - { - auto VarType = GetShaderVariableType(ShaderStages, UB.Name, ResourceLayout); - VERIFY_EXPR(IsAllowedType(VarType, DbgAllowedTypeBits)); - auto* pUBVar = new (&GetResource<UniformBuffBindInfo>(VarCounters.NumUBs++)) - UniformBuffBindInfo // - { - UB, - *this, - VarType // - }; - UniformBindingSlots = std::max(UniformBindingSlots, pUBVar->m_Attribs.Binding + pUBVar->m_Attribs.ArraySize); - }, - [&](const GLProgramResources::SamplerInfo& Sam) // - { - auto VarType = GetShaderVariableType(ShaderStages, Sam.Name, ResourceLayout); - VERIFY_EXPR(IsAllowedType(VarType, DbgAllowedTypeBits)); - Int32 ImtblSamplerIdx = -1; - if (Sam.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) - { - ImtblSamplerIdx = FindImmutableSampler(ResourceLayout.ImmutableSamplers, ResourceLayout.NumImmutableSamplers, ShaderStages, - Sam.Name, nullptr); - } - auto* pSamVar = new (&GetResource<SamplerBindInfo>(VarCounters.NumSamplers++)) - SamplerBindInfo // - { - Sam, - *this, - VarType, - ImtblSamplerIdx // - }; - SamplerBindingSlots = std::max(SamplerBindingSlots, pSamVar->m_Attribs.Binding + pSamVar->m_Attribs.ArraySize); - }, - [&](const GLProgramResources::ImageInfo& Img) // - { - auto VarType = GetShaderVariableType(ShaderStages, Img.Name, ResourceLayout); - VERIFY_EXPR(IsAllowedType(VarType, DbgAllowedTypeBits)); - auto* pImgVar = new (&GetResource<ImageBindInfo>(VarCounters.NumImages++)) - ImageBindInfo // - { - Img, - *this, - VarType // - }; - ImageBindingSlots = std::max(ImageBindingSlots, pImgVar->m_Attribs.Binding + pImgVar->m_Attribs.ArraySize); - }, - [&](const GLProgramResources::StorageBlockInfo& SB) // - { - auto VarType = GetShaderVariableType(ShaderStages, SB.Name, ResourceLayout); - VERIFY_EXPR(IsAllowedType(VarType, DbgAllowedTypeBits)); - auto* pSSBOVar = new (&GetResource<StorageBufferBindInfo>(VarCounters.NumStorageBlocks++)) - StorageBufferBindInfo // - { - SB, - *this, - VarType // - }; - SSBOBindingSlots = std::max(SSBOBindingSlots, pSSBOVar->m_Attribs.Binding + pSSBOVar->m_Attribs.ArraySize); - }, - &ResourceLayout, - AllowedVarTypes, - NumAllowedTypes // - ); - - new (&GetProgramVarEndOffsets(prog)) GLProgramResources::ResourceCounters{VarCounters}; - while (ShaderStages != SHADER_TYPE_UNKNOWN) - { - auto Stage = static_cast<SHADER_TYPE>(Uint32{ShaderStages} & ~(Uint32{ShaderStages} - 1)); - auto ShaderInd = GetShaderTypePipelineIndex(Stage, PipelineType); - m_ProgramIndex[ShaderInd] = static_cast<Int8>(prog); - ShaderStages = static_cast<SHADER_TYPE>(Uint32{ShaderStages} & ~Stage); - } - } - - // clang-format off - VERIFY(VarCounters.NumUBs == GetNumUBs(), "Not all UBs are initialized which will cause a crash when dtor is called"); - VERIFY(VarCounters.NumSamplers == GetNumSamplers(), "Not all Samplers are initialized which will cause a crash when dtor is called"); - VERIFY(VarCounters.NumImages == GetNumImages(), "Not all Images are initialized which will cause a crash when dtor is called"); - VERIFY(VarCounters.NumStorageBlocks == GetNumStorageBuffers(), "Not all SSBOs are initialized which will cause a crash when dtor is called"); - // clang-format on - - m_pResourceCache = pResourceCache; - if (m_pResourceCache != nullptr && !m_pResourceCache->IsInitialized()) - { - // NOTE that here we are using max bind points required to cache only the shader variables of allowed types! - m_pResourceCache->Initialize(UniformBindingSlots, SamplerBindingSlots, ImageBindingSlots, SSBOBindingSlots, GetRawAllocator()); - } -} - -GLPipelineResourceLayout::~GLPipelineResourceLayout() -{ - // clang-format off - HandleResources( - [&](UniformBuffBindInfo& ub) - { - ub.~UniformBuffBindInfo(); - }, - - [&](SamplerBindInfo& sam) - { - sam.~SamplerBindInfo(); - }, - - [&](ImageBindInfo& img) - { - img.~ImageBindInfo(); - }, - - [&](StorageBufferBindInfo& ssbo) - { - ssbo.~StorageBufferBindInfo(); - } - ); - // clang-format on -} - - -void GLPipelineResourceLayout::UniformBuffBindInfo::BindResource(IDeviceObject* pBuffer, - Uint32 ArrayIndex) -{ - DEV_CHECK_ERR(ArrayIndex < m_Attribs.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", m_Attribs.Name, "'. Max allowed index: ", m_Attribs.ArraySize - 1); - VERIFY(m_ParentResLayout.m_pResourceCache != nullptr, "Resource cache is not initialized"); - auto& ResourceCache = *m_ParentResLayout.m_pResourceCache; - - VERIFY_EXPR(m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER); - - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<BufferGLImpl> pBuffGLImpl(pBuffer, IID_BufferGL); -#ifdef DILIGENT_DEVELOPMENT - { - const auto& CachedUB = ResourceCache.GetConstUB(m_Attribs.Binding + ArrayIndex); - VerifyConstantBufferBinding(m_Attribs, GetType(), ArrayIndex, pBuffer, pBuffGLImpl.RawPtr(), CachedUB.pBuffer.RawPtr()); - } -#endif - - ResourceCache.SetUniformBuffer(m_Attribs.Binding + ArrayIndex, std::move(pBuffGLImpl)); -} - - - -void GLPipelineResourceLayout::SamplerBindInfo::BindResource(IDeviceObject* pView, - Uint32 ArrayIndex) -{ - DEV_CHECK_ERR(ArrayIndex < m_Attribs.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", m_Attribs.Name, "'. Max allowed index: ", m_Attribs.ArraySize - 1); - VERIFY(m_ParentResLayout.m_pResourceCache != nullptr, "Resource cache is not initialized"); - auto& ResourceCache = *m_ParentResLayout.m_pResourceCache; - - VERIFY_EXPR(m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV || - m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); - - if (m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) - { - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<TextureViewGLImpl> pViewGL(pView, IID_TextureViewGL); -#ifdef DILIGENT_DEVELOPMENT - { - auto& CachedTexSampler = ResourceCache.GetConstSampler(m_Attribs.Binding + ArrayIndex); - VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, CachedTexSampler.pView.RawPtr()); - if (m_ImtblSamplerIdx >= 0) - { - VERIFY(CachedTexSampler.pSampler != nullptr, "Immutable samplers must be initialized by PipelineStateGLImpl::InitializeSRBResourceCache!"); - } - } -#endif - ResourceCache.SetTexSampler(m_Attribs.Binding + ArrayIndex, std::move(pViewGL), m_ImtblSamplerIdx < 0); - } - else if (m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV) - { - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<BufferViewGLImpl> pViewGL(pView, IID_BufferViewGL); -#ifdef DILIGENT_DEVELOPMENT - { - auto& CachedBuffSampler = ResourceCache.GetConstSampler(m_Attribs.Binding + ArrayIndex); - VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE}, CachedBuffSampler.pView.RawPtr()); - if (pViewGL != nullptr) - { - const auto& ViewDesc = pViewGL->GetDesc(); - const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); - if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) - { - LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - m_Attribs.Name, ": formatted buffer view is expected."); - } - } - } -#endif - ResourceCache.SetBufSampler(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); - } - else - { - UNEXPECTED("Unexpected resource type ", GetShaderResourceTypeLiteralName(m_Attribs.ResourceType), ". Texture SRV or buffer SRV is expected."); - } -} - - -void GLPipelineResourceLayout::ImageBindInfo::BindResource(IDeviceObject* pView, - Uint32 ArrayIndex) -{ - DEV_CHECK_ERR(ArrayIndex < m_Attribs.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", m_Attribs.Name, "'. Max allowed index: ", m_Attribs.ArraySize - 1); - VERIFY(m_ParentResLayout.m_pResourceCache != nullptr, "Resource cache is not initialized"); - auto& ResourceCache = *m_ParentResLayout.m_pResourceCache; - - if (m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV) - { - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<TextureViewGLImpl> pViewGL(pView, IID_TextureViewGL); -#ifdef DILIGENT_DEVELOPMENT - { - auto& CachedUAV = ResourceCache.GetConstImage(m_Attribs.Binding + ArrayIndex); - VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {TEXTURE_VIEW_UNORDERED_ACCESS}, CachedUAV.pView.RawPtr()); - } -#endif - ResourceCache.SetTexImage(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); - } - else if (m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV) - { - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<BufferViewGLImpl> pViewGL(pView, IID_BufferViewGL); -#ifdef DILIGENT_DEVELOPMENT - { - auto& CachedUAV = ResourceCache.GetConstImage(m_Attribs.Binding + ArrayIndex); - VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {BUFFER_VIEW_UNORDERED_ACCESS}, CachedUAV.pView.RawPtr()); - if (pViewGL != nullptr) - { - const auto& ViewDesc = pViewGL->GetDesc(); - const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); - if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) - { - LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - m_Attribs.Name, ": formatted buffer view is expected."); - } - } - } -#endif - ResourceCache.SetBufImage(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); - } - else - { - UNEXPECTED("Unexpected resource type ", GetShaderResourceTypeLiteralName(m_Attribs.ResourceType), ". Texture UAV or buffer UAV is expected."); - } -} - - - -void GLPipelineResourceLayout::StorageBufferBindInfo::BindResource(IDeviceObject* pView, - Uint32 ArrayIndex) -{ - DEV_CHECK_ERR(ArrayIndex < m_Attribs.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", m_Attribs.Name, "'. Max allowed index: ", m_Attribs.ArraySize - 1); - VERIFY(m_ParentResLayout.m_pResourceCache != nullptr, "Resource cache is not initialized"); - auto& ResourceCache = *m_ParentResLayout.m_pResourceCache; - VERIFY_EXPR(m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV); - - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<BufferViewGLImpl> pViewGL(pView, IID_BufferViewGL); -#ifdef DILIGENT_DEVELOPMENT - { - auto& CachedSSBO = ResourceCache.GetConstSSBO(m_Attribs.Binding + ArrayIndex); - // HLSL structured buffers are mapped to SSBOs in GLSL - VerifyResourceViewBinding(m_Attribs, GetType(), ArrayIndex, pView, pViewGL.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE, BUFFER_VIEW_UNORDERED_ACCESS}, CachedSSBO.pBufferView.RawPtr()); - if (pViewGL != nullptr) - { - const auto& ViewDesc = pViewGL->GetDesc(); - const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); - if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) - { - LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - m_Attribs.Name, ": structured buffer view is expected."); - } - } - } -#endif - ResourceCache.SetSSBO(m_Attribs.Binding + ArrayIndex, std::move(pViewGL)); -} - - - -// Helper template class that facilitates binding CBs, SRVs, and UAVs -class BindResourceHelper -{ -public: - BindResourceHelper(IResourceMapping& RM, SHADER_TYPE SS, Uint32 Fl) : - // clang-format off - ResourceMapping {RM}, - ShaderStage {SS}, - Flags {Fl} - // clang-format on - { - } - - template <typename ResourceType> - void Bind(ResourceType& Res) - { - if ((Flags & (1 << Res.GetType())) == 0) - return; - - for (Uint16 elem = 0; elem < Res.m_Attribs.ArraySize; ++elem) - { - if ((Res.m_Attribs.ShaderStages & ShaderStage) == 0) - continue; - - if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(elem)) - continue; - - const auto* VarName = Res.m_Attribs.Name; - RefCntAutoPtr<IDeviceObject> pRes; - ResourceMapping.GetResource(VarName, &pRes, elem); - if (pRes) - { - // Call non-virtual function - Res.BindResource(pRes, elem); - } - else - { - if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(elem)) - LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", VarName, "': resource is not found in the resource mapping"); - } - } - } - -private: - IResourceMapping& ResourceMapping; - const SHADER_TYPE ShaderStage; - const Uint32 Flags; -}; - - -void GLPipelineResourceLayout::BindResources(SHADER_TYPE ShaderStage, IResourceMapping* pResourceMapping, Uint32 Flags, const GLProgramResourceCache& dbgResourceCache) -{ - VERIFY(&dbgResourceCache == m_pResourceCache, "Resource cache does not match the cache provided at initialization"); - - if (pResourceMapping == nullptr) - { - LOG_ERROR_MESSAGE("Failed to bind resources: resource mapping is null"); - return; - } - - if ((Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0) - Flags |= BIND_SHADER_RESOURCES_UPDATE_ALL; - - BindResourceHelper BindResHelper(*pResourceMapping, ShaderStage, Flags); - - // clang-format off - HandleResources( - [&](UniformBuffBindInfo& ub) - { - BindResHelper.Bind(ub); - }, - - [&](SamplerBindInfo& sam) - { - BindResHelper.Bind(sam); - }, - - [&](ImageBindInfo& img) - { - BindResHelper.Bind(img); - }, - - [&](StorageBufferBindInfo& ssbo) - { - BindResHelper.Bind(ssbo); - } - ); - // clang-format on -} - - -template <typename ResourceType> -IShaderResourceVariable* GLPipelineResourceLayout::GetResourceByName(SHADER_TYPE ShaderStage, const Char* Name) -{ - auto NumResources = GetNumResources<ResourceType>(); - for (Uint32 res = 0; res < NumResources; ++res) - { - auto& Resource = GetResource<ResourceType>(res); - if ((Resource.m_Attribs.ShaderStages & ShaderStage) != 0 && strcmp(Resource.m_Attribs.Name, Name) == 0) - return &Resource; - } - - return nullptr; -} - - -IShaderResourceVariable* GLPipelineResourceLayout::GetShaderVariable(SHADER_TYPE ShaderStage, const Char* Name) -{ - VERIFY_EXPR(IsConsistentShaderType(ShaderStage, static_cast<PIPELINE_TYPE>(m_PipelineType))); - - if (auto* pUB = GetResourceByName<UniformBuffBindInfo>(ShaderStage, Name)) - return pUB; - - if (auto* pSampler = GetResourceByName<SamplerBindInfo>(ShaderStage, Name)) - return pSampler; - - if (auto* pImage = GetResourceByName<ImageBindInfo>(ShaderStage, Name)) - return pImage; - - if (auto* pSSBO = GetResourceByName<StorageBufferBindInfo>(ShaderStage, Name)) - return pSSBO; - - return nullptr; -} - -Uint32 GLPipelineResourceLayout::GetNumVariables(SHADER_TYPE ShaderStage) const -{ - VERIFY_EXPR(IsConsistentShaderType(ShaderStage, static_cast<PIPELINE_TYPE>(m_PipelineType))); - VERIFY(IsPowerOfTwo(Uint32{ShaderStage}), "Only one shader stage must be specified"); - auto ShaderInd = GetShaderTypePipelineIndex(ShaderStage, static_cast<PIPELINE_TYPE>(m_PipelineType)); - auto ProgIdx = m_ProgramIndex[ShaderInd]; - - if (ProgIdx < 0) - { - LOG_WARNING_MESSAGE("Unable to get the number of variables in shader stage ", GetShaderTypeLiteralName(ShaderStage), - " as the stage is inactive"); - return 0; - } - - const auto& VariableEndOffset = GetProgramVarEndOffsets(ProgIdx); - const auto& VariableStartOffset = ProgIdx > 0 ? GetProgramVarEndOffsets(ProgIdx - 1) : GLProgramResources::ResourceCounters{}; - - // clang-format off - Uint32 NumVars = VariableEndOffset.NumUBs - VariableStartOffset.NumUBs + - VariableEndOffset.NumSamplers - VariableStartOffset.NumSamplers + - VariableEndOffset.NumImages - VariableStartOffset.NumImages + - VariableEndOffset.NumStorageBlocks - VariableStartOffset.NumStorageBlocks; - // clang-format on - -#ifdef DILIGENT_DEBUG - { - Uint32 DbgNumVars = 0; - auto CountVar = [&](const GLVariableBase& Var) { - DbgNumVars += ((Var.m_Attribs.ShaderStages & ShaderStage) != 0) ? 1 : 0; - }; - HandleConstResources(CountVar, CountVar, CountVar, CountVar); - VERIFY_EXPR(DbgNumVars == NumVars); - } -#endif - - return NumVars; -} - -class ShaderVariableLocator -{ -public: - ShaderVariableLocator(GLPipelineResourceLayout& _Layout, - Uint32 _Index) : - // clang-format off - Layout {_Layout}, - Index {_Index} - // clang-format on - { - } - - template <typename ResourceType> - IShaderResourceVariable* TryResource(Uint32 StartVarOffset, Uint32 EndVarOffset) - { - auto NumResources = EndVarOffset - StartVarOffset; - if (Index < NumResources) - return &Layout.GetResource<ResourceType>(StartVarOffset + Index); - else - { - Index -= NumResources; - return nullptr; - } - } - -private: - GLPipelineResourceLayout& Layout; - Uint32 Index; -}; - - -IShaderResourceVariable* GLPipelineResourceLayout::GetShaderVariable(SHADER_TYPE ShaderStage, Uint32 Index) -{ - VERIFY(IsPowerOfTwo(Uint32{ShaderStage}), "Only one shader stage must be specified"); - auto ShaderInd = GetShaderTypePipelineIndex(ShaderStage, static_cast<PIPELINE_TYPE>(m_PipelineType)); - auto ProgIdx = m_ProgramIndex[ShaderInd]; - - if (ProgIdx < 0) - return nullptr; - - const auto& VariableEndOffset = GetProgramVarEndOffsets(ProgIdx); - const auto& VariableStartOffset = ProgIdx > 0 ? GetProgramVarEndOffsets(ProgIdx - 1) : GLProgramResources::ResourceCounters{}; - - ShaderVariableLocator VarLocator(*this, Index); - - if (auto* pUB = VarLocator.TryResource<UniformBuffBindInfo>(VariableStartOffset.NumUBs, VariableEndOffset.NumUBs)) - return pUB; - - if (auto* pSampler = VarLocator.TryResource<SamplerBindInfo>(VariableStartOffset.NumSamplers, VariableEndOffset.NumSamplers)) - return pSampler; - - if (auto* pImage = VarLocator.TryResource<ImageBindInfo>(VariableStartOffset.NumImages, VariableEndOffset.NumImages)) - return pImage; - - if (auto* pSSBO = VarLocator.TryResource<StorageBufferBindInfo>(VariableStartOffset.NumStorageBlocks, VariableEndOffset.NumStorageBlocks)) - return pSSBO; - - LOG_ERROR(Index, " is not a valid variable index."); - return nullptr; -} - - - -class ShaderVariableIndexLocator -{ -public: - ShaderVariableIndexLocator(const GLPipelineResourceLayout& _Layout, const GLPipelineResourceLayout::GLVariableBase& Variable) : - // clang-format off - Layout {_Layout}, - VarOffset(reinterpret_cast<const Uint8*>(&Variable) - reinterpret_cast<const Uint8*>(_Layout.m_ResourceBuffer.get())) - // clang-format on - {} - - template <typename ResourceType> - bool TryResource(Uint32 NextResourceTypeOffset, Uint32 FirstVarOffset, Uint32 LastVarOffset) - { - if (VarOffset < NextResourceTypeOffset) - { - auto RelativeOffset = VarOffset - Layout.GetResourceOffset<ResourceType>(); - DEV_CHECK_ERR(RelativeOffset % sizeof(ResourceType) == 0, "Offset is not multiple of resource type (", sizeof(ResourceType), ")"); - RelativeOffset /= sizeof(ResourceType); - VERIFY(RelativeOffset >= FirstVarOffset && RelativeOffset < LastVarOffset, - "Relative offset is out of bounds which either means the variable does not belong to this SRB or " - "there is a bug in varaible offsets"); - Index += static_cast<Uint32>(RelativeOffset) - FirstVarOffset; - return true; - } - else - { - Index += LastVarOffset - FirstVarOffset; - return false; - } - } - - Uint32 GetIndex() const { return Index; } - -private: - const GLPipelineResourceLayout& Layout; - const size_t VarOffset; - Uint32 Index = 0; -}; - - -Uint32 GLPipelineResourceLayout::GetVariableIndex(const GLVariableBase& Var) const -{ - if (!m_ResourceBuffer) - { - LOG_ERROR("This shader resource layout does not have resources"); - return static_cast<Uint32>(-1); - } - - auto FirstStage = static_cast<SHADER_TYPE>(Uint32{Var.m_Attribs.ShaderStages} & ~(Uint32{Var.m_Attribs.ShaderStages} - 1)); - auto ProgIdx = m_ProgramIndex[GetShaderTypePipelineIndex(FirstStage, static_cast<PIPELINE_TYPE>(m_PipelineType))]; - VERIFY(ProgIdx >= 0, "This shader stage is not initialized in the resource layout"); - - const auto& VariableEndOffset = GetProgramVarEndOffsets(ProgIdx); - const auto& VariableStartOffset = ProgIdx > 0 ? GetProgramVarEndOffsets(ProgIdx - 1) : GLProgramResources::ResourceCounters{}; - - ShaderVariableIndexLocator IdxLocator(*this, Var); - - if (IdxLocator.TryResource<UniformBuffBindInfo>(m_SamplerOffset, VariableStartOffset.NumUBs, VariableEndOffset.NumUBs)) - return IdxLocator.GetIndex(); - - if (IdxLocator.TryResource<SamplerBindInfo>(m_ImageOffset, VariableStartOffset.NumSamplers, VariableEndOffset.NumSamplers)) - return IdxLocator.GetIndex(); - - if (IdxLocator.TryResource<ImageBindInfo>(m_StorageBufferOffset, VariableStartOffset.NumImages, VariableEndOffset.NumImages)) - return IdxLocator.GetIndex(); - - if (IdxLocator.TryResource<StorageBufferBindInfo>(m_VariableEndOffset, VariableStartOffset.NumStorageBlocks, VariableEndOffset.NumStorageBlocks)) - return IdxLocator.GetIndex(); - - LOG_ERROR("Failed to get variable index. The variable ", &Var, " does not belong to this shader resource layout"); - return static_cast<Uint32>(-1); -} - -void GLPipelineResourceLayout::CopyResources(GLProgramResourceCache& DstCache) const -{ - VERIFY_EXPR(m_pResourceCache != nullptr); - const auto& SrcCache = *m_pResourceCache; - // clang-format off - VERIFY( DstCache.GetUBCount() >= SrcCache.GetUBCount(), "Dst cache is not large enough to contain all CBs" ); - VERIFY( DstCache.GetSamplerCount() >= SrcCache.GetSamplerCount(), "Dst cache is not large enough to contain all SRVs" ); - VERIFY( DstCache.GetImageCount() >= SrcCache.GetImageCount(), "Dst cache is not large enough to contain all samplers" ); - VERIFY( DstCache.GetSSBOCount() >= SrcCache.GetSSBOCount(), "Dst cache is not large enough to contain all UAVs" ); - // clang-format on - - HandleConstResources( - [&](const UniformBuffBindInfo& UB) // - { - for (auto binding = UB.m_Attribs.Binding; binding < UB.m_Attribs.Binding + UB.m_Attribs.ArraySize; ++binding) - { - auto pBufferGL = SrcCache.GetConstUB(binding).pBuffer; - DstCache.SetUniformBuffer(binding, std::move(pBufferGL)); - } - }, - - [&](const SamplerBindInfo& Sam) // - { - for (auto binding = Sam.m_Attribs.Binding; binding < Sam.m_Attribs.Binding + Sam.m_Attribs.ArraySize; ++binding) - { - const auto& SrcSam = SrcCache.GetConstSampler(binding); - DstCache.CopySampler(binding, SrcSam); - } - }, - - [&](const ImageBindInfo& Img) // - { - for (auto binding = Img.m_Attribs.Binding; binding < Img.m_Attribs.Binding + Img.m_Attribs.ArraySize; ++binding) - { - const auto& SrcImg = SrcCache.GetConstImage(binding); - DstCache.CopyImage(binding, SrcImg); - } - }, - - [&](const StorageBufferBindInfo& SSBO) // - { - for (auto binding = SSBO.m_Attribs.Binding; binding < SSBO.m_Attribs.Binding + SSBO.m_Attribs.ArraySize; ++binding) - { - auto pBufferView = SrcCache.GetConstSSBO(binding).pBufferView; - DstCache.SetSSBO(binding, std::move(pBufferView)); - } - } // - ); -} - -#ifdef DILIGENT_DEVELOPMENT -bool GLPipelineResourceLayout::dvpVerifyBindings(const GLProgramResourceCache& ResourceCache) const -{ -# define LOG_MISSING_BINDING(VarType, BindInfo, BindPt) LOG_ERROR_MESSAGE("No resource is bound to ", VarType, " variable '", BindInfo.m_Attribs.GetPrintName(BindPt - BindInfo.m_Attribs.Binding), "'") - - bool BindingsOK = true; - HandleConstResources( - [&](const UniformBuffBindInfo& ub) // - { - for (Uint32 BindPoint = ub.m_Attribs.Binding; BindPoint < Uint32{ub.m_Attribs.Binding} + ub.m_Attribs.ArraySize; ++BindPoint) - { - if (!ResourceCache.IsUBBound(BindPoint)) - { - LOG_MISSING_BINDING("constant buffer", ub, BindPoint); - BindingsOK = false; - } - } - }, - - [&](const SamplerBindInfo& sam) // - { - for (Uint32 BindPoint = sam.m_Attribs.Binding; BindPoint < Uint32{sam.m_Attribs.Binding} + sam.m_Attribs.ArraySize; ++BindPoint) - { - VERIFY_EXPR(sam.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV || - sam.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV); - if (!ResourceCache.IsSamplerBound(BindPoint, sam.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV)) - { - LOG_MISSING_BINDING("texture", sam, BindPoint); - BindingsOK = false; - } - else - { - const auto& CachedSampler = ResourceCache.GetConstSampler(BindPoint); - if (sam.m_ImtblSamplerIdx >= 0 && CachedSampler.pSampler == nullptr) - { - LOG_ERROR_MESSAGE("Immutable sampler is not initialized for texture '", sam.m_Attribs.Name, "'"); - BindingsOK = false; - } - } - } - }, - - [&](const ImageBindInfo& img) // - { - for (Uint32 BindPoint = img.m_Attribs.Binding; BindPoint < Uint32{img.m_Attribs.Binding} + img.m_Attribs.ArraySize; ++BindPoint) - { - VERIFY_EXPR(img.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV || - img.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV); - if (!ResourceCache.IsImageBound(BindPoint, img.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV)) - { - LOG_MISSING_BINDING("texture UAV", img, BindPoint); - BindingsOK = false; - } - } - }, - - [&](const StorageBufferBindInfo& ssbo) // - { - for (Uint32 BindPoint = ssbo.m_Attribs.Binding; BindPoint < Uint32{ssbo.m_Attribs.Binding} + ssbo.m_Attribs.ArraySize; ++BindPoint) - { - if (!ResourceCache.IsSSBOBound(BindPoint)) - { - LOG_MISSING_BINDING("buffer", ssbo, BindPoint); - BindingsOK = false; - } - } - }); -# undef LOG_MISSING_BINDING - - return BindingsOK; -} - -#endif - -} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineResourceSignatureGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineResourceSignatureGLImpl.cpp new file mode 100644 index 00000000..42131f1e --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/src/PipelineResourceSignatureGLImpl.cpp @@ -0,0 +1,758 @@ +/* + * Copyright 2019-2021 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "PipelineResourceSignatureGLImpl.hpp" +#include "RenderDeviceGLImpl.hpp" +#include "ShaderResourceBindingGLImpl.hpp" +#include "ShaderVariableGL.hpp" + +namespace Diligent +{ +namespace +{ + +inline bool ResourcesCompatible(const PipelineResourceSignatureGLImpl::ResourceAttribs& lhs, + const PipelineResourceSignatureGLImpl::ResourceAttribs& rhs) +{ + // Ignore sampler index. + // clang-format off + return lhs.CacheOffset == rhs.CacheOffset && + lhs.ImtblSamplerAssigned == rhs.ImtblSamplerAssigned; + // clang-format on +} + +struct PatchedPipelineResourceSignatureDesc : PipelineResourceSignatureDesc +{ + std::vector<ImmutableSamplerDesc> m_ImmutableSamplers; + + PatchedPipelineResourceSignatureDesc(RenderDeviceGLImpl* pDeviceGL, const PipelineResourceSignatureDesc& Desc) : + PipelineResourceSignatureDesc{Desc} + { + if (NumImmutableSamplers > 0 && !pDeviceGL->GetDeviceCaps().Features.SeparablePrograms) + { + m_ImmutableSamplers.resize(NumImmutableSamplers); + + SHADER_TYPE ActiveStages = SHADER_TYPE_UNKNOWN; + for (Uint32 r = 0; r < NumResources; ++r) + ActiveStages |= Resources[r].ShaderStages; + + for (Uint32 s = 0; s < NumImmutableSamplers; ++s) + { + m_ImmutableSamplers[s] = ImmutableSamplers[s]; + m_ImmutableSamplers[s].ShaderStages |= ActiveStages; + } + + ImmutableSamplers = m_ImmutableSamplers.data(); + } + } +}; + +} // namespace + + +const char* GetBindingRangeName(BINDING_RANGE Range) +{ + static_assert(BINDING_RANGE_COUNT == 4, "Please update the switch below to handle the new shader resource range"); + switch (Range) + { + // clang-format off + case BINDING_RANGE_UNIFORM_BUFFER: return "Uniform buffer"; + case BINDING_RANGE_TEXTURE: return "Texture"; + case BINDING_RANGE_IMAGE: return "Image"; + case BINDING_RANGE_STORAGE_BUFFER: return "Storage buffer"; + // clang-format on + default: + return "Unknown"; + } +} + +BINDING_RANGE PipelineResourceToBindingRange(const PipelineResourceDesc& Desc) +{ + static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update the switch below to handle the new shader resource type"); + switch (Desc.ResourceType) + { + // clang-format off + case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: return BINDING_RANGE_UNIFORM_BUFFER; + case SHADER_RESOURCE_TYPE_TEXTURE_SRV: return BINDING_RANGE_TEXTURE; + case SHADER_RESOURCE_TYPE_BUFFER_SRV: return (Desc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) ? BINDING_RANGE_TEXTURE : BINDING_RANGE_STORAGE_BUFFER; + case SHADER_RESOURCE_TYPE_TEXTURE_UAV: return BINDING_RANGE_IMAGE; + case SHADER_RESOURCE_TYPE_BUFFER_UAV: return (Desc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) ? BINDING_RANGE_IMAGE : BINDING_RANGE_STORAGE_BUFFER; + // clang-format on + case SHADER_RESOURCE_TYPE_SAMPLER: + case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT: + case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: + default: + return BINDING_RANGE_UNKNOWN; + } +} + + +PipelineResourceSignatureGLImpl::PipelineResourceSignatureGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const PipelineResourceSignatureDesc& Desc, + bool bIsDeviceInternal) : + PipelineResourceSignatureGLImpl{pRefCounters, pDeviceGL, PatchedPipelineResourceSignatureDesc{pDeviceGL, Desc}, bIsDeviceInternal, 0} +{} + +PipelineResourceSignatureGLImpl::PipelineResourceSignatureGLImpl(IReferenceCounters* pRefCounters, + RenderDeviceGLImpl* pDeviceGL, + const PipelineResourceSignatureDesc& Desc, + bool bIsDeviceInternal, + int) : + TPipelineResourceSignatureBase{pRefCounters, pDeviceGL, Desc, bIsDeviceInternal} +{ + try + { + FixedLinearAllocator MemPool{GetRawAllocator()}; + + // Reserve at least 1 element because m_pResourceAttribs must hold a pointer to memory + MemPool.AddSpace<ResourceAttribs>(std::max(1u, Desc.NumResources)); + MemPool.AddSpace<SamplerPtr>(Desc.NumImmutableSamplers); + + ReserveSpaceForDescription(MemPool, Desc); + + const auto NumStaticResStages = GetNumStaticResStages(); + if (NumStaticResStages > 0) + { + MemPool.AddSpace<ShaderResourceCacheGL>(1); + MemPool.AddSpace<ShaderVariableGL>(NumStaticResStages); + } + + MemPool.Reserve(); + + m_pResourceAttribs = MemPool.Allocate<ResourceAttribs>(std::max(1u, m_Desc.NumResources)); + m_ImmutableSamplers = MemPool.ConstructArray<SamplerPtr>(m_Desc.NumImmutableSamplers); + + // The memory is now owned by PipelineResourceSignatureGLImpl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pResourceAttribs); + (void)Ptr; + + CopyDescription(MemPool, Desc); + + if (NumStaticResStages > 0) + { + m_pStaticResCache = MemPool.Construct<ShaderResourceCacheGL>(ShaderResourceCacheGL::CacheContentType::Signature); + m_StaticVarsMgrs = MemPool.ConstructArray<ShaderVariableGL>(NumStaticResStages, std::ref(*this), std::ref(*m_pStaticResCache)); + } + + CreateLayouts(); + + if (NumStaticResStages > 0) + { + constexpr SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; + for (Uint32 i = 0; i < m_StaticResStageIndex.size(); ++i) + { + Int8 Idx = m_StaticResStageIndex[i]; + if (Idx >= 0) + { + VERIFY_EXPR(static_cast<Uint32>(Idx) < NumStaticResStages); + const auto ShaderType = GetShaderTypeFromPipelineIndex(i, GetPipelineType()); + m_StaticVarsMgrs[Idx].Initialize(*this, AllowedVarTypes, _countof(AllowedVarTypes), ShaderType); + } + } + } + + m_Hash = CalculateHash(); + } + catch (...) + { + Destruct(); + throw; + } +} + +void PipelineResourceSignatureGLImpl::CreateLayouts() +{ + std::array<Uint32, BINDING_RANGE_COUNT> StaticCounter = {}; + + for (Uint32 s = 0; s < m_Desc.NumImmutableSamplers; ++s) + GetDevice()->CreateSampler(m_Desc.ImmutableSamplers[s].Desc, &m_ImmutableSamplers[s]); + + for (Uint32 i = 0; i < m_Desc.NumResources; ++i) + { + const auto& ResDesc = m_Desc.Resources[i]; + VERIFY(i == 0 || ResDesc.VarType >= m_Desc.Resources[i - 1].VarType, "Resources must be sorted by variable type"); + + if (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER) + { + Int32 ImtblSamplerIdx = FindImmutableSampler(ResDesc.ShaderStages, ResDesc.Name); + if (ImtblSamplerIdx < 0) + { + LOG_WARNING_MESSAGE("Pipeline resource signature '", m_Desc.Name, "' has separate sampler with name '", ResDesc.Name, "' that is not supported in OpenGL."); + } + + new (m_pResourceAttribs + i) ResourceAttribs // + { + ResourceAttribs::InvalidCacheOffset, + ImtblSamplerIdx < 0 ? ResourceAttribs::InvalidSamplerInd : static_cast<Uint32>(ImtblSamplerIdx), + ImtblSamplerIdx >= 0 // + }; + } + else + { + const auto Range = PipelineResourceToBindingRange(ResDesc); + VERIFY_EXPR(Range != BINDING_RANGE_UNKNOWN); + + const Uint32 CacheOffset = m_BindingCount[Range]; + Uint32 SamplerIdx = ResourceAttribs::InvalidSamplerInd; + Int32 ImtblSamplerIdx = -1; + + if (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) + { + ImtblSamplerIdx = FindImmutableSampler(ResDesc.ShaderStages, ResDesc.Name); + if (ImtblSamplerIdx < 0) + SamplerIdx = FindAssignedSampler(ResDesc, ResourceAttribs::InvalidSamplerInd); + else + SamplerIdx = static_cast<Uint32>(ImtblSamplerIdx); + } + + new (m_pResourceAttribs + i) ResourceAttribs // + { + CacheOffset, + SamplerIdx, + ImtblSamplerIdx >= 0 // + }; + + m_BindingCount[Range] += ResDesc.ArraySize; + + if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) + StaticCounter[Range] += ResDesc.ArraySize; + } + } + + if (m_pStaticResCache) + { + m_pStaticResCache->Initialize(StaticCounter[BINDING_RANGE_UNIFORM_BUFFER], + StaticCounter[BINDING_RANGE_TEXTURE], + StaticCounter[BINDING_RANGE_IMAGE], + StaticCounter[BINDING_RANGE_STORAGE_BUFFER], + GetRawAllocator()); + // Set immutable samplers for static resources. + const auto ResIdxRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& ResDesc = GetResourceDesc(r); + const auto& ResAttr = GetResourceAttribs(r); + + if (ResDesc.ResourceType != SHADER_RESOURCE_TYPE_TEXTURE_SRV || !ResAttr.IsSamplerAssigned()) + continue; + + ISampler* Sampler = nullptr; + if (ResAttr.IsImmutableSamplerAssigned()) + { + VERIFY_EXPR(ResAttr.SamplerInd < GetImmutableSamplerCount()); + + Sampler = m_ImmutableSamplers[ResAttr.SamplerInd].RawPtr(); + } + else + { + const auto& SampAttr = GetResourceAttribs(ResAttr.SamplerInd); + if (!SampAttr.IsImmutableSamplerAssigned()) + continue; + + Sampler = m_ImmutableSamplers[SampAttr.SamplerInd].RawPtr(); + } + + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + m_pStaticResCache->SetSampler(ResAttr.CacheOffset + ArrInd, Sampler); + } +#ifdef DILIGENT_DEVELOPMENT + m_pStaticResCache->SetStaticResourcesInitialized(); +#endif + } +} + +size_t PipelineResourceSignatureGLImpl::CalculateHash() const +{ + if (m_Desc.NumResources == 0 && m_Desc.NumImmutableSamplers == 0) + return 0; + + auto Hash = CalculatePipelineResourceSignatureDescHash(m_Desc); + for (Uint32 i = 0; i < m_Desc.NumResources; ++i) + { + const auto& Attr = m_pResourceAttribs[i]; + HashCombine(Hash, Attr.CacheOffset); + } + + return Hash; +} + +PipelineResourceSignatureGLImpl::~PipelineResourceSignatureGLImpl() +{ + Destruct(); +} + +void PipelineResourceSignatureGLImpl::Destruct() +{ + auto& RawAllocator = GetRawAllocator(); + + if (m_ImmutableSamplers != nullptr) + { + for (Uint32 s = 0; s < m_Desc.NumImmutableSamplers; ++s) + m_ImmutableSamplers[s].~SamplerPtr(); + + m_ImmutableSamplers = nullptr; + } + + if (m_StaticVarsMgrs) + { + for (auto Idx : m_StaticResStageIndex) + { + if (Idx >= 0) + m_StaticVarsMgrs[Idx].~ShaderVariableGL(); + } + m_StaticVarsMgrs = nullptr; + } + + if (m_pStaticResCache) + { + m_pStaticResCache->Destroy(RawAllocator); + m_pStaticResCache = nullptr; + } + + if (void* pRawMem = m_pResourceAttribs) + { + RawAllocator.Free(pRawMem); + m_pResourceAttribs = nullptr; + } + + TPipelineResourceSignatureBase::Destruct(); +} + +void PipelineResourceSignatureGLImpl::ApplyBindings(GLObjectWrappers::GLProgramObj& GLProgram, + GLContextState& State, + SHADER_TYPE Stages, + const TBindings& Bindings) const +{ + VERIFY(GLProgram != 0, "Null GL program"); + State.SetProgram(GLProgram); + + for (Uint32 r = 0; r < GetTotalResourceCount(); ++r) + { + const auto& ResDesc = m_Desc.Resources[r]; + const auto& ResAttr = m_pResourceAttribs[r]; + const auto Range = PipelineResourceToBindingRange(ResDesc); + + if (Range == BINDING_RANGE_UNKNOWN) + continue; + + if ((ResDesc.ShaderStages & Stages) == 0) + continue; + + const Uint32 BindingIndex = Bindings[Range] + ResAttr.CacheOffset; + + static_assert(BINDING_RANGE_COUNT == 4, "Please update the switch below to handle the new shader resource range"); + switch (Range) + { + case BINDING_RANGE_UNIFORM_BUFFER: + { + auto UniformBlockIndex = glGetUniformBlockIndex(GLProgram, ResDesc.Name); + if (UniformBlockIndex == GL_INVALID_INDEX) + break; // Uniform block defined in resource signature, but not presented in shader program. + + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + glUniformBlockBinding(GLProgram, UniformBlockIndex + ArrInd, BindingIndex + ArrInd); + CHECK_GL_ERROR("glUniformBlockBinding() failed"); + } + break; + } + case BINDING_RANGE_TEXTURE: + { + auto UniformLocation = glGetUniformLocation(GLProgram, ResDesc.Name); + if (UniformLocation < 0) + break; // Uniform defined in resource signature, but not presented in shader program. + + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + glUniform1i(UniformLocation + ArrInd, BindingIndex + ArrInd); + CHECK_GL_ERROR("Failed to set binding point for sampler uniform '", ResDesc.Name, '\''); + } + break; + } +#if GL_ARB_shader_image_load_store + case BINDING_RANGE_IMAGE: + { + auto UniformLocation = glGetUniformLocation(GLProgram, ResDesc.Name); + if (UniformLocation < 0) + break; // Uniform defined in resource signature, but not presented in shader program. + + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + // glUniform1i for image uniforms is not supported in at least GLES3.2. + // glProgramUniform1i is not available in GLES3.0 + const Uint32 ImgBinding = BindingIndex + ArrInd; + glUniform1i(UniformLocation + ArrInd, ImgBinding); + if (glGetError() != GL_NO_ERROR) + { + if (ResDesc.ArraySize > 1) + { + LOG_WARNING_MESSAGE("Failed to set binding for image uniform '", ResDesc.Name, "'[", ArrInd, + "]. Expected binding: ", ImgBinding, + ". Make sure that this binding is explicitly assigned in shader source code." + " Note that if the source code is converted from HLSL and if images are only used" + " by a single shader stage, then bindings automatically assigned by HLSL->GLSL" + " converter will work fine."); + } + else + { + LOG_WARNING_MESSAGE("Failed to set binding for image uniform '", ResDesc.Name, + "'. Expected binding: ", ImgBinding, + ". Make sure that this binding is explicitly assigned in shader source code." + " Note that if the source code is converted from HLSL and if images are only used" + " by a single shader stage, then bindings automatically assigned by HLSL->GLSL" + " converter will work fine."); + } + } + } + break; + } +#endif +#if GL_ARB_shader_storage_buffer_object + case BINDING_RANGE_STORAGE_BUFFER: + { + auto SBIndex = glGetProgramResourceIndex(GLProgram, GL_SHADER_STORAGE_BLOCK, ResDesc.Name); + if (SBIndex == GL_INVALID_INDEX) + break; // Storage block defined in resource signature, but not presented in shader program. + + if (glShaderStorageBlockBinding) + { + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + glShaderStorageBlockBinding(GLProgram, SBIndex + ArrInd, BindingIndex + ArrInd); + CHECK_GL_ERROR("glShaderStorageBlockBinding() failed"); + } + } + else + { + const GLenum props[] = {GL_BUFFER_BINDING}; + GLint params[_countof(props)] = {}; + glGetProgramResourceiv(GLProgram, GL_SHADER_STORAGE_BLOCK, SBIndex, _countof(props), props, _countof(params), nullptr, params); + CHECK_GL_ERROR("glGetProgramResourceiv() failed"); + + if (BindingIndex != static_cast<Uint32>(params[0])) + { + LOG_WARNING_MESSAGE("glShaderStorageBlockBinding is not available on this device and " + "the engine is unable to automatically assign shader storage block bindindg for '", + ResDesc.Name, "' variable. Expected binding: ", BindingIndex, ", actual binding: ", params[0], + ". Make sure that this binding is explicitly assigned in shader source code." + " Note that if the source code is converted from HLSL and if storage blocks are only used" + " by a single shader stage, then bindings automatically assigned by HLSL->GLSL" + " converter will work fine."); + } + } + break; + } +#endif + default: + UNEXPECTED("Unsupported shader resource range type."); + } + } + + State.SetProgram(GLObjectWrappers::GLProgramObj::Null()); +} + +void PipelineResourceSignatureGLImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, + bool InitStaticResources) +{ + auto* pRenderDeviceGL = GetDevice(); + auto& SRBAllocator = pRenderDeviceGL->GetSRBAllocator(); + auto pResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this); + if (InitStaticResources) + InitializeStaticSRBResources(pResBinding); + pResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding)); +} + +void PipelineResourceSignatureGLImpl::InitializeStaticSRBResources(IShaderResourceBinding* pSRB) const +{ + InitializeStaticSRBResourcesImpl(ValidatedCast<ShaderResourceBindingGLImpl>(pSRB), + [&](ShaderResourceBindingGLImpl* pSRBGL) // + { + CopyStaticResources(pSRBGL->GetResourceCache()); + } // + ); +} + +Uint32 PipelineResourceSignatureGLImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const +{ + return GetStaticVariableCountImpl(ShaderType, m_StaticVarsMgrs); +} + +IShaderResourceVariable* PipelineResourceSignatureGLImpl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) +{ + return GetStaticVariableByNameImpl(ShaderType, Name, m_StaticVarsMgrs); +} + +IShaderResourceVariable* PipelineResourceSignatureGLImpl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) +{ + return GetStaticVariableByIndexImpl(ShaderType, Index, m_StaticVarsMgrs); +} + +void PipelineResourceSignatureGLImpl::BindStaticResources(Uint32 ShaderFlags, + IResourceMapping* pResMapping, + Uint32 Flags) +{ + BindStaticResourcesImpl(ShaderFlags, pResMapping, Flags, m_StaticVarsMgrs); +} + +void PipelineResourceSignatureGLImpl::CopyStaticResources(ShaderResourceCacheGL& DstResourceCache) const +{ + if (m_pStaticResCache == nullptr) + return; + + // SrcResourceCache contains only static resources. + // DstResourceCache contains static, mutable and dynamic resources. + const auto& SrcResourceCache = *m_pStaticResCache; + const auto ResIdxRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + + VERIFY_EXPR(SrcResourceCache.GetContentType() == ShaderResourceCacheGL::CacheContentType::Signature); + VERIFY_EXPR(DstResourceCache.GetContentType() == ShaderResourceCacheGL::CacheContentType::SRB); + + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& ResDesc = GetResourceDesc(r); + const auto& ResAttr = GetResourceAttribs(r); + VERIFY_EXPR(ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + + if (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER) + continue; // Skip separate samplers + + static_assert(BINDING_RANGE_COUNT == 4, "Please update the switch below to handle the new shader resource range"); + switch (PipelineResourceToBindingRange(ResDesc)) + { + case BINDING_RANGE_UNIFORM_BUFFER: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + const auto& SrcCachedRes = SrcResourceCache.GetConstUB(ResAttr.CacheOffset + ArrInd); + if (!SrcCachedRes.pBuffer) + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetShaderResourcePrintName(ResDesc, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); + + DstResourceCache.SetUniformBuffer(ResAttr.CacheOffset + ArrInd, RefCntAutoPtr<BufferGLImpl>{SrcCachedRes.pBuffer}); + } + break; + case BINDING_RANGE_STORAGE_BUFFER: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + const auto& SrcCachedRes = SrcResourceCache.GetConstSSBO(ResAttr.CacheOffset + ArrInd); + if (!SrcCachedRes.pBufferView) + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetShaderResourcePrintName(ResDesc, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); + + DstResourceCache.SetSSBO(ResAttr.CacheOffset + ArrInd, RefCntAutoPtr<BufferViewGLImpl>{SrcCachedRes.pBufferView}); + } + break; + case BINDING_RANGE_TEXTURE: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + const auto& SrcCachedRes = SrcResourceCache.GetConstTexture(ResAttr.CacheOffset + ArrInd); + if (!SrcCachedRes.pView) + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetShaderResourcePrintName(ResDesc, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); + + DstResourceCache.CopyTexture(ResAttr.CacheOffset + ArrInd, SrcCachedRes); + } + break; + case BINDING_RANGE_IMAGE: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + const auto& SrcCachedRes = SrcResourceCache.GetConstImage(ResAttr.CacheOffset + ArrInd); + if (!SrcCachedRes.pView) + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetShaderResourcePrintName(ResDesc, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); + + DstResourceCache.CopyImage(ResAttr.CacheOffset + ArrInd, SrcCachedRes); + } + break; + default: + UNEXPECTED("Unsupported shader resource range type."); + } + } + + // Copy immutable samplers. + for (Uint32 r = 0; r < m_Desc.NumResources; ++r) + { + const auto& ResDesc = GetResourceDesc(r); + const auto& ResAttr = GetResourceAttribs(r); + + if (ResDesc.ResourceType != SHADER_RESOURCE_TYPE_TEXTURE_SRV || + ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) + continue; + + if (!ResAttr.IsSamplerAssigned()) + continue; + + ISampler* Sampler = nullptr; + if (ResAttr.IsImmutableSamplerAssigned()) + { + VERIFY_EXPR(ResAttr.SamplerInd < GetImmutableSamplerCount()); + + Sampler = m_ImmutableSamplers[ResAttr.SamplerInd].RawPtr(); + } + else + { + const auto& SampAttr = GetResourceAttribs(ResAttr.SamplerInd); + if (!SampAttr.IsImmutableSamplerAssigned()) + continue; + + Sampler = m_ImmutableSamplers[SampAttr.SamplerInd].RawPtr(); + } + + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + DstResourceCache.SetSampler(ResAttr.CacheOffset + ArrInd, Sampler); + } + +#ifdef DILIGENT_DEVELOPMENT + DstResourceCache.SetStaticResourcesInitialized(); +#endif +} + +void PipelineResourceSignatureGLImpl::InitSRBResourceCache(ShaderResourceCacheGL& ResourceCache) const +{ + ResourceCache.Initialize(m_BindingCount[BINDING_RANGE_UNIFORM_BUFFER], + m_BindingCount[BINDING_RANGE_TEXTURE], + m_BindingCount[BINDING_RANGE_IMAGE], + m_BindingCount[BINDING_RANGE_STORAGE_BUFFER], + GetRawAllocator()); +} + +bool PipelineResourceSignatureGLImpl::IsCompatibleWith(const PipelineResourceSignatureGLImpl& Other) const +{ + if (this == &Other) + return true; + + if (GetHash() != Other.GetHash()) + return false; + + if (m_BindingCount != Other.m_BindingCount) + return false; + + if (!PipelineResourceSignaturesCompatible(GetDesc(), Other.GetDesc())) + return false; + + const auto ResCount = GetTotalResourceCount(); + VERIFY_EXPR(ResCount == Other.GetTotalResourceCount()); + for (Uint32 r = 0; r < ResCount; ++r) + { + if (!ResourcesCompatible(GetResourceAttribs(r), Other.GetResourceAttribs(r))) + return false; + } + + return true; +} + +#ifdef DILIGENT_DEVELOPMENT +bool PipelineResourceSignatureGLImpl::DvpValidateCommittedResource(const ShaderResourcesGL::GLResourceAttribs& GLAttribs, + RESOURCE_DIMENSION ResourceDim, + bool IsMultisample, + Uint32 ResIndex, + const ShaderResourceCacheGL& ResourceCache, + const char* ShaderName, + const char* PSOName) const +{ + VERIFY_EXPR(ResIndex < m_Desc.NumResources); + const auto& ResDesc = m_Desc.Resources[ResIndex]; + const auto& ResAttr = m_pResourceAttribs[ResIndex]; + VERIFY(strcmp(ResDesc.Name, GLAttribs.Name) == 0, "Inconsistent resource names"); + + if (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER) + return true; // Skip separate samplers + + VERIFY_EXPR(GLAttribs.ArraySize <= ResDesc.ArraySize); + + bool BindingsOK = true; + + static_assert(BINDING_RANGE_COUNT == 4, "Please update the switch below to handle the new shader resource range"); + switch (PipelineResourceToBindingRange(ResDesc)) + { + case BINDING_RANGE_UNIFORM_BUFFER: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + if (!ResourceCache.IsUBBound(ResAttr.CacheOffset + ArrInd)) + { + LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(GLAttribs, ArrInd), + "' in shader '", ShaderName, "' of PSO '", PSOName, "'"); + BindingsOK = false; + continue; + } + } + break; + case BINDING_RANGE_STORAGE_BUFFER: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + if (!ResourceCache.IsSSBOBound(ResAttr.CacheOffset + ArrInd)) + { + LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(GLAttribs, ArrInd), + "' in shader '", ShaderName, "' of PSO '", PSOName, "'"); + BindingsOK = false; + continue; + } + } + break; + case BINDING_RANGE_TEXTURE: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + if (!ResourceCache.IsTextureBound(ResAttr.CacheOffset + ArrInd, ResDesc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV)) + { + LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(GLAttribs, ArrInd), + "' in shader '", ShaderName, "' of PSO '", PSOName, "'"); + BindingsOK = false; + continue; + } + + const auto& Tex = ResourceCache.GetConstTexture(ResAttr.CacheOffset + ArrInd); + if (Tex.pTexture) + ValidateResourceViewDimension(ResDesc.Name, ResDesc.ArraySize, ArrInd, Tex.pView.RawPtr<ITextureView>(), ResourceDim, IsMultisample); + else + ValidateResourceViewDimension(ResDesc.Name, ResDesc.ArraySize, ArrInd, Tex.pView.RawPtr<IBufferView>(), ResourceDim, IsMultisample); + } + break; + case BINDING_RANGE_IMAGE: + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + if (!ResourceCache.IsImageBound(ResAttr.CacheOffset + ArrInd, ResDesc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV)) + { + LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(GLAttribs, ArrInd), + "' in shader '", ShaderName, "' of PSO '", PSOName, "'"); + BindingsOK = false; + continue; + } + + const auto& Img = ResourceCache.GetConstImage(ResAttr.CacheOffset + ArrInd); + if (Img.pTexture) + ValidateResourceViewDimension(ResDesc.Name, ResDesc.ArraySize, ArrInd, Img.pView.RawPtr<ITextureView>(), ResourceDim, IsMultisample); + else + ValidateResourceViewDimension(ResDesc.Name, ResDesc.ArraySize, ArrInd, Img.pView.RawPtr<IBufferView>(), ResourceDim, IsMultisample); + } + break; + default: + UNEXPECTED("Unsupported shader resource range type."); + } + return BindingsOK; +} +#endif // DILIGENT_DEVELOPMENT + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp index 43cfc9e0..4aff0b55 100644 --- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp @@ -36,41 +36,270 @@ namespace Diligent { +void PipelineStateGLImpl::CreateDefaultSignature(const PipelineStateCreateInfo& CreateInfo, + const TShaderStages& ShaderStages, + SHADER_TYPE ActiveStages, + IPipelineResourceSignature** ppSignature) +{ + std::vector<PipelineResourceDesc> Resources; -template <typename PSOCreateInfoType> -void PipelineStateGLImpl::Initialize(const PSOCreateInfoType& CreateInfo, std::vector<ShaderGLImpl*>& Shaders) + const auto& LayoutDesc = CreateInfo.PSODesc.ResourceLayout; + const auto DefaultVarType = LayoutDesc.DefaultVariableType; + ShaderResourcesGL ProgramResources; + + struct UniqueResource + { + const ShaderResourcesGL::GLResourceAttribs& Attribs; + const SHADER_TYPE ShaderStages; + + bool operator==(const UniqueResource& Res) const + { + return strcmp(Attribs.Name, Res.Attribs.Name) == 0 && ShaderStages == Res.ShaderStages; + } + + struct Hasher + { + size_t operator()(const UniqueResource& Res) const + { + return ComputeHash(CStringHash<Char>{}(Res.Attribs.Name), Uint32{Res.ShaderStages}); + } + }; + }; + std::unordered_set<UniqueResource, UniqueResource::Hasher> UniqueResources; + + const auto HandleResource = [&](const ShaderResourcesGL::GLResourceAttribs& Attribs, PIPELINE_RESOURCE_FLAGS Flags) // + { + PipelineResourceDesc ResDesc = {}; + + ResDesc.Name = Attribs.Name; + ResDesc.ShaderStages = Attribs.ShaderStages; + ResDesc.ArraySize = Attribs.ArraySize; + ResDesc.ResourceType = Attribs.ResourceType; + ResDesc.VarType = DefaultVarType; + ResDesc.Flags = Flags; + + if (m_IsProgramPipelineSupported) + { + const auto VarIndex = FindPipelineResourceLayoutVariable(LayoutDesc, Attribs.Name, ResDesc.ShaderStages, nullptr); + if (VarIndex != InvalidPipelineResourceLayoutVariableIndex) + { + const auto& Var = LayoutDesc.Variables[VarIndex]; + ResDesc.ShaderStages = Var.ShaderStages; + ResDesc.VarType = Var.Type; + } + + auto IterAndAssigned = UniqueResources.emplace(UniqueResource{Attribs, ResDesc.ShaderStages}); + if (IterAndAssigned.second) + { + Resources.push_back(ResDesc); + } + else + { + DEV_CHECK_ERR(IterAndAssigned.first->Attribs.ResourceType == Attribs.ResourceType, + "Shader variable '", Attribs.Name, + "' exists in multiple shaders from the same shader stage, but its type is not consistent between " + "shaders. All variables with the same name from the same shader stage must have the same type."); + } + } + else + { + for (Uint32 i = 0; i < LayoutDesc.NumVariables; ++i) + { + const auto& Var = LayoutDesc.Variables[i]; + if ((Var.ShaderStages & Attribs.ShaderStages) != 0 && + std::strcmp(Attribs.Name, Var.Name) == 0) + { + ResDesc.VarType = Var.Type; + break; + } + } + Resources.push_back(ResDesc); + } + }; + const auto HandleUB = [&](const ShaderResourcesGL::UniformBufferInfo& Attribs) { + HandleResource(Attribs, PIPELINE_RESOURCE_FLAG_UNKNOWN); + }; + const auto HandleTexture = [&](const ShaderResourcesGL::TextureInfo& Attribs) { + HandleResource(Attribs, Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV ? PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER : PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER); + }; + const auto HandleImage = [&](const ShaderResourcesGL::ImageInfo& Attribs) { + HandleResource(Attribs, Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV ? PIPELINE_RESOURCE_FLAG_UNKNOWN : PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER); + }; + const auto HandleSB = [&](const ShaderResourcesGL::StorageBlockInfo& Attribs) { + HandleResource(Attribs, PIPELINE_RESOURCE_FLAG_UNKNOWN); + }; + + if (m_IsProgramPipelineSupported) + { + for (size_t i = 0; i < ShaderStages.size(); ++i) + { + auto* pShaderGL = ShaderStages[i].pShader; + pShaderGL->GetShaderResources()->ProcessConstResources(HandleUB, HandleTexture, HandleImage, HandleSB); + } + } + else + { + auto pImmediateCtx = m_pDevice->GetImmediateContext(); + VERIFY_EXPR(pImmediateCtx); + VERIFY_EXPR(m_GLPrograms[0] != 0); + + ProgramResources.LoadUniforms(ActiveStages, m_GLPrograms[0], pImmediateCtx.RawPtr<DeviceContextGLImpl>()->GetContextState()); + ProgramResources.ProcessConstResources(HandleUB, HandleTexture, HandleImage, HandleSB); + } + + if (Resources.size()) + { + String SignName = String{"Implicit signature for PSO '"} + m_Desc.Name + '\''; + + PipelineResourceSignatureDesc ResSignDesc = {}; + + ResSignDesc.Name = SignName.c_str(); + ResSignDesc.Resources = Resources.data(); + ResSignDesc.NumResources = static_cast<Uint32>(Resources.size()); + ResSignDesc.ImmutableSamplers = LayoutDesc.ImmutableSamplers; + ResSignDesc.NumImmutableSamplers = LayoutDesc.NumImmutableSamplers; + ResSignDesc.BindingIndex = 0; + ResSignDesc.SRBAllocationGranularity = CreateInfo.PSODesc.SRBAllocationGranularity; + ResSignDesc.UseCombinedTextureSamplers = true; + + GetDevice()->CreatePipelineResourceSignature(ResSignDesc, ppSignature, true); + + if (*ppSignature == nullptr) + LOG_ERROR_AND_THROW("Failed to create resource signature for pipeline state"); + } +} + +void PipelineStateGLImpl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + const TShaderStages& ShaderStages, + SHADER_TYPE ActiveStages) { - FixedLinearAllocator MemPool{GetRawAllocator()}; - VERIFY_EXPR(m_NumShaderStages > 0 && m_NumShaderStages == Shaders.size()); - if (!GetDevice()->GetDeviceCaps().Features.SeparablePrograms) - m_NumShaderStages = 1; + const Uint32 SignatureCount = CreateInfo.ResourceSignaturesCount; + RefCntAutoPtr<IPipelineResourceSignature> pImplicitSignature; - const auto NumPrograms = GetNumShaderStages(); + if (SignatureCount == 0 || CreateInfo.ppResourceSignatures == nullptr) + { + CreateDefaultSignature(CreateInfo, ShaderStages, ActiveStages, &pImplicitSignature); + if (pImplicitSignature != nullptr) + { + VERIFY_EXPR(pImplicitSignature->GetDesc().BindingIndex == 0); + m_Signatures[0] = ValidatedCast<PipelineResourceSignatureGLImpl>(pImplicitSignature.RawPtr()); + m_SignatureCount = 1; + } + } + else + { + const auto MaxBindingIndex = + PipelineResourceSignatureGLImpl::CopyResourceSignatures(CreateInfo.PSODesc.PipelineType, SignatureCount, CreateInfo.ppResourceSignatures, + m_Signatures.data(), m_Signatures.size()); + m_SignatureCount = static_cast<decltype(m_SignatureCount)>(MaxBindingIndex + 1); + VERIFY_EXPR(m_SignatureCount == MaxBindingIndex + 1); + } - MemPool.AddSpace<GLProgramObj>(NumPrograms); - MemPool.AddSpace<GLProgramResources>(NumPrograms); - MemPool.AddSpace<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers); + // Apply resource bindings to programs. + auto& CtxState = m_pDevice->GetImmediateContext().RawPtr<DeviceContextGLImpl>()->GetContextState(); - ReserveSpaceForPipelineDesc(CreateInfo, MemPool); + PipelineResourceSignatureGLImpl::TBindings Bindings = {}; - MemPool.Reserve(); + for (Uint32 s = 0; s < m_SignatureCount; ++s) + { + const auto& pSignature = m_Signatures[s]; + if (pSignature == nullptr) + continue; - m_GLPrograms = MemPool.ConstructArray<GLProgramObj>(NumPrograms, false); + if (m_IsProgramPipelineSupported) + { + for (Uint32 p = 0; p < m_NumPrograms; ++p) + pSignature->ApplyBindings(m_GLPrograms[p], CtxState, GetShaderStageType(p), Bindings); + } + else + { + pSignature->ApplyBindings(m_GLPrograms[0], CtxState, ActiveStages, Bindings); + } + pSignature->AddBindings(Bindings); + } - // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct(). - auto* Ptr = MemPool.ReleaseOwnership(); - VERIFY_EXPR(Ptr == m_GLPrograms); - (void)Ptr; +#ifdef DILIGENT_DEVELOPMENT + const auto& Limits = GetDevice()->GetDeviceLimits(); - m_ProgramResources = MemPool.ConstructArray<GLProgramResources>(NumPrograms); + DEV_CHECK_ERR(Bindings[BINDING_RANGE_UNIFORM_BUFFER] <= static_cast<Uint32>(Limits.MaxUniformBlocks), + "Number of bindings in range '", GetBindingRangeName(BINDING_RANGE_UNIFORM_BUFFER), "' is greater than maximum allowed (", Limits.MaxUniformBlocks, ")."); + DEV_CHECK_ERR(Bindings[BINDING_RANGE_TEXTURE] <= static_cast<Uint32>(Limits.MaxTextureUnits), + "Number of bindings in range '", GetBindingRangeName(BINDING_RANGE_TEXTURE), "' is greater than maximum allowed (", Limits.MaxTextureUnits, ")."); + DEV_CHECK_ERR(Bindings[BINDING_RANGE_STORAGE_BUFFER] <= static_cast<Uint32>(Limits.MaxStorageBlock), + "Number of bindings in range '", GetBindingRangeName(BINDING_RANGE_STORAGE_BUFFER), "' is greater than maximum allowed (", Limits.MaxStorageBlock, ")."); + DEV_CHECK_ERR(Bindings[BINDING_RANGE_IMAGE] <= static_cast<Uint32>(Limits.MaxImagesUnits), + "Number of bindings in range '", GetBindingRangeName(BINDING_RANGE_IMAGE), "' is greater than maximum allowed (", Limits.MaxImagesUnits, ")."); - m_ImmutableSamplers = MemPool.ConstructArray<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers); + if (m_IsProgramPipelineSupported) + { + for (size_t i = 0; i < ShaderStages.size(); ++i) + { + auto* pShaderGL = ShaderStages[i].pShader; + DvpValidateShaderResources(pShaderGL->GetShaderResources(), pShaderGL->GetDesc().Name, pShaderGL->GetDesc().ShaderType); + } + } + else + { + auto pImmediateCtx = m_pDevice->GetImmediateContext(); + VERIFY_EXPR(pImmediateCtx); + VERIFY_EXPR(m_GLPrograms[0] != 0); + + std::unique_ptr<ShaderResourcesGL> pResources{new ShaderResourcesGL{}}; + pResources->LoadUniforms(ActiveStages, m_GLPrograms[0], pImmediateCtx.RawPtr<DeviceContextGLImpl>()->GetContextState()); + + std::shared_ptr<const ShaderResourcesGL> pShaderResources{pResources.release()}; + DvpValidateShaderResources(pShaderResources, m_Desc.Name, ActiveStages); + } +#endif +} + +template <typename PSOCreateInfoType> +void PipelineStateGLImpl::InitInternalObjects(const PSOCreateInfoType& CreateInfo, const TShaderStages& ShaderStages) +{ + const auto& deviceCaps = GetDevice()->GetDeviceCaps(); + VERIFY(deviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized"); + + m_IsProgramPipelineSupported = deviceCaps.Features.SeparablePrograms != DEVICE_FEATURE_STATE_DISABLED; + + FixedLinearAllocator MemPool{GetRawAllocator()}; + + ReserveSpaceForPipelineDesc(CreateInfo, MemPool); + MemPool.AddSpace<GLProgramObj>(m_IsProgramPipelineSupported ? ShaderStages.size() : 1); - // It is important to construct all objects before initializing them because if an exception is thrown, - // destructors will be called for all objects + MemPool.Reserve(); - InitResourceLayouts(Shaders, MemPool); InitializePipelineDesc(CreateInfo, MemPool); + + // Get active shader stages. + SHADER_TYPE ActiveStages = SHADER_TYPE_UNKNOWN; + for (auto& Stage : ShaderStages) + { + const auto ShaderType = Stage.pShader->GetDesc().ShaderType; + VERIFY((ActiveStages & ShaderType) == 0, "Shader stage ", GetShaderTypeLiteralName(ShaderType), " is already active"); + ActiveStages |= ShaderType; + } + + // Create programs. + if (m_IsProgramPipelineSupported) + { + m_GLPrograms = MemPool.ConstructArray<GLProgramObj>(ShaderStages.size(), false); + for (size_t i = 0; i < ShaderStages.size(); ++i) + { + auto* pShaderGL = ShaderStages[i].pShader; + m_GLPrograms[i] = GLProgramObj{ShaderGLImpl::LinkProgram(&ShaderStages[i], 1, true)}; + m_ShaderTypes[i] = pShaderGL->GetDesc().ShaderType; + } + m_NumPrograms = static_cast<Uint8>(ShaderStages.size()); + } + else + { + m_GLPrograms = MemPool.ConstructArray<GLProgramObj>(1, false); + m_GLPrograms[0] = ShaderGLImpl::LinkProgram(ShaderStages.data(), static_cast<Uint32>(ShaderStages.size()), false); + m_ShaderTypes[0] = ActiveStages; + m_NumPrograms = 1; + } + + InitResourceLayouts(CreateInfo, ShaderStages, ActiveStages); } PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters, @@ -84,14 +313,12 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pDeviceGL, CreateInfo, bIsDeviceInternal - }, - m_ResourceLayout {*this}, - m_StaticResourceLayout{*this} + } // clang-format on { try { - std::vector<ShaderGLImpl*> Shaders; + TShaderStages Shaders; ExtractShaders<ShaderGLImpl>(CreateInfo, Shaders); RefCntAutoPtr<ShaderGLImpl> pTempPS; @@ -107,14 +334,14 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pDeviceGL->CreateShader(ShaderCI, reinterpret_cast<IShader**>(static_cast<ShaderGLImpl**>(&pTempPS))); Shaders.emplace_back(pTempPS); - m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_PIXEL; } - Initialize(CreateInfo, Shaders); + InitInternalObjects(CreateInfo, Shaders); } catch (...) { Destruct(); + throw; } } @@ -129,21 +356,20 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* p pDeviceGL, CreateInfo, bIsDeviceInternal - }, - m_ResourceLayout {*this}, - m_StaticResourceLayout{*this} + } // clang-format on { try { - std::vector<ShaderGLImpl*> Shaders; + TShaderStages Shaders; ExtractShaders<ShaderGLImpl>(CreateInfo, Shaders); - Initialize(CreateInfo, Shaders); + InitInternalObjects(CreateInfo, Shaders); } catch (...) { Destruct(); + throw; } } @@ -154,123 +380,31 @@ PipelineStateGLImpl::~PipelineStateGLImpl() void PipelineStateGLImpl::Destruct() { - auto& RawAllocator = GetRawAllocator(); - m_StaticResourceCache.Destroy(RawAllocator); GetDevice()->OnDestroyPSO(this); - if (m_ImmutableSamplers != nullptr) + if (m_GLPrograms) { - for (Uint32 i = 0; i < m_Desc.ResourceLayout.NumImmutableSamplers; ++i) - { - m_ImmutableSamplers[i].~SamplerPtr(); - } - } - - for (Uint32 i = 0; i < GetNumShaderStages(); ++i) - { - if (m_GLPrograms != nullptr) + for (Uint32 i = 0; i < m_NumPrograms; ++i) { m_GLPrograms[i].~GLProgramObj(); } - if (m_ProgramResources != nullptr) - { - m_ProgramResources[i].~GLProgramResources(); - } + m_GLPrograms = nullptr; } - if (void* pRawMem = m_GLPrograms) - { - RawAllocator.Free(pRawMem); - } + m_Signatures.fill({}); + + m_SignatureCount = 0; + m_NumPrograms = 0; TPipelineStateBase::Destruct(); } IMPLEMENT_QUERY_INTERFACE(PipelineStateGLImpl, IID_PipelineStateGL, TPipelineStateBase) - -void PipelineStateGLImpl::InitResourceLayouts(std::vector<ShaderGLImpl*>& Shaders, - FixedLinearAllocator& MemPool) +SHADER_TYPE PipelineStateGLImpl::GetShaderStageType(Uint32 Index) const { - auto* const pDeviceGL = GetDevice(); - const auto& deviceCaps = pDeviceGL->GetDeviceCaps(); - VERIFY(deviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized"); - - auto pImmediateCtx = m_pDevice->GetImmediateContext(); - VERIFY_EXPR(pImmediateCtx); - auto& GLState = pImmediateCtx.RawPtr<DeviceContextGLImpl>()->GetContextState(); - - { - m_TotalUniformBufferBindings = 0; - m_TotalSamplerBindings = 0; - m_TotalImageBindings = 0; - m_TotalStorageBufferBindings = 0; - if (deviceCaps.Features.SeparablePrograms) - { - // Program pipelines are not shared between GL contexts, so we cannot create - // it now - m_ShaderResourceLayoutHash = 0; - for (size_t i = 0; i < Shaders.size(); ++i) - { - auto* pShaderGL = Shaders[i]; - const auto& ShaderDesc = pShaderGL->GetDesc(); - m_GLPrograms[i] = GLProgramObj{ShaderGLImpl::LinkProgram(&pShaderGL, 1, true)}; - // Load uniforms and assign bindings - m_ProgramResources[i].LoadUniforms(ShaderDesc.ShaderType, m_GLPrograms[i], GLState, - m_TotalUniformBufferBindings, - m_TotalSamplerBindings, - m_TotalImageBindings, - m_TotalStorageBufferBindings); - - HashCombine(m_ShaderResourceLayoutHash, m_ProgramResources[i].GetHash()); - } - } - else - { - SHADER_TYPE ActiveStages = SHADER_TYPE_UNKNOWN; - for (const auto* pShader : Shaders) - { - const auto ShaderType = pShader->GetDesc().ShaderType; - VERIFY((ActiveStages & ShaderType) == 0, "Shader stage ", GetShaderTypeLiteralName(ShaderType), " is already active"); - ActiveStages |= ShaderType; - } - - m_GLPrograms[0] = ShaderGLImpl::LinkProgram(Shaders.data(), static_cast<Uint32>(Shaders.size()), false); - - m_ProgramResources[0].LoadUniforms(ActiveStages, m_GLPrograms[0], GLState, - m_TotalUniformBufferBindings, - m_TotalSamplerBindings, - m_TotalImageBindings, - m_TotalStorageBufferBindings); - - m_ShaderResourceLayoutHash = m_ProgramResources[0].GetHash(); - } - - // Initialize master resource layout that keeps all variable types and does not reference a resource cache - m_ResourceLayout.Initialize(m_ProgramResources, GetNumShaderStages(), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr); - } - - for (Uint32 s = 0; s < m_Desc.ResourceLayout.NumImmutableSamplers; ++s) - { - pDeviceGL->CreateSampler(m_Desc.ResourceLayout.ImmutableSamplers[s].Desc, &m_ImmutableSamplers[s]); - } - - { - // Clone only static variables into static resource layout, assign and initialize static resource cache - const SHADER_RESOURCE_VARIABLE_TYPE StaticVars[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - m_StaticResourceLayout.Initialize(m_ProgramResources, GetNumShaderStages(), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache); - InitImmutableSamplersInResourceCache(m_StaticResourceLayout, m_StaticResourceCache); - } -} - -void PipelineStateGLImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) -{ - auto* pRenderDeviceGL = GetDevice(); - auto& SRBAllocator = pRenderDeviceGL->GetSRBAllocator(); - auto pResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this, m_ProgramResources, GetNumShaderStages()); - if (InitStaticResources) - pResBinding->InitializeStaticResources(this); - pResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding)); + VERIFY(Index < m_NumPrograms, "Index is out of range"); + return m_ShaderTypes[Index]; } bool PipelineStateGLImpl::IsCompatibleWith(const IPipelineState* pPSO) const @@ -280,27 +414,23 @@ bool PipelineStateGLImpl::IsCompatibleWith(const IPipelineState* pPSO) const if (pPSO == this) return true; - const PipelineStateGLImpl* pPSOGL = ValidatedCast<const PipelineStateGLImpl>(pPSO); - if (m_ShaderResourceLayoutHash != pPSOGL->m_ShaderResourceLayoutHash) - return false; + const auto& lhs = *this; + const auto& rhs = *ValidatedCast<const PipelineStateGLImpl>(pPSO); - if (GetNumShaderStages() != pPSOGL->GetNumShaderStages()) + if (lhs.GetSignatureCount() != rhs.GetSignatureCount()) return false; - for (size_t i = 0; i < GetNumShaderStages(); ++i) + for (Uint32 s = 0, SigCount = lhs.GetSignatureCount(); s < SigCount; ++s) { - if (!m_ProgramResources[i].IsCompatibleWith(pPSOGL->m_ProgramResources[i])) + if (!lhs.GetSignature(s)->IsCompatibleWith(*rhs.GetSignature(s))) return false; } - return true; } void PipelineStateGLImpl::CommitProgram(GLContextState& State) { - auto ProgramPipelineSupported = m_pDevice->GetDeviceCaps().Features.SeparablePrograms; - - if (ProgramPipelineSupported) + if (m_IsProgramPipelineSupported) { // WARNING: glUseProgram() overrides glBindProgramPipeline(). That is, if you have a program in use and // a program pipeline bound, all rendering will use the program that is in use, not the pipeline programs! @@ -342,65 +472,180 @@ GLObjectWrappers::GLPipelineObj& PipelineStateGLImpl::GetGLProgramPipeline(GLCon return ctx_pipeline.second; } -void PipelineStateGLImpl::InitializeSRBResourceCache(GLProgramResourceCache& ResourceCache) const +#ifdef DILIGENT_DEVELOPMENT +PipelineStateGLImpl::ResourceAttribution PipelineStateGLImpl::GetResourceAttribution(const char* Name, SHADER_TYPE Stage) const { - ResourceCache.Initialize(m_TotalUniformBufferBindings, m_TotalSamplerBindings, m_TotalImageBindings, m_TotalStorageBufferBindings, GetRawAllocator()); - InitImmutableSamplersInResourceCache(m_ResourceLayout, ResourceCache); -} - -void PipelineStateGLImpl::InitImmutableSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache) const -{ - for (Uint32 s = 0; s < ResourceLayout.GetNumResources<GLPipelineResourceLayout::SamplerBindInfo>(); ++s) + const auto SignCount = GetSignatureCount(); + for (Uint32 sign = 0; sign < SignCount; ++sign) { - const auto& Sam = ResourceLayout.GetConstResource<GLPipelineResourceLayout::SamplerBindInfo>(s); - if (Sam.m_ImtblSamplerIdx >= 0) + const auto* const pSignature = GetSignature(sign); + if (pSignature == nullptr) + continue; + + const auto ResIndex = pSignature->FindResource(Stage, Name); + if (ResIndex != ResourceAttribution::InvalidResourceIndex) + return ResourceAttribution{pSignature, sign, ResIndex}; + else { - ISampler* pSampler = m_ImmutableSamplers[Sam.m_ImtblSamplerIdx].RawPtr<ISampler>(); - for (Uint32 binding = Sam.m_Attribs.Binding; binding < Sam.m_Attribs.Binding + Sam.m_Attribs.ArraySize; ++binding) - Cache.SetImmutableSampler(binding, pSampler); + const auto ImtblSamIndex = pSignature->FindImmutableSampler(Stage, Name); + if (ImtblSamIndex != ResourceAttribution::InvalidSamplerIndex) + return ResourceAttribution{pSignature, sign, ResourceAttribution::InvalidResourceIndex, ImtblSamIndex}; } } + return ResourceAttribution{}; } -void PipelineStateGLImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) +void PipelineStateGLImpl::DvpValidateShaderResources(const std::shared_ptr<const ShaderResourcesGL>& pShaderResources, const char* ShaderName, SHADER_TYPE ShaderStages) { - m_StaticResourceLayout.BindResources(static_cast<SHADER_TYPE>(ShaderFlags), pResourceMapping, Flags, m_StaticResourceCache); -} + m_ShaderResources.emplace_back(pShaderResources); + m_ShaderNames.emplace_back(ShaderName); -Uint32 PipelineStateGLImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const -{ - if (!IsConsistentShaderType(ShaderType, m_Desc.PipelineType)) + const auto HandleResource = [&](const ShaderResourcesGL::GLResourceAttribs& Attribs, SHADER_RESOURCE_TYPE ReadOnlyResourceType, PIPELINE_RESOURCE_FLAGS Flags) // { - LOG_WARNING_MESSAGE("Unable to get the number of static variables in shader stage ", GetShaderTypeLiteralName(ShaderType), - " as the stage is invalid for ", GetPipelineTypeString(m_Desc.PipelineType), " pipeline '", m_Desc.Name, "'"); - return 0; - } + m_ResourceAttibutions.emplace_back(); + auto& ResAttribution = m_ResourceAttibutions.back(); + + ResAttribution = GetResourceAttribution(Attribs.Name, ShaderStages); + if (!ResAttribution) + { + LOG_ERROR_AND_THROW("Shader '", ShaderName, "' contains resource '", Attribs.Name, + "' that is not present in any pipeline resource signature used to create pipeline state '", + m_Desc.Name, "'."); + } + + const auto* const pSignature = ResAttribution.pSignature; + VERIFY_EXPR(pSignature != nullptr); - return m_StaticResourceLayout.GetNumVariables(ShaderType); + if (ResAttribution.ResourceIndex != ResourceAttribution::InvalidResourceIndex) + { + const auto& ResDesc = pSignature->GetResourceDesc(ResAttribution.ResourceIndex); + + // Shader reflection does not contain read-only flag, so image and storage buffer can be UAV or SRV. + if (Attribs.ResourceType != ResDesc.ResourceType && + ReadOnlyResourceType != ResDesc.ResourceType) + { + LOG_ERROR_AND_THROW("Shader '", ShaderName, "' contains resource with name '", Attribs.Name, + "' and type '", GetShaderResourceTypeLiteralName(Attribs.ResourceType), "' that is not compatible with type '", + GetShaderResourceTypeLiteralName(ResDesc.ResourceType), "' in pipeline resource signature '", pSignature->GetDesc().Name, "'."); + } + + if ((Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) != (ResDesc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER)) + { + LOG_ERROR_AND_THROW("Shader '", ShaderName, "' contains resource '", Attribs.Name, + "' that is", ((Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) ? "" : " not"), + " labeled as formatted buffer, while the same resource specified by the pipeline resource signature '", + pSignature->GetDesc().Name, "' is", ((ResDesc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) ? "" : " not"), + " labeled as such."); + } + } + }; + + const auto HandleUB = [&](const ShaderResourcesGL::UniformBufferInfo& Attribs) { + HandleResource(Attribs, Attribs.ResourceType, PIPELINE_RESOURCE_FLAG_UNKNOWN); + }; + + const auto HandleTexture = [&](const ShaderResourcesGL::TextureInfo& Attribs) { + const bool IsTexelBuffer = (Attribs.ResourceType != SHADER_RESOURCE_TYPE_TEXTURE_SRV); + HandleResource(Attribs, + Attribs.ResourceType, + IsTexelBuffer ? PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER : PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER); + }; + + const auto HandleImage = [&](const ShaderResourcesGL::ImageInfo& Attribs) { + const bool IsImageBuffer = (Attribs.ResourceType != SHADER_RESOURCE_TYPE_TEXTURE_UAV); + HandleResource(Attribs, + IsImageBuffer ? SHADER_RESOURCE_TYPE_BUFFER_SRV : SHADER_RESOURCE_TYPE_TEXTURE_SRV, + IsImageBuffer ? PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER : PIPELINE_RESOURCE_FLAG_UNKNOWN); + }; + + const auto HandleSB = [&](const ShaderResourcesGL::StorageBlockInfo& Attribs) { + HandleResource(Attribs, SHADER_RESOURCE_TYPE_BUFFER_SRV, PIPELINE_RESOURCE_FLAG_UNKNOWN); + }; + + pShaderResources->ProcessConstResources(HandleUB, HandleTexture, HandleImage, HandleSB); } -IShaderResourceVariable* PipelineStateGLImpl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) +void PipelineStateGLImpl::DvpVerifySRBResources(ShaderResourceBindingGLImpl* pSRBs[], + const TBindings BoundResOffsets[], + Uint32 NumSRBs) const { - if (!IsConsistentShaderType(ShaderType, m_Desc.PipelineType)) + // Verify SRB compatibility with this pipeline + const auto SignCount = GetResourceSignatureCount(); + TBindings Bindings = {}; + for (Uint32 sign = 0; sign < SignCount; ++sign) { - LOG_WARNING_MESSAGE("Unable to find static variable '", Name, "' in shader stage ", GetShaderTypeLiteralName(ShaderType), - " as the stage is invalid for ", GetPipelineTypeString(m_Desc.PipelineType), " pipeline '", m_Desc.Name, "'"); - return nullptr; + // Get resource signature from the root signature + const auto& pSignature = GetSignature(sign); + if (pSignature == nullptr || pSignature->GetTotalResourceCount() == 0) + continue; // Skip null and empty signatures + + VERIFY_EXPR(pSignature->GetDesc().BindingIndex == sign); + const auto* const pSRB = pSRBs[sign]; + if (pSRB == nullptr) + { + LOG_ERROR_MESSAGE("Pipeline state '", m_Desc.Name, "' requires SRB at index ", sign, " but none is bound in the device context."); + continue; + } + + const auto* const pSRBSign = pSRB->GetSignature(); + if (!pSignature->IsCompatibleWith(pSRBSign)) + { + LOG_ERROR_MESSAGE("Shader resource binding at index ", sign, " with signature '", pSRBSign->GetDesc().Name, + "' is not compatible with pipeline layout in current pipeline '", m_Desc.Name, "'."); + } + + DEV_CHECK_ERR(Bindings == BoundResOffsets[sign], + "Bound resources has incorrect base binding indices, this may indicate a bug in resource signature compatibility comparison."); + + pSignature->AddBindings(Bindings); } - return m_StaticResourceLayout.GetShaderVariable(ShaderType, Name); -} -IShaderResourceVariable* PipelineStateGLImpl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) -{ - if (!IsConsistentShaderType(ShaderType, m_Desc.PipelineType)) + using AttribIter = std::vector<ResourceAttribution>::const_iterator; + struct HandleResourceHelper { - LOG_WARNING_MESSAGE("Unable to get static variable at index ", Index, " in shader stage ", GetShaderTypeLiteralName(ShaderType), - " as the stage is invalid for ", GetPipelineTypeString(m_Desc.PipelineType), " pipeline '", m_Desc.Name, "'"); - return nullptr; - } + PipelineStateGLImpl const& PSO; + ShaderResourceBindingGLImpl** ppSRBs; + const Uint32 NumSRBs; + AttribIter attrib_it; + Uint32& shader_ind; + + HandleResourceHelper(const PipelineStateGLImpl& _PSO, ShaderResourceBindingGLImpl** _ppSRBs, Uint32 _NumSRBs, AttribIter iter, Uint32& ind) : + PSO{_PSO}, ppSRBs{_ppSRBs}, NumSRBs{_NumSRBs}, attrib_it{iter}, shader_ind{ind} + {} - return m_StaticResourceLayout.GetShaderVariable(ShaderType, Index); + void Validate(const ShaderResourcesGL::GLResourceAttribs& Attribs, RESOURCE_DIMENSION ResDim, bool IsMS) + { + if (*attrib_it && !attrib_it->IsImmutableSampler()) + { + if (attrib_it->SignatureIndex >= NumSRBs || ppSRBs[attrib_it->SignatureIndex] == nullptr) + { + LOG_ERROR_MESSAGE("No resource is bound to variable '", Attribs.Name, "' in shader '", PSO.m_ShaderNames[shader_ind], + "' of PSO '", PSO.m_Desc.Name, "': SRB at index ", attrib_it->SignatureIndex, " is not bound in the context."); + return; + } + + const auto& SRBCache = ppSRBs[attrib_it->SignatureIndex]->GetResourceCache(); + attrib_it->pSignature->DvpValidateCommittedResource(Attribs, ResDim, IsMS, attrib_it->ResourceIndex, SRBCache, PSO.m_ShaderNames[shader_ind].c_str(), PSO.m_Desc.Name); + } + ++attrib_it; + } + + void operator()(const ShaderResourcesGL::GLResourceAttribs& Attribs) { Validate(Attribs, RESOURCE_DIM_UNDEFINED, false); } + void operator()(const ShaderResourcesGL::TextureInfo& Attribs) { Validate(Attribs, Attribs.ResourceDim, Attribs.IsMultisample); } + void operator()(const ShaderResourcesGL::ImageInfo& Attribs) { Validate(Attribs, Attribs.ResourceDim, Attribs.IsMultisample); } + }; + + Uint32 i = 0; + HandleResourceHelper HandleResource{*this, pSRBs, NumSRBs, m_ResourceAttibutions.begin(), i}; + + VERIFY_EXPR(m_ShaderResources.size() == m_ShaderNames.size()); + for (; i < m_ShaderResources.size(); ++i) + { + m_ShaderResources[i]->ProcessConstResources(std::ref(HandleResource), std::ref(HandleResource), std::ref(HandleResource), std::ref(HandleResource)); + } + VERIFY_EXPR(HandleResource.attrib_it == m_ResourceAttibutions.end()); } +#endif // DILIGENT_DEVELOPMENT } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp index fd30dbb2..789a4760 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceGLImpl.cpp @@ -48,6 +48,7 @@ #include "QueryGLImpl.hpp" #include "RenderPassGLImpl.hpp" #include "FramebufferGLImpl.hpp" +#include "PipelineResourceSignatureGLImpl.hpp" #include "EngineMemory.h" #include "StringTools.hpp" @@ -152,14 +153,15 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, sizeof(FramebufferGLImpl), 0, 0, - 0 + 0, + sizeof(PipelineResourceSignatureGLImpl) } }, // Device caps must be filled in before the constructor of Pipeline Cache is called! m_GLContext{InitAttribs, m_DeviceCaps, pSCDesc} // clang-format on { - static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 15, "Please add new objects to DeviceObjectSizes constructor"); + static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 16, "Please add new objects to DeviceObjectSizes constructor"); GLint NumExtensions = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtensions); @@ -440,6 +442,7 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, SET_FEATURE_STATE(ShaderInt8, strstr(Extensions, "shader_explicit_arithmetic_types_int8"), "8-bit integer shader operations are"); SET_FEATURE_STATE(ResourceBuffer8BitAccess, strstr(Extensions, "shader_8bit_storage"), "8-bit resoure buffer access is"); SET_FEATURE_STATE(UniformBuffer8BitAccess, strstr(Extensions, "shader_8bit_storage"), "8-bit uniform buffer access is"); + SET_FEATURE_STATE(ShaderResourceRuntimeArray, false, "runtime-sized array is"); // clang-format on TexCaps.MaxTexture1DDimension = 0; // Not supported in GLES 3.2 @@ -467,8 +470,29 @@ RenderDeviceGLImpl::RenderDeviceGLImpl(IReferenceCounters* pRefCounters, #undef SET_FEATURE_STATE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 33, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); +#endif + + // get device limits + { + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &m_DeviceLimits.MaxUniformBlocks); + CHECK_GL_ERROR("glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS) failed"); + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_DeviceLimits.MaxTextureUnits); + CHECK_GL_ERROR("glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) failed"); + + if (Features.ComputeShaders) + { +#if GL_ARB_shader_storage_buffer_object + glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &m_DeviceLimits.MaxStorageBlock); + CHECK_GL_ERROR("glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS) failed"); #endif +#if GL_ARB_shader_image_load_store + glGetIntegerv(GL_MAX_IMAGE_UNITS, &m_DeviceLimits.MaxImagesUnits); + CHECK_GL_ERROR("glGetIntegerv(GL_MAX_IMAGE_UNITS) failed"); +#endif + } + } } RenderDeviceGLImpl::~RenderDeviceGLImpl() @@ -788,17 +812,38 @@ void RenderDeviceGLImpl::CreateRenderPass(const RenderPassDesc& Desc, IRenderPas void RenderDeviceGLImpl::CreateFramebuffer(const FramebufferDesc& Desc, IFramebuffer** ppFramebuffer) { - CreateDeviceObject("Framebuffer", Desc, ppFramebuffer, - [&]() // - { - auto spDeviceContext = GetImmediateContext(); - VERIFY(spDeviceContext, "Immediate device context has been destroyed"); - auto& GLState = spDeviceContext.RawPtr<DeviceContextGLImpl>()->GetContextState(); - - FramebufferGLImpl* pFramebufferGL(NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferGLImpl instance", FramebufferGLImpl)(this, GLState, Desc)); - pFramebufferGL->QueryInterface(IID_Framebuffer, reinterpret_cast<IObject**>(ppFramebuffer)); - OnCreateDeviceObject(pFramebufferGL); - }); + CreateDeviceObject( + "Framebuffer", Desc, ppFramebuffer, + [&]() // + { + auto spDeviceContext = GetImmediateContext(); + VERIFY(spDeviceContext, "Immediate device context has been destroyed"); + auto& GLState = spDeviceContext.RawPtr<DeviceContextGLImpl>()->GetContextState(); + + FramebufferGLImpl* pFramebufferGL(NEW_RC_OBJ(m_FramebufferAllocator, "FramebufferGLImpl instance", FramebufferGLImpl)(this, GLState, Desc)); + pFramebufferGL->QueryInterface(IID_Framebuffer, reinterpret_cast<IObject**>(ppFramebuffer)); + OnCreateDeviceObject(pFramebufferGL); + }); +} + +void RenderDeviceGLImpl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature) +{ + CreatePipelineResourceSignature(Desc, ppSignature, false); +} + +void RenderDeviceGLImpl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature, + bool IsDeviceInternal) +{ + CreateDeviceObject( + "PipelineResourceSignature", Desc, ppSignature, + [&]() // + { + PipelineResourceSignatureGLImpl* pPRSGL(NEW_RC_OBJ(m_PipeResSignAllocator, "PipelineResourceSignatureGLImpl instance", PipelineResourceSignatureGLImpl)(this, Desc, IsDeviceInternal)); + pPRSGL->QueryInterface(IID_PipelineResourceSignature, reinterpret_cast<IObject**>(ppSignature)); + OnCreateDeviceObject(pPRSGL); + }); } void RenderDeviceGLImpl::CreateBLAS(const BottomLevelASDesc& Desc, diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp index 3418875e..bc480a06 100644 --- a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp @@ -41,6 +41,11 @@ using namespace Diligent; namespace Diligent { +ShaderGLImpl::ShaderStageInfo::ShaderStageInfo(const ShaderGLImpl* _pShader) : + Type{_pShader->GetDesc().ShaderType}, + pShader{_pShader} +{} + ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters, RenderDeviceGLImpl* pDeviceGL, const ShaderCreateInfo& ShaderCI, @@ -158,16 +163,15 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters, if (deviceCaps.Features.SeparablePrograms) { - ShaderGLImpl* ThisShader[] = {this}; - GLObjectWrappers::GLProgramObj Program = LinkProgram(ThisShader, 1, true); - Uint32 UniformBufferBinding = 0; - Uint32 SamplerBinding = 0; - Uint32 ImageBinding = 0; - Uint32 StorageBufferBinding = 0; - auto pImmediateCtx = m_pDevice->GetImmediateContext(); + ShaderStageInfo ThisShader[] = {ShaderStageInfo{this}}; + GLObjectWrappers::GLProgramObj Program = LinkProgram(ThisShader, 1, true); + auto pImmediateCtx = m_pDevice->GetImmediateContext(); VERIFY_EXPR(pImmediateCtx); auto& GLState = pImmediateCtx.RawPtr<DeviceContextGLImpl>()->GetContextState(); - m_Resources.LoadUniforms(m_Desc.ShaderType, Program, GLState, UniformBufferBinding, SamplerBinding, ImageBinding, StorageBufferBinding); + + std::unique_ptr<ShaderResourcesGL> pResources{new ShaderResourcesGL{}}; + pResources->LoadUniforms(m_Desc.ShaderType, Program, GLState); + m_pShaderResources.reset(pResources.release()); } } @@ -178,7 +182,7 @@ ShaderGLImpl::~ShaderGLImpl() IMPLEMENT_QUERY_INTERFACE(ShaderGLImpl, IID_ShaderGL, TShaderBase) -GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(ShaderGLImpl** ppShaders, Uint32 NumShaders, bool IsSeparableProgram) +GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(const ShaderStageInfo* pShaderStagess, Uint32 NumShaders, bool IsSeparableProgram) { VERIFY(!IsSeparableProgram || NumShaders == 1, "Number of shaders must be 1 when separable program is created"); @@ -190,7 +194,7 @@ GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(ShaderGLImpl** ppShader for (Uint32 i = 0; i < NumShaders; ++i) { - auto* pCurrShader = ppShaders[i]; + auto* pCurrShader = pShaderStagess[i].pShader; glAttachShader(GLProg, pCurrShader->m_GLShaderObj); CHECK_GL_ERROR("glAttachShader() failed"); } @@ -229,7 +233,7 @@ GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(ShaderGLImpl** ppShader for (Uint32 i = 0; i < NumShaders; ++i) { - auto* pCurrShader = ValidatedCast<ShaderGLImpl>(ppShaders[i]); + auto* pCurrShader = ValidatedCast<const ShaderGLImpl>(pShaderStagess[i].pShader); glDetachShader(GLProg, pCurrShader->m_GLShaderObj); CHECK_GL_ERROR("glDetachShader() failed"); } @@ -241,7 +245,7 @@ Uint32 ShaderGLImpl::GetResourceCount() const { if (m_pDevice->GetDeviceCaps().Features.SeparablePrograms) { - return m_Resources.GetVariableCount(); + return m_pShaderResources->GetVariableCount(); } else { @@ -255,7 +259,7 @@ void ShaderGLImpl::GetResourceDesc(Uint32 Index, ShaderResourceDesc& ResourceDes if (m_pDevice->GetDeviceCaps().Features.SeparablePrograms) { DEV_CHECK_ERR(Index < GetResourceCount(), "Index is out of range"); - ResourceDesc = m_Resources.GetResourceDesc(Index); + ResourceDesc = m_pShaderResources->GetResourceDesc(Index); } else { diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp index c5b6fab1..a2713fbf 100644 --- a/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp @@ -34,119 +34,99 @@ namespace Diligent { -ShaderResourceBindingGLImpl::ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters, - PipelineStateGLImpl* pPSO, - GLProgramResources* ProgramResources, - Uint32 NumPrograms) : +ShaderResourceBindingGLImpl::ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters, + PipelineResourceSignatureGLImpl* pPRS) : // clang-format off TBase { pRefCounters, - pPSO + pPRS }, - m_ResourceLayout{*this} + m_ShaderResourceCache{ShaderResourceCacheGL::CacheContentType::SRB} // clang-format on { - pPSO->InitializeSRBResourceCache(m_ResourceCache); - - // Copy only mutable and dynamic variables from master resource layout - const SHADER_RESOURCE_VARIABLE_TYPE SRBVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; - - const auto& ResourceLayout = pPSO->GetDesc().ResourceLayout; - m_ResourceLayout.Initialize(ProgramResources, NumPrograms, pPSO->GetDesc().PipelineType, ResourceLayout, SRBVarTypes, _countof(SRBVarTypes), &m_ResourceCache); + try + { + const auto NumShaders = GetNumShaders(); + + FixedLinearAllocator MemPool{GetRawAllocator()}; + MemPool.AddSpace<ShaderVariableGL>(NumShaders); + MemPool.Reserve(); + m_pShaderVarMgrs = MemPool.ConstructArray<ShaderVariableGL>(NumShaders, std::ref(*this), std::ref(m_ShaderResourceCache)); + + // The memory is now owned by ShaderResourceBindingVkImpl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pShaderVarMgrs); + (void)Ptr; + + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + pPRS->InitSRBResourceCache(m_ShaderResourceCache); + + for (Uint32 s = 0; s < NumShaders; ++s) + { + const auto ShaderType = pPRS->GetActiveShaderStageType(s); + const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPRS->GetPipelineType()); + const auto MgrInd = m_ActiveShaderStageIndex[ShaderInd]; + VERIFY_EXPR(MgrInd >= 0 && MgrInd < static_cast<int>(NumShaders)); + + // Create shader variable manager in place + // Initialize vars manager to reference mutable and dynamic variables + // Note that the cache has space for all variable types + const SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + m_pShaderVarMgrs[MgrInd].Initialize(*pPRS, VarTypes, _countof(VarTypes), ShaderType); + } + } + catch (...) + { + Destruct(); + throw; + } } ShaderResourceBindingGLImpl::~ShaderResourceBindingGLImpl() { - m_ResourceCache.Destroy(GetRawAllocator()); + Destruct(); } -IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingGLImpl, IID_ShaderResourceBindingGL, TBase) - -void ShaderResourceBindingGLImpl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags) +void ShaderResourceBindingGLImpl::Destruct() { - m_ResourceLayout.BindResources(static_cast<SHADER_TYPE>(ShaderFlags), pResMapping, Flags, m_ResourceCache); -} + auto& RawAllocator = GetRawAllocator(); -IShaderResourceVariable* ShaderResourceBindingGLImpl::GetVariableByName(SHADER_TYPE ShaderType, const char* Name) -{ - if (!IsConsistentShaderType(ShaderType, m_pPSO->GetDesc().PipelineType)) + if (m_pShaderVarMgrs != nullptr) { - LOG_WARNING_MESSAGE("Unable to find mutable/dynamic variable '", Name, "' in shader stage ", GetShaderTypeLiteralName(ShaderType), - " as the stage is invalid for ", GetPipelineTypeString(m_pPSO->GetDesc().PipelineType), " pipeline '", m_pPSO->GetDesc().Name, "'"); - return nullptr; + const auto NumShaders = GetNumShaders(); + for (Uint32 s = 0; s < NumShaders; ++s) + m_pShaderVarMgrs[s].~ShaderVariableGL(); + + RawAllocator.Free(m_pShaderVarMgrs); + m_pShaderVarMgrs = nullptr; } - return m_ResourceLayout.GetShaderVariable(ShaderType, Name); + m_ShaderResourceCache.Destroy(RawAllocator); } -Uint32 ShaderResourceBindingGLImpl::GetVariableCount(SHADER_TYPE ShaderType) const -{ - if (!IsConsistentShaderType(ShaderType, m_pPSO->GetDesc().PipelineType)) - { - LOG_WARNING_MESSAGE("Unable to get the number of mutable/dynamic variables in shader stage ", GetShaderTypeLiteralName(ShaderType), - " as the stage is invalid for ", GetPipelineTypeString(m_pPSO->GetDesc().PipelineType), " pipeline '", m_pPSO->GetDesc().Name, "'"); - return 0; - } +IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingGLImpl, IID_ShaderResourceBindingGL, TBase) - return m_ResourceLayout.GetNumVariables(ShaderType); +void ShaderResourceBindingGLImpl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags) +{ + BindResourcesImpl(ShaderFlags, pResMapping, Flags, m_pShaderVarMgrs); } -IShaderResourceVariable* ShaderResourceBindingGLImpl::GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) +IShaderResourceVariable* ShaderResourceBindingGLImpl::GetVariableByName(SHADER_TYPE ShaderType, const char* Name) { - if (!IsConsistentShaderType(ShaderType, m_pPSO->GetDesc().PipelineType)) - { - LOG_WARNING_MESSAGE("Unable to get mutable/dynamic variable at index ", Index, " in shader stage ", GetShaderTypeLiteralName(ShaderType), - " as the stage is invalid for ", GetPipelineTypeString(m_pPSO->GetDesc().PipelineType), " pipeline '", m_pPSO->GetDesc().Name, "'"); - return nullptr; - } - - return m_ResourceLayout.GetShaderVariable(ShaderType, Index); + return GetVariableByNameImpl(ShaderType, Name, m_pShaderVarMgrs); } -const GLProgramResourceCache& ShaderResourceBindingGLImpl::GetResourceCache(PipelineStateGLImpl* pdbgPSO) +Uint32 ShaderResourceBindingGLImpl::GetVariableCount(SHADER_TYPE ShaderType) const { -#ifdef DILIGENT_DEBUG - if (pdbgPSO->IsIncompatibleWith(GetPipelineState())) - { - LOG_ERROR("Shader resource binding is incompatible with the currently bound pipeline state."); - } -#endif - return m_ResourceCache; + return GetVariableCountImpl(ShaderType, m_pShaderVarMgrs); } -void ShaderResourceBindingGLImpl::InitializeStaticResources(const IPipelineState* pPipelineState) +IShaderResourceVariable* ShaderResourceBindingGLImpl::GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) { - if (m_bIsStaticResourcesBound) - { - LOG_WARNING_MESSAGE("Static resources have already been initialized in this shader resource binding object. The operation will be ignored."); - return; - } - - if (pPipelineState == nullptr) - { - pPipelineState = GetPipelineState(); - } - else - { - DEV_CHECK_ERR(pPipelineState->IsCompatibleWith(GetPipelineState()), "The pipeline state is not compatible with this SRB"); - } - - const auto* pPSOGL = ValidatedCast<const PipelineStateGLImpl>(pPipelineState); - const auto& StaticResLayout = pPSOGL->GetStaticResourceLayout(); - -#ifdef DILIGENT_DEVELOPMENT - if (!StaticResLayout.dvpVerifyBindings(pPSOGL->GetStaticResourceCache())) - { - LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", pPSOGL->GetDesc().Name, - "' will not be successfully initialized because not all static resource bindings in shader '", pPSOGL->GetDesc().Name, - "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " - "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); - } -#endif - - StaticResLayout.CopyResources(m_ResourceCache); - m_bIsStaticResourcesBound = true; + return GetVariableByIndexImpl(ShaderType, Index, m_pShaderVarMgrs); } } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceCacheGL.cpp index 125958d4..05a6f038 100644 --- a/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceCacheGL.cpp @@ -26,33 +26,33 @@ */ #include "pch.h" -#include "GLProgramResourceCache.hpp" +#include "ShaderResourceCacheGL.hpp" namespace Diligent { -size_t GLProgramResourceCache::GetRequriedMemorySize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount) +size_t ShaderResourceCacheGL::GetRequriedMemorySize(Uint32 UBCount, Uint32 TextureCount, Uint32 ImageCount, Uint32 SSBOCount) { // clang-format off auto MemSize = sizeof(CachedUB) * UBCount + - sizeof(CachedResourceView) * SamplerCount + + sizeof(CachedResourceView) * TextureCount + sizeof(CachedResourceView) * ImageCount + sizeof(CachedSSBO) * SSBOCount; // clang-format on return MemSize; } -void GLProgramResourceCache::Initialize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount, IMemoryAllocator& MemAllocator) +void ShaderResourceCacheGL::Initialize(Uint32 UBCount, Uint32 TextureCount, Uint32 ImageCount, Uint32 SSBOCount, IMemoryAllocator& MemAllocator) { // clang-format off - m_SmplrsOffset = static_cast<Uint16>(m_UBsOffset + sizeof(CachedUB) * UBCount); - m_ImgsOffset = static_cast<Uint16>(m_SmplrsOffset + sizeof(CachedResourceView) * SamplerCount); - m_SSBOsOffset = static_cast<Uint16>(m_ImgsOffset + sizeof(CachedResourceView) * ImageCount); - m_MemoryEndOffset = static_cast<Uint16>(m_SSBOsOffset + sizeof(CachedSSBO) * SSBOCount); + m_TexturesOffset = static_cast<Uint16>(m_UBsOffset + sizeof(CachedUB) * UBCount); + m_ImagesOffset = static_cast<Uint16>(m_TexturesOffset + sizeof(CachedResourceView) * TextureCount); + m_SSBOsOffset = static_cast<Uint16>(m_ImagesOffset + sizeof(CachedResourceView) * ImageCount); + m_MemoryEndOffset = static_cast<Uint16>(m_SSBOsOffset + sizeof(CachedSSBO) * SSBOCount); VERIFY_EXPR(GetUBCount() == static_cast<Uint32>(UBCount)); - VERIFY_EXPR(GetSamplerCount() == static_cast<Uint32>(SamplerCount)); + VERIFY_EXPR(GetTextureCount() == static_cast<Uint32>(TextureCount)); VERIFY_EXPR(GetImageCount() == static_cast<Uint32>(ImageCount)); VERIFY_EXPR(GetSSBOCount() == static_cast<Uint32>(SSBOCount)); // clang-format on @@ -60,7 +60,7 @@ void GLProgramResourceCache::Initialize(Uint32 UBCount, Uint32 SamplerCount, Uin VERIFY_EXPR(m_pResourceData == nullptr); size_t BufferSize = m_MemoryEndOffset; - VERIFY_EXPR(BufferSize == GetRequriedMemorySize(UBCount, SamplerCount, ImageCount, SSBOCount)); + VERIFY_EXPR(BufferSize == GetRequriedMemorySize(UBCount, TextureCount, ImageCount, SSBOCount)); #ifdef DILIGENT_DEBUG m_pdbgMemoryAllocator = &MemAllocator; @@ -75,8 +75,8 @@ void GLProgramResourceCache::Initialize(Uint32 UBCount, Uint32 SamplerCount, Uin for (Uint32 cb = 0; cb < UBCount; ++cb) new (&GetUB(cb)) CachedUB; - for (Uint32 s = 0; s < SamplerCount; ++s) - new (&GetSampler(s)) CachedResourceView; + for (Uint32 s = 0; s < TextureCount; ++s) + new (&GetTexture(s)) CachedResourceView; for (Uint32 i = 0; i < ImageCount; ++i) new (&GetImage(i)) CachedResourceView; @@ -85,12 +85,12 @@ void GLProgramResourceCache::Initialize(Uint32 UBCount, Uint32 SamplerCount, Uin new (&GetSSBO(s)) CachedSSBO; } -GLProgramResourceCache::~GLProgramResourceCache() +ShaderResourceCacheGL::~ShaderResourceCacheGL() { - VERIFY(!IsInitialized(), "Shader resource cache memory must be released with GLProgramResourceCache::Destroy()"); + VERIFY(!IsInitialized(), "Shader resource cache memory must be released with ShaderResourceCacheGL::Destroy()"); } -void GLProgramResourceCache::Destroy(IMemoryAllocator& MemAllocator) +void ShaderResourceCacheGL::Destroy(IMemoryAllocator& MemAllocator) { if (!IsInitialized()) return; @@ -100,8 +100,8 @@ void GLProgramResourceCache::Destroy(IMemoryAllocator& MemAllocator) for (Uint32 cb = 0; cb < GetUBCount(); ++cb) GetUB(cb).~CachedUB(); - for (Uint32 s = 0; s < GetSamplerCount(); ++s) - GetSampler(s).~CachedResourceView(); + for (Uint32 s = 0; s < GetTextureCount(); ++s) + GetTexture(s).~CachedResourceView(); for (Uint32 i = 0; i < GetImageCount(); ++i) GetImage(i).~CachedResourceView(); @@ -113,8 +113,8 @@ void GLProgramResourceCache::Destroy(IMemoryAllocator& MemAllocator) MemAllocator.Free(m_pResourceData); m_pResourceData = nullptr; - m_SmplrsOffset = InvalidResourceOffset; - m_ImgsOffset = InvalidResourceOffset; + m_TexturesOffset = InvalidResourceOffset; + m_ImagesOffset = InvalidResourceOffset; m_SSBOsOffset = InvalidResourceOffset; m_MemoryEndOffset = InvalidResourceOffset; } diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderResourcesGL.cpp index 53ce4963..a0eb2e25 100644 --- a/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderResourcesGL.cpp @@ -28,7 +28,7 @@ #include "pch.h" #include <unordered_set> #include "GLContextState.hpp" -#include "GLProgramResources.hpp" +#include "ShaderResourcesGL.hpp" #include "RenderDeviceGLImpl.hpp" #include "ShaderResourceBindingBase.hpp" #include "ShaderResourceVariableBase.hpp" @@ -36,27 +36,173 @@ namespace Diligent { +namespace +{ +void GLTextureTypeToResourceDim(GLenum TextureType, RESOURCE_DIMENSION& ResDim, bool& IsMS) +{ + IsMS = false; + ResDim = RESOURCE_DIM_UNDEFINED; + switch (TextureType) + { + case GL_SAMPLER_1D: + case GL_SAMPLER_1D_SHADOW: + case GL_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_1D: + ResDim = RESOURCE_DIM_TEX_1D; + return; + + case GL_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_EXTERNAL_OES: + ResDim = RESOURCE_DIM_TEX_2D; + return; + + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + ResDim = RESOURCE_DIM_TEX_3D; + return; + + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + ResDim = RESOURCE_DIM_TEX_CUBE; + return; + + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_1D_ARRAY_SHADOW: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + ResDim = RESOURCE_DIM_TEX_1D_ARRAY; + return; + + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + ResDim = RESOURCE_DIM_TEX_2D_ARRAY; + return; + + case GL_SAMPLER_CUBE_MAP_ARRAY: + case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: + case GL_INT_SAMPLER_CUBE_MAP_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: + ResDim = RESOURCE_DIM_TEX_CUBE_ARRAY; + return; + + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + ResDim = RESOURCE_DIM_TEX_2D; + IsMS = true; + return; + + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + ResDim = RESOURCE_DIM_TEX_2D_ARRAY; + IsMS = true; + return; + + case GL_SAMPLER_BUFFER: + case GL_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: + ResDim = RESOURCE_DIM_BUFFER; + return; + +#if GL_ARB_shader_image_load_store + case GL_IMAGE_1D: + case GL_INT_IMAGE_1D: + case GL_UNSIGNED_INT_IMAGE_1D: + ResDim = RESOURCE_DIM_TEX_1D; + return; + + case GL_IMAGE_2D: + case GL_IMAGE_2D_RECT: + case GL_INT_IMAGE_2D: + case GL_INT_IMAGE_2D_RECT: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D_RECT: + ResDim = RESOURCE_DIM_TEX_2D; + return; + + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + ResDim = RESOURCE_DIM_TEX_3D; + return; + + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + ResDim = RESOURCE_DIM_TEX_CUBE; + return; + + case GL_IMAGE_BUFFER: + case GL_INT_IMAGE_BUFFER: + case GL_UNSIGNED_INT_IMAGE_BUFFER: + ResDim = RESOURCE_DIM_BUFFER; + return; + + case GL_IMAGE_1D_ARRAY: + case GL_INT_IMAGE_1D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: + ResDim = RESOURCE_DIM_TEX_1D_ARRAY; + return; + + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + ResDim = RESOURCE_DIM_TEX_2D_ARRAY; + return; + + case GL_IMAGE_CUBE_MAP_ARRAY: + case GL_INT_IMAGE_CUBE_MAP_ARRAY: + case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: + ResDim = RESOURCE_DIM_TEX_CUBE_ARRAY; + return; + + case GL_IMAGE_2D_MULTISAMPLE: + case GL_INT_IMAGE_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: + ResDim = RESOURCE_DIM_TEX_2D; + IsMS = true; + return; + + case GL_IMAGE_2D_MULTISAMPLE_ARRAY: + case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: + ResDim = RESOURCE_DIM_TEX_2D_ARRAY; + IsMS = true; + return; +#endif + } +} +} // namespace -GLProgramResources::GLProgramResources(GLProgramResources&& Program) noexcept : +ShaderResourcesGL::ShaderResourcesGL(ShaderResourcesGL&& Program) noexcept : // clang-format off m_ShaderStages {Program.m_ShaderStages }, m_UniformBuffers {Program.m_UniformBuffers }, - m_Samplers {Program.m_Samplers }, + m_Textures {Program.m_Textures }, m_Images {Program.m_Images }, m_StorageBlocks {Program.m_StorageBlocks }, m_NumUniformBuffers{Program.m_NumUniformBuffers }, - m_NumSamplers {Program.m_NumSamplers }, + m_NumTextures {Program.m_NumTextures }, m_NumImages {Program.m_NumImages }, m_NumStorageBlocks {Program.m_NumStorageBlocks } // clang-format on { Program.m_UniformBuffers = nullptr; - Program.m_Samplers = nullptr; + Program.m_Textures = nullptr; Program.m_Images = nullptr; Program.m_StorageBlocks = nullptr; Program.m_NumUniformBuffers = 0; - Program.m_NumSamplers = 0; + Program.m_NumTextures = 0; Program.m_NumImages = 0; Program.m_NumStorageBlocks = 0; } @@ -68,15 +214,15 @@ inline void RemoveArrayBrackets(char* Str) *OpenBacketPtr = 0; } -void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& UniformBlocks, - std::vector<SamplerInfo>& Samplers, - std::vector<ImageInfo>& Images, - std::vector<StorageBlockInfo>& StorageBlocks) +void ShaderResourcesGL::AllocateResources(std::vector<UniformBufferInfo>& UniformBlocks, + std::vector<TextureInfo>& Textures, + std::vector<ImageInfo>& Images, + std::vector<StorageBlockInfo>& StorageBlocks) { VERIFY(m_UniformBuffers == nullptr, "Resources have already been allocated!"); m_NumUniformBuffers = static_cast<Uint32>(UniformBlocks.size()); - m_NumSamplers = static_cast<Uint32>(Samplers.size()); + m_NumTextures = static_cast<Uint32>(Textures.size()); m_NumImages = static_cast<Uint32>(Images.size()); m_NumStorageBlocks = static_cast<Uint32>(StorageBlocks.size()); @@ -86,7 +232,7 @@ void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& Unifo StringPoolDataSize += strlen(ub.Name) + 1; } - for (const auto& sam : Samplers) + for (const auto& sam : Textures) { StringPoolDataSize += strlen(sam.Name) + 1; } @@ -106,7 +252,7 @@ void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& Unifo // clang-format off size_t TotalMemorySize = m_NumUniformBuffers * sizeof(UniformBufferInfo) + - m_NumSamplers * sizeof(SamplerInfo) + + m_NumTextures * sizeof(TextureInfo) + m_NumImages * sizeof(ImageInfo) + m_NumStorageBlocks * sizeof(StorageBlockInfo); // clang-format on @@ -114,12 +260,12 @@ void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& Unifo if (TotalMemorySize == 0) { m_UniformBuffers = nullptr; - m_Samplers = nullptr; + m_Textures = nullptr; m_Images = nullptr; m_StorageBlocks = nullptr; m_NumUniformBuffers = 0; - m_NumSamplers = 0; + m_NumTextures = 0; m_NumImages = 0; m_NumStorageBlocks = 0; @@ -129,12 +275,12 @@ void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& Unifo TotalMemorySize += AlignedStringPoolDataSize * sizeof(Char); auto& MemAllocator = GetRawAllocator(); - void* RawMemory = ALLOCATE_RAW(MemAllocator, "Memory buffer for GLProgramResources", TotalMemorySize); + void* RawMemory = ALLOCATE_RAW(MemAllocator, "Memory buffer for ShaderResourcesGL", TotalMemorySize); // clang-format off m_UniformBuffers = reinterpret_cast<UniformBufferInfo*>(RawMemory); - m_Samplers = reinterpret_cast<SamplerInfo*> (m_UniformBuffers + m_NumUniformBuffers); - m_Images = reinterpret_cast<ImageInfo*> (m_Samplers + m_NumSamplers); + m_Textures = reinterpret_cast<TextureInfo*> (m_UniformBuffers + m_NumUniformBuffers); + m_Images = reinterpret_cast<ImageInfo*> (m_Textures + m_NumTextures); m_StorageBlocks = reinterpret_cast<StorageBlockInfo*>(m_Images + m_NumImages); void* EndOfResourceData = m_StorageBlocks + m_NumStorageBlocks; Char* StringPoolData = reinterpret_cast<Char*>(EndOfResourceData); @@ -150,10 +296,10 @@ void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& Unifo new (m_UniformBuffers + ub) UniformBufferInfo{SrcUB, TmpStringPool}; } - for (Uint32 s = 0; s < m_NumSamplers; ++s) + for (Uint32 s = 0; s < m_NumTextures; ++s) { - auto& SrcSam = Samplers[s]; - new (m_Samplers + s) SamplerInfo{SrcSam, TmpStringPool}; + auto& SrcSam = Textures[s]; + new (m_Textures + s) TextureInfo{SrcSam, TmpStringPool}; } for (Uint32 img = 0; img < m_NumImages; ++img) @@ -171,7 +317,7 @@ void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& Unifo VERIFY_EXPR(TmpStringPool.GetRemainingSize() == 0); } -GLProgramResources::~GLProgramResources() +ShaderResourcesGL::~ShaderResourcesGL() { // clang-format off ProcessResources( @@ -179,9 +325,9 @@ GLProgramResources::~GLProgramResources() { UB.~UniformBufferInfo(); }, - [&](SamplerInfo& Sam) + [&](TextureInfo& Sam) { - Sam.~SamplerInfo(); + Sam.~TextureInfo(); }, [&](ImageInfo& Img) { @@ -203,17 +349,13 @@ GLProgramResources::~GLProgramResources() } -void GLProgramResources::LoadUniforms(SHADER_TYPE ShaderStages, - const GLObjectWrappers::GLProgramObj& GLProgram, - GLContextState& State, - Uint32& UniformBufferBinding, - Uint32& SamplerBinding, - Uint32& ImageBinding, - Uint32& StorageBufferBinding) +void ShaderResourcesGL::LoadUniforms(SHADER_TYPE ShaderStages, + const GLObjectWrappers::GLProgramObj& GLProgram, + GLContextState& State) { // Load uniforms to temporary arrays. We will then pack all variables into a single chunk of memory. std::vector<UniformBufferInfo> UniformBlocks; - std::vector<SamplerInfo> Samplers; + std::vector<TextureInfo> Textures; std::vector<ImageInfo> Images; std::vector<StorageBlockInfo> StorageBlocks; std::unordered_set<String> NamesPool; @@ -295,6 +437,10 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad // // The latter is only available in GL 4.4 and GLES 3.1 + RESOURCE_DIMENSION ResDim; + bool IsMS; + GLTextureTypeToResourceDim(dataType, ResDim, IsMS); + switch (dataType) { case GL_SAMPLER_1D: @@ -341,11 +487,6 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad case GL_INT_SAMPLER_BUFFER: case GL_UNSIGNED_INT_SAMPLER_BUFFER: { - auto UniformLocation = glGetUniformLocation(GLProgram, Name.data()); - // Note that glGetUniformLocation(program, name) is equivalent to - // glGetProgramResourceLocation(program, GL_UNIFORM, name); - // The latter is only available in GL 4.4 and GLES 3.1 - // clang-format off const auto ResourceType = dataType == GL_SAMPLER_BUFFER || @@ -357,23 +498,15 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad RemoveArrayBrackets(Name.data()); - Samplers.emplace_back( + Textures.emplace_back( NamesPool.emplace(Name.data()).first->c_str(), ShaderStages, ResourceType, - SamplerBinding, static_cast<Uint32>(size), - UniformLocation, - dataType // + dataType, + ResDim, + IsMS // ); - - for (GLint arr_ind = 0; arr_ind < size; ++arr_ind) - { - // glProgramUniform1i is not available in GLES3.0 - glUniform1i(UniformLocation + arr_ind, SamplerBinding++); - CHECK_GL_ERROR("Failed to set binding point for sampler uniform '", Name.data(), '\''); - } - break; } @@ -412,8 +545,6 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: { - auto UniformLocation = glGetUniformLocation(GLProgram, Name.data()); - // clang-format off const auto ResourceType = dataType == GL_IMAGE_BUFFER || @@ -429,42 +560,11 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad NamesPool.emplace(Name.data()).first->c_str(), ShaderStages, ResourceType, - ImageBinding, static_cast<Uint32>(size), - UniformLocation, - dataType // + dataType, + ResDim, + IsMS // ); - - for (GLint arr_ind = 0; arr_ind < size; ++arr_ind) - { - // glUniform1i for image uniforms is not supported in at least GLES3.2. - // glProgramUniform1i is not available in GLES3.0 - glUniform1i(UniformLocation + arr_ind, ImageBinding); - if (glGetError() != GL_NO_ERROR) - { - if (size > 1) - { - LOG_WARNING_MESSAGE("Failed to set binding for image uniform '", Name.data(), "'[", arr_ind, - "]. Expected binding: ", ImageBinding, - ". Make sure that this binding is explicitly assigned in shader source code." - " Note that if the source code is converted from HLSL and if images are only used" - " by a single shader stage, then bindings automatically assigned by HLSL->GLSL" - " converter will work fine."); - } - else - { - LOG_WARNING_MESSAGE("Failed to set binding for image uniform '", Name.data(), "'." - " Expected binding: ", - ImageBinding, - ". Make sure that this binding is explicitly assigned in shader source code." - " Note that if the source code is converted from HLSL and if images are only used" - " by a single shader stage, then bindings automatically assigned by HLSL->GLSL" - " converter will work fine."); - } - } - ++ImageBinding; - } - break; } #endif @@ -528,14 +628,10 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad NamesPool.emplace(Name.data()).first->c_str(), ShaderStages, SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, - UniformBufferBinding, static_cast<Uint32>(ArraySize), UniformBlockIndex // ); } - - glUniformBlockBinding(GLProgram, UniformBlockIndex, UniformBufferBinding++); - CHECK_GL_ERROR("glUniformBlockBinding() failed"); } #if GL_ARB_shader_storage_buffer_object @@ -584,47 +680,29 @@ void GLProgramResources::LoadUniforms(SHADER_TYPE Shad NamesPool.emplace(Name.data()).first->c_str(), ShaderStages, SHADER_RESOURCE_TYPE_BUFFER_UAV, - StorageBufferBinding, static_cast<Uint32>(ArraySize), SBIndex // ); } - - if (glShaderStorageBlockBinding) - { - glShaderStorageBlockBinding(GLProgram, SBIndex, StorageBufferBinding); - CHECK_GL_ERROR("glShaderStorageBlockBinding() failed"); - } - else - { - LOG_WARNING_MESSAGE("glShaderStorageBlockBinding is not available on this device and " - "the engine is unable to automatically assign shader storage block bindindg for '", - Name.data(), "' variable. Expected binding: ", StorageBufferBinding, - ". Make sure that this binding is explicitly assigned in shader source code." - " Note that if the source code is converted from HLSL and if storage blocks are only used" - " by a single shader stage, then bindings automatically assigned by HLSL->GLSL" - " converter will work fine."); - } - ++StorageBufferBinding; } #endif State.SetProgram(GLObjectWrappers::GLProgramObj::Null()); - AllocateResources(UniformBlocks, Samplers, Images, StorageBlocks); + AllocateResources(UniformBlocks, Textures, Images, StorageBlocks); } -ShaderResourceDesc GLProgramResources::GetResourceDesc(Uint32 Index) const +ShaderResourceDesc ShaderResourcesGL::GetResourceDesc(Uint32 Index) const { if (Index < m_NumUniformBuffers) return GetUniformBuffer(Index).GetResourceDesc(); else Index -= m_NumUniformBuffers; - if (Index < m_NumSamplers) - return GetSampler(Index).GetResourceDesc(); + if (Index < m_NumTextures) + return GetTexture(Index).GetResourceDesc(); else - Index -= m_NumSamplers; + Index -= m_NumTextures; if (Index < m_NumImages) return GetImage(Index).GetResourceDesc(); @@ -640,108 +718,4 @@ ShaderResourceDesc GLProgramResources::GetResourceDesc(Uint32 Index) const return ShaderResourceDesc{}; } -void GLProgramResources::CountResources(const PipelineResourceLayoutDesc& ResourceLayout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - ResourceCounters& Counters) const -{ - // clang-format off - ProcessConstResources( - [&](const GLProgramResources::UniformBufferInfo& UB) - { - ++Counters.NumUBs; - }, - [&](const GLProgramResources::SamplerInfo& Sam) - { - ++Counters.NumSamplers; - }, - [&](const GLProgramResources::ImageInfo& Img) - { - ++Counters.NumImages; - }, - [&](const GLProgramResources::StorageBlockInfo& SB) - { - ++Counters.NumStorageBlocks; - }, - &ResourceLayout, - AllowedVarTypes, - NumAllowedTypes - ); - // clang-format on -} - -bool GLProgramResources::IsCompatibleWith(const GLProgramResources& Res) const -{ - // clang-format off - if (GetNumUniformBuffers() != Res.GetNumUniformBuffers() || - GetNumSamplers() != Res.GetNumSamplers() || - GetNumImages() != Res.GetNumImages() || - GetNumStorageBlocks() != Res.GetNumStorageBlocks()) - return false; - // clang-format on - - for (Uint32 ub = 0; ub < GetNumUniformBuffers(); ++ub) - { - const auto& UB0 = GetUniformBuffer(ub); - const auto& UB1 = Res.GetUniformBuffer(ub); - if (!UB0.IsCompatibleWith(UB1)) - return false; - } - - for (Uint32 sam = 0; sam < GetNumSamplers(); ++sam) - { - const auto& Sam0 = GetSampler(sam); - const auto& Sam1 = Res.GetSampler(sam); - if (!Sam0.IsCompatibleWith(Sam1)) - return false; - } - - for (Uint32 img = 0; img < GetNumImages(); ++img) - { - const auto& Img0 = GetImage(img); - const auto& Img1 = Res.GetImage(img); - if (!Img0.IsCompatibleWith(Img1)) - return false; - } - - for (Uint32 sb = 0; sb < GetNumStorageBlocks(); ++sb) - { - const auto& SB0 = GetStorageBlock(sb); - const auto& SB1 = Res.GetStorageBlock(sb); - if (!SB0.IsCompatibleWith(SB1)) - return false; - } - - return true; -} - - -size_t GLProgramResources::GetHash() const -{ - size_t hash = ComputeHash(GetNumUniformBuffers(), GetNumSamplers(), GetNumImages(), GetNumStorageBlocks()); - - // clang-format off - ProcessConstResources( - [&](const UniformBufferInfo& UB) - { - HashCombine(hash, UB.GetHash()); - }, - [&](const SamplerInfo& Sam) - { - HashCombine(hash, Sam.GetHash()); - }, - [&](const ImageInfo& Img) - { - HashCombine(hash, Img.GetHash()); - }, - [&](const StorageBlockInfo& SB) - { - HashCombine(hash, SB.GetHash()); - } - ); - // clang-format on - - return hash; -} - } // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderVariableGL.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderVariableGL.cpp new file mode 100644 index 00000000..68485b78 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderVariableGL.cpp @@ -0,0 +1,733 @@ +/* + * Copyright 2019-2021 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include <array> +#include "ShaderVariableGL.hpp" +#include "PipelineResourceSignatureGLImpl.hpp" +#include "Align.hpp" +#include "PlatformMisc.hpp" +#include "ShaderBase.hpp" + +namespace Diligent +{ + +void ShaderVariableGL::CountResources(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + const SHADER_TYPE ShaderType, + ResourceCounters& Counters) +{ + ProcessSignatureResources( + Signature, AllowedVarTypes, NumAllowedTypes, ShaderType, + [&](Uint32 Index) { + const auto& ResDesc = Signature.GetResourceDesc(Index); + static_assert(BINDING_RANGE_COUNT == 4, "Please update the switch below to handle the new shader resource range"); + switch (PipelineResourceToBindingRange(ResDesc)) + { + // clang-format off + case BINDING_RANGE_UNIFORM_BUFFER: ++Counters.NumUBs; break; + case BINDING_RANGE_TEXTURE: ++Counters.NumTextures; break; + case BINDING_RANGE_IMAGE: ++Counters.NumImages; break; + case BINDING_RANGE_STORAGE_BUFFER: ++Counters.NumStorageBlocks; break; + // clang-format on + default: + UNEXPECTED("Unsupported resource type."); + } + }); +} + +template <typename HandlerType> +void ShaderVariableGL::ProcessSignatureResources(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType, + HandlerType Handler) +{ + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + + for (Uint32 var_type = 0; var_type < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++var_type) + { + const auto VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(var_type); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + const auto ResIdxRange = Signature.GetResourceIndexRange(VarType); + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& Res = Signature.GetResourceDesc(r); + VERIFY_EXPR(Res.VarType == VarType); + + if ((Res.ShaderStages & ShaderType) == 0) + continue; + + if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER) + continue; + + Handler(r); + } + } + } +} + +size_t ShaderVariableGL::GetRequiredMemorySize(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType) +{ + ResourceCounters Counters; + CountResources(Signature, AllowedVarTypes, NumAllowedTypes, ShaderType, Counters); + + // clang-format off + size_t RequiredSize = Counters.NumUBs * sizeof(UniformBuffBindInfo) + + Counters.NumTextures * sizeof(SamplerBindInfo) + + Counters.NumImages * sizeof(ImageBindInfo) + + Counters.NumStorageBlocks * sizeof(StorageBufferBindInfo); + // clang-format on + return RequiredSize; +} + +void ShaderVariableGL::Initialize(const PipelineResourceSignatureGLImpl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType) +{ + ResourceCounters Counters; + CountResources(Signature, AllowedVarTypes, NumAllowedTypes, ShaderType, Counters); + + m_pSignature = &Signature; + + // Initialize offsets + size_t CurrentOffset = 0; + + auto AdvanceOffset = [&CurrentOffset](size_t NumBytes) // + { + constexpr size_t MaxOffset = std::numeric_limits<OffsetType>::max(); + VERIFY(CurrentOffset <= MaxOffset, "Current offser (", CurrentOffset, ") exceeds max allowed value (", MaxOffset, ")"); + (void)MaxOffset; + auto Offset = static_cast<OffsetType>(CurrentOffset); + CurrentOffset += NumBytes; + return Offset; + }; + + // clang-format off + auto UBOffset = AdvanceOffset(Counters.NumUBs * sizeof(UniformBuffBindInfo) ); (void)UBOffset; // To suppress warning + m_TextureOffset = AdvanceOffset(Counters.NumTextures * sizeof(SamplerBindInfo) ); + m_ImageOffset = AdvanceOffset(Counters.NumImages * sizeof(ImageBindInfo) ); + m_StorageBufferOffset = AdvanceOffset(Counters.NumStorageBlocks * sizeof(StorageBufferBindInfo)); + m_VariableEndOffset = AdvanceOffset(0); + // clang-format off + auto TotalMemorySize = m_VariableEndOffset; + VERIFY_EXPR(TotalMemorySize == GetRequiredMemorySize(Signature, AllowedVarTypes, NumAllowedTypes, ShaderType)); + + auto& ResLayoutDataAllocator = GetRawAllocator(); + if (TotalMemorySize) + { + auto* pRawMem = ALLOCATE_RAW(ResLayoutDataAllocator, "Raw memory buffer for shader resource layout resources", TotalMemorySize); + m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void> >(pRawMem, ResLayoutDataAllocator); + } + + // clang-format off + VERIFY_EXPR(Counters.NumUBs == GetNumUBs() ); + VERIFY_EXPR(Counters.NumTextures == GetNumTextures() ); + VERIFY_EXPR(Counters.NumImages == GetNumImages() ); + VERIFY_EXPR(Counters.NumStorageBlocks == GetNumStorageBuffers()); + // clang-format on + + // Current resource index for every resource type + ResourceCounters VarCounters = {}; + + ProcessSignatureResources( + Signature, AllowedVarTypes, NumAllowedTypes, ShaderType, + [&](Uint32 Index) { + const auto& ResDesc = Signature.GetResourceDesc(Index); + static_assert(BINDING_RANGE_COUNT == 4, "Please update the switch below to handle the new shader resource range"); + switch (PipelineResourceToBindingRange(ResDesc)) + { + case BINDING_RANGE_UNIFORM_BUFFER: + new (&GetResource<UniformBuffBindInfo>(VarCounters.NumUBs++)) UniformBuffBindInfo{*this, Index}; + break; + case BINDING_RANGE_TEXTURE: + new (&GetResource<SamplerBindInfo>(VarCounters.NumTextures++)) SamplerBindInfo{*this, Index}; + break; + case BINDING_RANGE_IMAGE: + new (&GetResource<ImageBindInfo>(VarCounters.NumImages++)) ImageBindInfo{*this, Index}; + break; + case BINDING_RANGE_STORAGE_BUFFER: + new (&GetResource<StorageBufferBindInfo>(VarCounters.NumStorageBlocks++)) StorageBufferBindInfo{*this, Index}; + break; + default: + UNEXPECTED("Unsupported resource type."); + } + }); + + // clang-format off + VERIFY(VarCounters.NumUBs == GetNumUBs(), "Not all UBs are initialized which will cause a crash when dtor is called"); + VERIFY(VarCounters.NumTextures == GetNumTextures(), "Not all Samplers are initialized which will cause a crash when dtor is called"); + VERIFY(VarCounters.NumImages == GetNumImages(), "Not all Images are initialized which will cause a crash when dtor is called"); + VERIFY(VarCounters.NumStorageBlocks == GetNumStorageBuffers(), "Not all SSBOs are initialized which will cause a crash when dtor is called"); + // clang-format on +} + +ShaderVariableGL::~ShaderVariableGL() +{ + // clang-format off + HandleResources( + [&](UniformBuffBindInfo& ub) + { + ub.~UniformBuffBindInfo(); + }, + + [&](SamplerBindInfo& sam) + { + sam.~SamplerBindInfo(); + }, + + [&](ImageBindInfo& img) + { + img.~ImageBindInfo(); + }, + + [&](StorageBufferBindInfo& ssbo) + { + ssbo.~StorageBufferBindInfo(); + } + ); + // clang-format on +} + +void ShaderVariableGL::UniformBuffBindInfo::BindResource(IDeviceObject* pBuffer, + Uint32 ArrayIndex) +{ + const auto& Desc = GetDesc(); + const auto& Attr = GetAttribs(); + + DEV_CHECK_ERR(ArrayIndex < Desc.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", Desc.Name, "'. Max allowed index: ", Desc.ArraySize - 1); + auto& ResourceCache = m_ParentManager.m_ResourceCache; + + VERIFY_EXPR(Desc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER); + + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<BufferGLImpl> pBuffGLImpl(pBuffer, IID_BufferGL); +#ifdef DILIGENT_DEVELOPMENT + { + const auto& CachedUB = ResourceCache.GetConstUB(Attr.CacheOffset + ArrayIndex); + VerifyConstantBufferBinding(Desc.Name, Desc.ArraySize, Desc.VarType, Desc.Flags, ArrayIndex, pBuffer, pBuffGLImpl.RawPtr(), CachedUB.pBuffer.RawPtr()); + } +#endif + + ResourceCache.SetUniformBuffer(Attr.CacheOffset + ArrayIndex, std::move(pBuffGLImpl)); +} + + + +void ShaderVariableGL::SamplerBindInfo::BindResource(IDeviceObject* pView, + Uint32 ArrayIndex) +{ + const auto& Desc = GetDesc(); + const auto& Attr = GetAttribs(); + + DEV_CHECK_ERR(ArrayIndex < Desc.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", Desc.Name, "'. Max allowed index: ", Desc.ArraySize - 1); + auto& ResourceCache = m_ParentManager.m_ResourceCache; + + VERIFY_EXPR(Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV || + Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV); + + if (Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) + { + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<TextureViewGLImpl> pViewGL(pView, IID_TextureViewGL); +#ifdef DILIGENT_DEVELOPMENT + { + auto& CachedTexSampler = ResourceCache.GetConstTexture(Attr.CacheOffset + ArrayIndex); + VerifyResourceViewBinding(Desc.Name, Desc.ArraySize, Desc.VarType, ArrayIndex, + pView, pViewGL.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, + RESOURCE_DIM_UNDEFINED, false, CachedTexSampler.pView.RawPtr()); + if (Attr.IsImmutableSamplerAssigned() && ResourceCache.StaticResourcesInitialized()) + { + VERIFY(CachedTexSampler.pSampler != nullptr, "Immutable samplers must be initialized by PipelineStateGLImpl::InitializeSRBResourceCache!"); + } + } +#endif + ResourceCache.SetTexture(Attr.CacheOffset + ArrayIndex, std::move(pViewGL), !Attr.IsImmutableSamplerAssigned()); + } + else if (Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV) + { + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<BufferViewGLImpl> pViewGL(pView, IID_BufferViewGL); +#ifdef DILIGENT_DEVELOPMENT + { + auto& CachedBuffSampler = ResourceCache.GetConstTexture(Attr.CacheOffset + ArrayIndex); + VerifyResourceViewBinding(Desc.Name, Desc.ArraySize, Desc.VarType, ArrayIndex, + pView, pViewGL.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE}, + RESOURCE_DIM_BUFFER, false, CachedBuffSampler.pView.RawPtr()); + if (pViewGL != nullptr) + { + const auto& ViewDesc = pViewGL->GetDesc(); + const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); + if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + Desc.Name, ": formatted buffer view is expected."); + } + } + } +#endif + VERIFY_EXPR((Desc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) != 0); + ResourceCache.SetTexelBuffer(Attr.CacheOffset + ArrayIndex, std::move(pViewGL)); + } + else + { + UNEXPECTED("Unexpected resource type ", GetShaderResourceTypeLiteralName(Desc.ResourceType), ". Texture SRV or buffer SRV is expected."); + } +} + + +void ShaderVariableGL::ImageBindInfo::BindResource(IDeviceObject* pView, + Uint32 ArrayIndex) +{ + const auto& Desc = GetDesc(); + const auto& Attr = GetAttribs(); + + DEV_CHECK_ERR(ArrayIndex < Desc.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", Desc.Name, "'. Max allowed index: ", Desc.ArraySize - 1); + auto& ResourceCache = m_ParentManager.m_ResourceCache; + + if (Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV) + { + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<TextureViewGLImpl> pViewGL(pView, IID_TextureViewGL); +#ifdef DILIGENT_DEVELOPMENT + { + auto& CachedUAV = ResourceCache.GetConstImage(Attr.CacheOffset + ArrayIndex); + VerifyResourceViewBinding(Desc.Name, Desc.ArraySize, Desc.VarType, ArrayIndex, + pView, pViewGL.RawPtr(), {TEXTURE_VIEW_UNORDERED_ACCESS}, + RESOURCE_DIM_UNDEFINED, false, CachedUAV.pView.RawPtr()); + } +#endif + ResourceCache.SetTexImage(Attr.CacheOffset + ArrayIndex, std::move(pViewGL)); + } + else if (Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV) + { + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<BufferViewGLImpl> pViewGL(pView, IID_BufferViewGL); +#ifdef DILIGENT_DEVELOPMENT + { + auto& CachedUAV = ResourceCache.GetConstImage(Attr.CacheOffset + ArrayIndex); + VerifyResourceViewBinding(Desc.Name, Desc.ArraySize, Desc.VarType, ArrayIndex, + pView, pViewGL.RawPtr(), {BUFFER_VIEW_UNORDERED_ACCESS}, + RESOURCE_DIM_BUFFER, false, CachedUAV.pView.RawPtr()); + if (pViewGL != nullptr) + { + const auto& ViewDesc = pViewGL->GetDesc(); + const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); + if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + Desc.Name, ": formatted buffer view is expected."); + } + } + } +#endif + VERIFY_EXPR((Desc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) != 0); + ResourceCache.SetBufImage(Attr.CacheOffset + ArrayIndex, std::move(pViewGL)); + } + else + { + UNEXPECTED("Unexpected resource type ", GetShaderResourceTypeLiteralName(Desc.ResourceType), ". Texture UAV or buffer UAV is expected."); + } +} + + + +void ShaderVariableGL::StorageBufferBindInfo::BindResource(IDeviceObject* pView, + Uint32 ArrayIndex) +{ + const auto& Desc = GetDesc(); + const auto& Attr = GetAttribs(); + + DEV_CHECK_ERR(ArrayIndex < Desc.ArraySize, "Array index (", ArrayIndex, ") is out of range for variable '", Desc.Name, "'. Max allowed index: ", Desc.ArraySize - 1); + auto& ResourceCache = m_ParentManager.m_ResourceCache; + VERIFY_EXPR(Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV || + Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV); + VERIFY_EXPR((Desc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) == 0); + + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<BufferViewGLImpl> pViewGL(pView, IID_BufferViewGL); +#ifdef DILIGENT_DEVELOPMENT + { + auto& CachedSSBO = ResourceCache.GetConstSSBO(Attr.CacheOffset + ArrayIndex); + // HLSL structured buffers are mapped to SSBOs in GLSL + VerifyResourceViewBinding(Desc.Name, Desc.ArraySize, Desc.VarType, ArrayIndex, + pView, pViewGL.RawPtr(), {BUFFER_VIEW_SHADER_RESOURCE, BUFFER_VIEW_UNORDERED_ACCESS}, + RESOURCE_DIM_BUFFER, false, CachedSSBO.pBufferView.RawPtr()); + if (pViewGL != nullptr) + { + const auto& ViewDesc = pViewGL->GetDesc(); + const auto& BuffDesc = pViewGL->GetBuffer()->GetDesc(); + if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) + { + LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", + Desc.Name, ": structured buffer view is expected."); + } + } + } +#endif + ResourceCache.SetSSBO(Attr.CacheOffset + ArrayIndex, std::move(pViewGL)); +} + + + +// Helper template class that facilitates binding CBs, SRVs, and UAVs +class BindResourceHelper +{ +public: + BindResourceHelper(IResourceMapping& RM, Uint32 Fl) : + // clang-format off + ResourceMapping {RM}, + Flags {Fl} + // clang-format on + { + } + + template <typename ResourceType> + void Bind(ResourceType& Res) + { + if ((Flags & (1 << Res.GetType())) == 0) + return; + + const auto& ResDesc = Res.GetDesc(); + + for (Uint16 elem = 0; elem < ResDesc.ArraySize; ++elem) + { + if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(elem)) + continue; + + const auto* VarName = ResDesc.Name; + RefCntAutoPtr<IDeviceObject> pRes; + ResourceMapping.GetResource(VarName, &pRes, elem); + if (pRes) + { + // Call non-virtual function + Res.BindResource(pRes, elem); + } + else + { + if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(elem)) + LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", VarName, "': resource is not found in the resource mapping"); + } + } + } + +private: + IResourceMapping& ResourceMapping; + const Uint32 Flags; +}; + + +void ShaderVariableGL::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) +{ + if (pResourceMapping == nullptr) + { + LOG_ERROR_MESSAGE("Failed to bind resources: resource mapping is null"); + return; + } + + if ((Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0) + Flags |= BIND_SHADER_RESOURCES_UPDATE_ALL; + + BindResourceHelper BindResHelper(*pResourceMapping, Flags); + + // clang-format off + HandleResources( + [&](UniformBuffBindInfo& ub) + { + BindResHelper.Bind(ub); + }, + + [&](SamplerBindInfo& sam) + { + BindResHelper.Bind(sam); + }, + + [&](ImageBindInfo& img) + { + BindResHelper.Bind(img); + }, + + [&](StorageBufferBindInfo& ssbo) + { + BindResHelper.Bind(ssbo); + } + ); + // clang-format on +} + + +template <typename ResourceType> +IShaderResourceVariable* ShaderVariableGL::GetResourceByName(const Char* Name) const +{ + auto NumResources = GetNumResources<ResourceType>(); + for (Uint32 res = 0; res < NumResources; ++res) + { + auto& Resource = GetResource<ResourceType>(res); + const auto& ResDesc = Resource.GetDesc(); + if (strcmp(ResDesc.Name, Name) == 0) + return &Resource; + } + + return nullptr; +} + + +IShaderResourceVariable* ShaderVariableGL::GetVariable(const Char* Name) const +{ + if (auto* pUB = GetResourceByName<UniformBuffBindInfo>(Name)) + return pUB; + + if (auto* pSampler = GetResourceByName<SamplerBindInfo>(Name)) + return pSampler; + + if (auto* pImage = GetResourceByName<ImageBindInfo>(Name)) + return pImage; + + if (auto* pSSBO = GetResourceByName<StorageBufferBindInfo>(Name)) + return pSSBO; + + return nullptr; +} + +Uint32 ShaderVariableGL::GetVariableCount() const +{ + return GetNumUBs() + GetNumTextures() + GetNumImages() + GetNumStorageBuffers(); +} + +class ShaderVariableLocator +{ +public: + ShaderVariableLocator(const ShaderVariableGL& _Layout, + Uint32 _Index) : + // clang-format off + Layout {_Layout}, + Index {_Index} + // clang-format on + { + } + + template <typename ResourceType> + IShaderResourceVariable* TryResource(Uint32 NumResources) + { + if (Index < NumResources) + return &Layout.GetResource<ResourceType>(Index); + else + { + Index -= NumResources; + return nullptr; + } + } + +private: + ShaderVariableGL const& Layout; + Uint32 Index; +}; + + +IShaderResourceVariable* ShaderVariableGL::GetVariable(Uint32 Index) const +{ + ShaderVariableLocator VarLocator(*this, Index); + + if (auto* pUB = VarLocator.TryResource<UniformBuffBindInfo>(GetNumUBs())) + return pUB; + + if (auto* pSampler = VarLocator.TryResource<SamplerBindInfo>(GetNumTextures())) + return pSampler; + + if (auto* pImage = VarLocator.TryResource<ImageBindInfo>(GetNumImages())) + return pImage; + + if (auto* pSSBO = VarLocator.TryResource<StorageBufferBindInfo>(GetNumStorageBuffers())) + return pSSBO; + + LOG_ERROR(Index, " is not a valid variable index."); + return nullptr; +} + + + +class ShaderVariableIndexLocator +{ +public: + ShaderVariableIndexLocator(const ShaderVariableGL& _Layout, const ShaderVariableGL::GLVariableBase& Variable) : + // clang-format off + Layout {_Layout}, + VarOffset(reinterpret_cast<const Uint8*>(&Variable) - reinterpret_cast<const Uint8*>(_Layout.m_ResourceBuffer.get())) + // clang-format on + {} + + template <typename ResourceType> + bool TryResource(Uint32 NextResourceTypeOffset, Uint32 VarCount) + { + if (VarOffset < NextResourceTypeOffset) + { + auto RelativeOffset = VarOffset - Layout.GetResourceOffset<ResourceType>(); + DEV_CHECK_ERR(RelativeOffset % sizeof(ResourceType) == 0, "Offset is not multiple of resource type (", sizeof(ResourceType), ")"); + RelativeOffset /= sizeof(ResourceType); + VERIFY(RelativeOffset >= 0 && RelativeOffset < VarCount, + "Relative offset is out of bounds which either means the variable does not belong to this SRB or " + "there is a bug in varaible offsets"); + Index += static_cast<Uint32>(RelativeOffset); + return true; + } + else + { + Index += VarCount; + return false; + } + } + + Uint32 GetIndex() const { return Index; } + +private: + const ShaderVariableGL& Layout; + const size_t VarOffset; + Uint32 Index = 0; +}; + + +Uint32 ShaderVariableGL::GetVariableIndex(const GLVariableBase& Var) const +{ + if (!m_ResourceBuffer) + { + LOG_ERROR("This shader resource layout does not have resources"); + return static_cast<Uint32>(-1); + } + + ShaderVariableIndexLocator IdxLocator(*this, Var); + + if (IdxLocator.TryResource<UniformBuffBindInfo>(m_TextureOffset, GetNumUBs())) + return IdxLocator.GetIndex(); + + if (IdxLocator.TryResource<SamplerBindInfo>(m_ImageOffset, GetNumTextures())) + return IdxLocator.GetIndex(); + + if (IdxLocator.TryResource<ImageBindInfo>(m_StorageBufferOffset, GetNumImages())) + return IdxLocator.GetIndex(); + + if (IdxLocator.TryResource<StorageBufferBindInfo>(m_VariableEndOffset, GetNumStorageBuffers())) + return IdxLocator.GetIndex(); + + LOG_ERROR("Failed to get variable index. The variable ", &Var, " does not belong to this shader resource layout"); + return ~0u; +} + +#ifdef DILIGENT_DEVELOPMENT +bool ShaderVariableGL::dvpVerifyBindings(const ShaderResourceCacheGL& ResourceCache) const +{ +# define LOG_MISSING_BINDING(VarType, BindInfo, ArrIndex) LOG_ERROR_MESSAGE("No resource is bound to ", VarType, " variable '", GetShaderResourcePrintName(Desc, ArrIndex), "'") + + bool BindingsOK = true; + HandleConstResources( + [&](const UniformBuffBindInfo& ub) // + { + const auto& Desc = GetResourceDesc(ub.m_ResIndex); + const auto& Attr = GetAttribs(ub.m_ResIndex); + for (Uint32 ArrInd = 0; ArrInd < Desc.ArraySize; ++ArrInd) + { + if (!ResourceCache.IsUBBound(Attr.CacheOffset + ArrInd)) + { + LOG_MISSING_BINDING("constant buffer", ub, ArrInd); + BindingsOK = false; + } + } + }, + + [&](const SamplerBindInfo& sam) // + { + const auto& Desc = GetResourceDesc(sam.m_ResIndex); + const auto& Attr = GetAttribs(sam.m_ResIndex); + for (Uint32 ArrInd = 0; ArrInd < Desc.ArraySize; ++ArrInd) + { + VERIFY_EXPR(Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV || + Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV); + if (!ResourceCache.IsTextureBound(Attr.CacheOffset + ArrInd, Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV)) + { + LOG_MISSING_BINDING("texture", sam, ArrInd); + BindingsOK = false; + } + else + { + const auto& CachedSampler = ResourceCache.GetConstTexture(Attr.CacheOffset + ArrInd); + if (Attr.IsImmutableSamplerAssigned() && CachedSampler.pSampler == nullptr) + { + LOG_ERROR_MESSAGE("Immutable sampler is not initialized for texture '", Desc.Name, "'"); + BindingsOK = false; + } + } + } + }, + + [&](const ImageBindInfo& img) // + { + const auto& Desc = GetResourceDesc(img.m_ResIndex); + const auto& Attr = GetAttribs(img.m_ResIndex); + for (Uint32 ArrInd = 0; ArrInd < Desc.ArraySize; ++ArrInd) + { + VERIFY_EXPR(Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV || + Desc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV); + if (!ResourceCache.IsImageBound(Attr.CacheOffset + ArrInd, Desc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_UAV)) + { + LOG_MISSING_BINDING("texture UAV", img, ArrInd); + BindingsOK = false; + } + } + }, + + [&](const StorageBufferBindInfo& ssbo) // + { + const auto& Desc = GetResourceDesc(ssbo.m_ResIndex); + const auto& Attr = GetAttribs(ssbo.m_ResIndex); + for (Uint32 ArrInd = 0; ArrInd < Desc.ArraySize; ++ArrInd) + { + if (!ResourceCache.IsSSBOBound(Attr.CacheOffset + ArrInd)) + { + LOG_MISSING_BINDING("buffer", ssbo, ArrInd); + BindingsOK = false; + } + } + }); +# undef LOG_MISSING_BINDING + + return BindingsOK; +} + +#endif // DILIGENT_DEVELOPMENT + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp index 33be0cfc..67a69a61 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp @@ -503,7 +503,7 @@ void TextureBaseGL::UpdateData(GLContextState& CtxState, Uint32 MipLevel, Uint32 // data written by shaders prior to the barrier. Additionally, texture writes from these // commands issued after the barrier will not execute until all shader writes initiated prior // to the barrier complete - TextureMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT, CtxState); + TextureMemoryBarrier(MEMORY_BARRIER_TEXTURE_UPDATE, CtxState); } //void TextureBaseGL::UpdateData(Uint32 Offset, Uint32 Size, const void* pData) @@ -647,19 +647,12 @@ void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL, } -void TextureBaseGL::TextureMemoryBarrier(Uint32 RequiredBarriers, GLContextState& GLContextState) +void TextureBaseGL::TextureMemoryBarrier(MEMORY_BARRIER RequiredBarriers, GLContextState& GLContextState) { #if GL_ARB_shader_image_load_store # ifdef DILIGENT_DEBUG { - // clang-format off - constexpr Uint32 TextureBarriers = - GL_TEXTURE_FETCH_BARRIER_BIT | - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | - GL_PIXEL_BUFFER_BARRIER_BIT | - GL_TEXTURE_UPDATE_BARRIER_BIT | - GL_FRAMEBUFFER_BARRIER_BIT; - // clang-format on + constexpr Uint32 TextureBarriers = MEMORY_BARRIER_ALL_TEXTURE_BARRIERS; VERIFY((RequiredBarriers & TextureBarriers) != 0, "At least one texture memory barrier flag should be set"); VERIFY((RequiredBarriers & ~TextureBarriers) == 0, "Inappropriate texture memory barrier flag"); } diff --git a/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp b/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp index 6a977e64..43bd9347 100644 --- a/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/VAOCache.cpp @@ -129,10 +129,10 @@ const GLObjectWrappers::GLVertexArrayObj& VAOCache::GetVAO(IPipelineState* VERIFY(pCurrBuf != nullptr, "No buffer bound to slot ", BuffSlot); ValidatedCast<BufferGLImpl>(pCurrBuf)->BufferMemoryBarrier( - GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT, // Vertex data sourced from buffer objects after the barrier - // will reflect data written by shaders prior to the barrier. - // The set of buffer objects affected by this bit is derived - // from the GL_VERTEX_ARRAY_BUFFER_BINDING bindings + MEMORY_BARRIER_VERTEX_BUFFER, // Vertex data sourced from buffer objects after the barrier + // will reflect data written by shaders prior to the barrier. + // The set of buffer objects affected by this bit is derived + // from the GL_VERTEX_ARRAY_BUFFER_BINDING bindings GLState); CurrStreamKey.BufferUId = pCurrBuf ? pCurrBuf->GetUniqueID() : 0; @@ -151,10 +151,10 @@ const GLObjectWrappers::GLVertexArrayObj& VAOCache::GetVAO(IPipelineState* if (pIndexBuffer) { pIndexBufferGL->BufferMemoryBarrier( - GL_ELEMENT_ARRAY_BARRIER_BIT, // Vertex array indices sourced from buffer objects after the barrier - // will reflect data written by shaders prior to the barrier. - // The buffer objects affected by this bit are derived from the - // ELEMENT_ARRAY_BUFFER binding. + MEMORY_BARRIER_INDEX_BUFFER, // Vertex array indices sourced from buffer objects after the barrier + // will reflect data written by shaders prior to the barrier. + // The buffer objects affected by this bit are derived from the + // ELEMENT_ARRAY_BUFFER binding. GLState); } |
