summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineOpenGL
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-10-07 16:19:35 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-10-07 16:19:35 +0000
commit42b12901274c2aabee3ddbb9d3a012d28e5f5f7d (patch)
tree8f78dfa0d2ace8192d07671da8676498c3623ded /Graphics/GraphicsEngineOpenGL
parentFixed JNI object reference leak in AndroidFileSystem (diff)
downloadDiligentCore-42b12901274c2aabee3ddbb9d3a012d28e5f5f7d.tar.gz
DiligentCore-42b12901274c2aabee3ddbb9d3a012d28e5f5f7d.zip
Completely reworked shader resource binding implementation in OpenGL backend to make it function similar to other backends
Diffstat (limited to 'Graphics/GraphicsEngineOpenGL')
-rw-r--r--Graphics/GraphicsEngineOpenGL/CMakeLists.txt6
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/BufferViewGLImpl.h10
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.h352
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/GLProgram.h52
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.h266
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/GLProgramResources.h382
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h35
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.h17
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h16
-rw-r--r--Graphics/GraphicsEngineOpenGL/include/pch.h6
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp476
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp92
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp880
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/GLProgram.cpp47
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp112
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp1369
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp229
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp156
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp104
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp6
20 files changed, 2897 insertions, 1716 deletions
diff --git a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt
index 1a17fa14..41760feb 100644
--- a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt
+++ b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt
@@ -12,7 +12,8 @@ set(INCLUDE
include/GLContext.h
include/GLContextState.h
include/GLObjectWrapper.h
- include/GLProgram.h
+ include/GLProgramResourceCache.h
+ include/GLPipelineResourceLayout.h
include/GLProgramResources.h
include/GLTypeConversions.h
include/pch.h
@@ -60,7 +61,8 @@ set(SOURCE
src/FenceGLImpl.cpp
src/GLContextState.cpp
src/GLObjectWrapper.cpp
- src/GLProgram.cpp
+ src/GLProgramResourceCache.cpp
+ src/GLPipelineResourceLayout.cpp
src/GLProgramResources.cpp
src/GLTypeConversions.cpp
src/PipelineStateGLImpl.cpp
diff --git a/Graphics/GraphicsEngineOpenGL/include/BufferViewGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/BufferViewGLImpl.h
index b43a0c6e..bb834536 100644
--- a/Graphics/GraphicsEngineOpenGL/include/BufferViewGLImpl.h
+++ b/Graphics/GraphicsEngineOpenGL/include/BufferViewGLImpl.h
@@ -45,12 +45,12 @@ class BufferViewGLImpl final : public BufferViewBase<IBufferViewGL, RenderDevice
public:
using TBuffViewBase = BufferViewBase<IBufferViewGL, RenderDeviceGLImpl>;
- BufferViewGLImpl( IReferenceCounters *pRefCounters,
- RenderDeviceGLImpl *pDevice,
- IDeviceContext *pContext,
+ BufferViewGLImpl( IReferenceCounters* pRefCounters,
+ RenderDeviceGLImpl* pDevice,
+ IDeviceContext* pContext,
const BufferViewDesc& ViewDesc,
- BufferGLImpl *pBuffer,
- bool bIsDefaultView);
+ BufferGLImpl* pBuffer,
+ bool bIsDefaultView);
/// Queries the specific interface, see IObject::QueryInterface() for details
virtual void QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface )override final;
diff --git a/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.h b/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.h
new file mode 100644
index 00000000..d2cf2951
--- /dev/null
+++ b/Graphics/GraphicsEngineOpenGL/include/GLPipelineResourceLayout.h
@@ -0,0 +1,352 @@
+/* Copyright 2019 Diligent Graphics LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+#include <array>
+
+#include "Object.h"
+#include "ShaderResourceVariableBase.h"
+#include "GLProgramResources.h"
+#include "GLProgramResourceCache.h"
+
+namespace Diligent
+{
+
+class IMemoryAllocator;
+
+class GLPipelineResourceLayout
+{
+public:
+ GLPipelineResourceLayout(IObject& Owner) :
+ m_Owner(Owner)
+ {}
+ ~GLPipelineResourceLayout();
+
+ // No copies, only moves are allowed
+ GLPipelineResourceLayout (const GLPipelineResourceLayout&) = delete;
+ GLPipelineResourceLayout& operator = (const GLPipelineResourceLayout&) = delete;
+ GLPipelineResourceLayout ( GLPipelineResourceLayout&&) = default;
+ GLPipelineResourceLayout& operator = ( GLPipelineResourceLayout&&) = delete;
+
+ void Initialize(GLProgramResources* ProgramResources,
+ Uint32 NumPrograms,
+ const PipelineResourceLayoutDesc& ResourceLayout,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ GLProgramResourceCache* pResourceCache);
+
+ static size_t GetRequiredMemorySize(GLProgramResources* ProgramResources,
+ Uint32 NumPrograms,
+ const PipelineResourceLayoutDesc& ResourceLayout,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes);
+
+ void CopyResources(GLProgramResourceCache& DstCache)const;
+
+ struct GLVariableBase : public ShaderVariableBase<GLPipelineResourceLayout>
+ {
+ using TBase = ShaderVariableBase<GLPipelineResourceLayout>;
+ GLVariableBase(const GLProgramResources::GLResourceAttribs& ResourceAttribs,
+ GLPipelineResourceLayout& ParentLayout,
+ SHADER_RESOURCE_VARIABLE_TYPE VariableType,
+ Int32 StaticSamplerIdx) :
+ TBase {ParentLayout},
+ m_Attribs {ResourceAttribs },
+ m_VariableType {VariableType },
+ m_StaticSamplerIdx{StaticSamplerIdx}
+ {
+ VERIFY_EXPR(StaticSamplerIdx < 0 || ResourceAttribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV);
+ }
+
+ virtual SHADER_RESOURCE_VARIABLE_TYPE GetType()const override final
+ {
+ return m_VariableType;
+ }
+
+ virtual ShaderResourceDesc GetResourceDesc()const override final
+ {
+ return m_Attribs.GetResourceDesc();
+ }
+
+ virtual Uint32 GetIndex()const override final
+ {
+ return m_ParentResLayout.GetVariableIndex(*this);
+ }
+
+ const GLProgramResources::GLResourceAttribs& m_Attribs;
+ const SHADER_RESOURCE_VARIABLE_TYPE m_VariableType;
+ const Int32 m_StaticSamplerIdx;
+ };
+
+
+ struct UniformBuffBindInfo final : GLVariableBase
+ {
+ UniformBuffBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs,
+ GLPipelineResourceLayout& ParentResLayout,
+ SHADER_RESOURCE_VARIABLE_TYPE VariableType) :
+ GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, -1}
+ {}
+
+ // Non-virtual function
+ void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex);
+ virtual void Set(IDeviceObject* pObject)override final
+ {
+ BindResource(pObject, 0);
+ }
+
+ virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final
+ {
+ for(Uint32 elem=0; elem < NumElements; ++elem)
+ BindResource(ppObjects[elem], FirstElement+elem);
+ }
+
+ virtual bool IsBound(Uint32 ArrayIndex)const override final
+ {
+ VERIFY_EXPR(ArrayIndex < m_Attribs.ArraySize);
+ return m_ParentResLayout.m_pResourceCache->IsUBBound(m_Attribs.Binding + ArrayIndex);
+ }
+ };
+
+
+ struct SamplerBindInfo final : GLVariableBase
+ {
+ SamplerBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs,
+ GLPipelineResourceLayout& ParentResLayout,
+ SHADER_RESOURCE_VARIABLE_TYPE VariableType,
+ Int32 StaticSamplerIdx) :
+ GLVariableBase {ResourceAttribs, ParentResLayout, VariableType, StaticSamplerIdx}
+ {}
+
+ // Non-virtual function
+ void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex);
+ virtual void Set(IDeviceObject* pObject)override final
+ {
+ BindResource(pObject, 0);
+ }
+
+ virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final
+ {
+ for(Uint32 elem=0; elem < NumElements; ++elem)
+ BindResource(ppObjects[elem], FirstElement+elem);
+ }
+
+ virtual bool 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);
+ }
+ };
+
+
+ struct ImageBindInfo final : GLVariableBase
+ {
+ ImageBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs,
+ GLPipelineResourceLayout& ParentResLayout,
+ SHADER_RESOURCE_VARIABLE_TYPE VariableType) :
+ GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, -1}
+ {}
+
+ // Provide non-virtual function
+ void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex);
+ virtual void Set(IDeviceObject* pObject)override final
+ {
+ BindResource(pObject, 0);
+ }
+
+ virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final
+ {
+ for(Uint32 elem=0; elem < NumElements; ++elem)
+ BindResource(ppObjects[elem], FirstElement+elem);
+ }
+
+ virtual bool 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);
+ }
+ };
+
+
+ struct StorageBufferBindInfo final : GLVariableBase
+ {
+ StorageBufferBindInfo(const GLProgramResources::GLResourceAttribs& ResourceAttribs,
+ GLPipelineResourceLayout& ParentResLayout,
+ SHADER_RESOURCE_VARIABLE_TYPE VariableType) :
+ GLVariableBase{ResourceAttribs, ParentResLayout, VariableType, -1}
+ {}
+
+ // Non-virtual function
+ void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex);
+ virtual void Set(IDeviceObject* pObject)override final
+ {
+ BindResource(pObject, 0);
+ }
+
+ virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final
+ {
+ for(Uint32 elem=0; elem < NumElements; ++elem)
+ BindResource(ppObjects[elem], FirstElement+elem);
+ }
+
+ virtual bool IsBound(Uint32 ArrayIndex)const override final
+ {
+ VERIFY_EXPR(ArrayIndex < m_Attribs.ArraySize);
+ return m_ParentResLayout.m_pResourceCache->IsSSBOBound(m_Attribs.Binding + 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);
+
+#ifdef DEVELOPMENT
+ bool dvpVerifyBindings()const;
+#endif
+
+ IShaderResourceVariable* GetShaderVariable( SHADER_TYPE ShaderStage, const Char* Name );
+ IShaderResourceVariable* GetShaderVariable( SHADER_TYPE ShaderStage, Uint32 Index );
+
+ IObject& GetOwner(){return m_Owner;}
+
+ Uint32 GetNumVariables(SHADER_TYPE ShaderStage)const;
+
+ Uint32 GetNumUBs() const { return (m_SamplerOffset - m_UBOffset) / sizeof(UniformBuffBindInfo); }
+ Uint32 GetNumSamplers() const { return (m_ImageOffset - m_SamplerOffset) / sizeof(SamplerBindInfo); }
+ Uint32 GetNumImages() const { return (m_StorageBufferOffset - m_ImageOffset) / sizeof(ImageBindInfo) ; }
+ Uint32 GetNumStorageBuffers() const { return (m_VariableEndOffset - m_StorageBufferOffset) / sizeof(StorageBufferBindInfo); }
+
+ template<typename ResourceType> Uint32 GetNumResources()const;
+ template<> Uint32 GetNumResources<UniformBuffBindInfo>() const { return GetNumUBs(); }
+ template<> Uint32 GetNumResources<SamplerBindInfo>() const { return GetNumSamplers(); }
+ template<> Uint32 GetNumResources<ImageBindInfo>() const { return GetNumImages(); }
+ template<> Uint32 GetNumResources<StorageBufferBindInfo>() const { return GetNumStorageBuffers(); }
+
+ template<typename ResourceType>
+ const ResourceType& GetConstResource(Uint32 ResIndex)const
+ {
+ VERIFY(ResIndex < GetNumResources<ResourceType>(), "Resource index (", ResIndex, ") exceeds max allowed value (", GetNumResources<ResourceType>(), ")");
+ auto Offset = GetResourceOffset<ResourceType>();
+ return reinterpret_cast<const ResourceType*>( reinterpret_cast<const Uint8*>(m_ResourceBuffer.get()) + Offset)[ResIndex];
+ }
+
+ Uint32 GetVariableIndex(const GLVariableBase& Var)const;
+
+private:
+
+/* 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, 6> m_ProgramIndex = {-1, -1, -1, -1, -1, -1};
+/*46*/ Uint8 m_NumPrograms = 0;
+/*48*/
+
+ template<typename ResourceType> OffsetType GetResourceOffset()const;
+ template<> OffsetType GetResourceOffset<UniformBuffBindInfo> () const { return m_UBOffset; }
+ template<> OffsetType GetResourceOffset<SamplerBindInfo> () const { return m_SamplerOffset; }
+ template<> OffsetType GetResourceOffset<ImageBindInfo> () const { return m_ImageOffset; }
+ template<> OffsetType GetResourceOffset<StorageBufferBindInfo>() const { return m_StorageBufferOffset; }
+
+ template<typename ResourceType>
+ ResourceType& GetResource(Uint32 ResIndex)
+ {
+ 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);
+
+ template<typename THandleUB,
+ typename THandleSampler,
+ typename THandleImage,
+ typename THandleStorageBuffer>
+ void HandleResources(THandleUB HandleUB,
+ THandleSampler HandleSampler,
+ THandleImage HandleImage,
+ THandleStorageBuffer HandleStorageBuffer)
+ {
+ for (Uint32 ub = 0; ub < GetNumResources<UniformBuffBindInfo>(); ++ub)
+ HandleUB(GetResource<UniformBuffBindInfo>(ub));
+
+ for (Uint32 s = 0; s < GetNumResources<SamplerBindInfo>(); ++s)
+ HandleSampler(GetResource<SamplerBindInfo>(s));
+
+ for (Uint32 i = 0; i < GetNumResources<ImageBindInfo>(); ++i)
+ HandleImage(GetResource<ImageBindInfo>(i));
+
+ for (Uint32 s = 0; s < GetNumResources<StorageBufferBindInfo>(); ++s)
+ HandleStorageBuffer(GetResource<StorageBufferBindInfo>(s));
+ }
+
+ template<typename THandleUB,
+ typename THandleSampler,
+ typename THandleImage,
+ typename THandleStorageBuffer>
+ void HandleConstResources(THandleUB HandleUB,
+ THandleSampler HandleSampler,
+ THandleImage HandleImage,
+ THandleStorageBuffer HandleStorageBuffer)const
+ {
+ for (Uint32 ub = 0; ub < GetNumResources<UniformBuffBindInfo>(); ++ub)
+ HandleUB(GetConstResource<UniformBuffBindInfo>(ub));
+
+ for (Uint32 s = 0; s < GetNumResources<SamplerBindInfo>(); ++s)
+ HandleSampler(GetConstResource<SamplerBindInfo>(s));
+
+ for (Uint32 i = 0; i < GetNumResources<ImageBindInfo>(); ++i)
+ HandleImage(GetConstResource<ImageBindInfo>(i));
+
+ for (Uint32 s = 0; s < GetNumResources<StorageBufferBindInfo>(); ++s)
+ HandleStorageBuffer(GetConstResource<StorageBufferBindInfo>(s));
+ }
+
+ friend class ShaderVariableIndexLocator;
+ friend class ShaderVariableLocator;
+};
+
+}
diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgram.h b/Graphics/GraphicsEngineOpenGL/include/GLProgram.h
deleted file mode 100644
index 03399bd1..00000000
--- a/Graphics/GraphicsEngineOpenGL/include/GLProgram.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright 2019 Diligent Graphics LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#pragma once
-#include "GLObjectWrapper.h"
-#include "GLProgramResources.h"
-
-namespace Diligent
-{
- class GLProgram : public GLObjectWrappers::GLProgramObj
- {
- public:
- GLProgram(bool CreateObject);
- GLProgram(GLProgram&& Program);
-
- GLProgram (const GLProgram&) = delete;
- GLProgram& operator = (const GLProgram&) = delete;
- GLProgram& operator = ( GLProgram&&) = delete;
-
- void InitResources(RenderDeviceGLImpl* pDeviceGLImpl,
- SHADER_TYPE ShaderStage,
- IObject& Owner);
-
- void BindConstantResources(IResourceMapping* pResourceMapping, Uint32 Flags);
-
- const GLProgramResources& GetResources() const { return m_AllResources; }
-
- private:
- GLProgramResources m_AllResources;
- // When adding new member DO NOT FORGET TO UPDATE GLProgram( GLProgram&& Program )!!!
- };
-}
diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.h b/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.h
new file mode 100644
index 00000000..a98d88cb
--- /dev/null
+++ b/Graphics/GraphicsEngineOpenGL/include/GLProgramResourceCache.h
@@ -0,0 +1,266 @@
+/* Copyright 2019 Diligent Graphics LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+#include "BufferGLImpl.h"
+#include "TextureBaseGL.h"
+#include "SamplerGLImpl.h"
+
+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 Strg Blocks |
+// |----------------------------------------------------|--------------------------|---------------------------|
+// | 0 | 1 | ... | UBCount-1 | 0 | 1 | ...| SmpCount-1 | 0 | 1 | ... | ImgCount-1 | 0 | 1 | ... | SBOCount-1 |
+// -----------------------------------------------------------------------------------------------------------
+//
+class GLProgramResourceCache
+{
+public:
+ GLProgramResourceCache()
+ {}
+
+ ~GLProgramResourceCache();
+
+ GLProgramResourceCache (const GLProgramResourceCache&) = delete;
+ GLProgramResourceCache& operator = (const GLProgramResourceCache&) = delete;
+ GLProgramResourceCache (GLProgramResourceCache&&) = delete;
+ GLProgramResourceCache& operator = (GLProgramResourceCache&&) = delete;
+
+ /// Describes a resource bound to a uniform buffer or a shader storage block slot
+ struct CachedUB
+ {
+ /// Strong reference to the buffer
+ RefCntAutoPtr<BufferGLImpl> pBuffer;
+ };
+
+ /// Describes a resource bound to a sampler or an image slot
+ struct CachedResourceView
+ {
+ /// Wee keep strong reference to the view instead of the reference
+ /// to the texture or buffer because this is more efficient from
+ /// performance point of view: this avoids one pair of
+ /// AddStrongRef()/ReleaseStrongRef(). The view holds a strong reference
+ /// to the texture or the buffer, so it makes no difference.
+ RefCntAutoPtr<IDeviceObject> pView;
+ TextureBaseGL* pTexture = nullptr;
+ union
+ {
+ BufferGLImpl* pBuffer = nullptr; // When pTexture == nullptr
+ SamplerGLImpl* pSampler; // When pTexture != nullptr
+ };
+ CachedResourceView() noexcept {}
+
+ void Set(RefCntAutoPtr<TextureViewGLImpl>&& pTexView, bool SetSampler)
+ {
+ // Do not null out pSampler as it could've been initialized by PipelineStateGLImpl::InitializeSRBResourceCache!
+ // pSampler = nullptr;
+
+ // Avoid unnecessary virtual function calls
+ pTexture = pTexView ? ValidatedCast<TextureBaseGL>(pTexView->TextureViewGLImpl::GetTexture()) : nullptr;
+ if (pTexView && SetSampler)
+ {
+ pSampler = ValidatedCast<SamplerGLImpl>(pTexView->GetSampler());
+ }
+
+ pView.Attach(pTexView.Detach());
+ }
+
+ void Set(RefCntAutoPtr<BufferViewGLImpl>&& pBufView)
+ {
+ pTexture = nullptr;
+ // Avoid unnecessary virtual function calls
+ pBuffer = pBufView ? ValidatedCast<BufferGLImpl>(pBufView->BufferViewGLImpl::GetBuffer()) : nullptr;
+ pView.Attach(pBufView.Detach());
+ }
+ };
+
+ struct CachedSSBO
+ {
+ /// Strong reference to the buffer
+ RefCntAutoPtr<BufferViewGLImpl> pBufferView;
+ };
+
+
+ static size_t GetRequriedMemorySize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount);
+ void Initialize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount, class IMemoryAllocator& MemAllocator);
+ void Destroy(class IMemoryAllocator& MemAllocator);
+
+ void SetUniformBuffer(Uint32 Binding, RefCntAutoPtr<BufferGLImpl>&& pBuff)
+ {
+ GetUB(Binding).pBuffer = std::move(pBuff);
+ }
+
+ void SetTexSampler(Uint32 Binding, RefCntAutoPtr<TextureViewGLImpl>&& pTexView, bool SetSampler)
+ {
+ GetSampler(Binding).Set(std::move(pTexView), SetSampler);
+ }
+
+ void SetStaticSampler(Uint32 Binding, ISampler* pStaticSampler)
+ {
+ GetSampler(Binding).pSampler = ValidatedCast<SamplerGLImpl>(pStaticSampler);
+ }
+
+ void CopySampler(Uint32 Binding, const CachedResourceView& SrcSam)
+ {
+ GetSampler(Binding) = SrcSam;
+ }
+
+ void SetBufSampler(Uint32 Binding, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView)
+ {
+ GetSampler(Binding).Set(std::move(pBuffView));
+ }
+
+ void SetTexImage(Uint32 Binding, RefCntAutoPtr<TextureViewGLImpl>&& pTexView)
+ {
+ GetImage(Binding).Set(std::move(pTexView), false);
+ }
+
+ void SetBufImage(Uint32 Binding, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView)
+ {
+ GetImage(Binding).Set(std::move(pBuffView));
+ }
+
+ void CopyImage(Uint32 Binding, const CachedResourceView& SrcImg)
+ {
+ GetImage(Binding) = SrcImg;
+ }
+
+ void SetSSBO(Uint32 Binding, RefCntAutoPtr<BufferViewGLImpl>&& pBuffView)
+ {
+ GetSSBO(Binding).pBufferView = std::move(pBuffView);
+ }
+
+ bool IsUBBound(Uint32 Binding)const
+ {
+ if (Binding >= GetUBCount())
+ return false;
+
+ const auto& UB = GetUB(Binding);
+ return UB.pBuffer;
+ }
+
+ bool IsSamplerBound(Uint32 Binding, bool dbgIsTextureView)const
+ {
+ if (Binding >= GetSamplerCount())
+ return false;
+
+ const auto& Sampler = GetSampler(Binding);
+ VERIFY_EXPR(dbgIsTextureView || Sampler.pTexture == nullptr);
+ return Sampler.pView;
+ }
+
+ bool IsImageBound(Uint32 Binding, bool dbgIsTextureView)const
+ {
+ if (Binding >= GetImageCount())
+ return false;
+
+ const auto& Image = GetImage(Binding);
+ VERIFY_EXPR(dbgIsTextureView || Image.pTexture == nullptr);
+ return Image.pView;
+ }
+
+ bool IsSSBOBound(Uint32 Binding)const
+ {
+ if (Binding >= GetSSBOCount())
+ return false;
+
+ const auto& SSBO = GetSSBO(Binding);
+ return SSBO.pBufferView;
+ }
+
+ 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); }
+
+ const CachedUB& GetUB(Uint32 Binding)const
+ {
+ VERIFY(Binding < GetUBCount(), "Uniform buffer binding (", Binding, ") is out of range");
+ return reinterpret_cast<CachedUB*>(m_pResourceData + m_UBsOffset)[Binding];
+ }
+
+ const CachedResourceView& GetSampler(Uint32 Binding)const
+ {
+ VERIFY(Binding < GetSamplerCount(), "Sampler binding (", Binding, ") is out of range");
+ return reinterpret_cast<CachedResourceView*>(m_pResourceData + m_SmplrsOffset)[Binding];
+ }
+
+ const CachedResourceView& GetImage(Uint32 Binding)const
+ {
+ VERIFY(Binding < GetImageCount(), "Image buffer binding (", Binding, ") is out of range");
+ return reinterpret_cast<CachedResourceView*>(m_pResourceData + m_ImgsOffset)[Binding];
+ }
+
+ const CachedSSBO& GetSSBO(Uint32 Binding)const
+ {
+ VERIFY(Binding < GetSSBOCount(), "Shader storage block binding (", Binding, ") is out of range");
+ return reinterpret_cast<CachedSSBO*>(m_pResourceData + m_SSBOsOffset)[Binding];
+ }
+
+ bool IsInitialized()const
+ {
+ return m_MemoryEndOffset != InvalidResourceOffset;
+ }
+
+private:
+ CachedUB& GetUB(Uint32 Binding)
+ {
+ return const_cast<CachedUB&>(const_cast<const GLProgramResourceCache*>(this)->GetUB(Binding));
+ }
+
+ CachedResourceView& GetSampler(Uint32 Binding)
+ {
+ return const_cast<CachedResourceView&>(const_cast<const GLProgramResourceCache*>(this)->GetSampler(Binding));
+ }
+
+ CachedResourceView& GetImage(Uint32 Binding)
+ {
+ return const_cast<CachedResourceView&>(const_cast<const GLProgramResourceCache*>(this)->GetImage(Binding));
+ }
+
+ CachedSSBO& GetSSBO(Uint32 Binding)
+ {
+ return const_cast<CachedSSBO&>(const_cast<const GLProgramResourceCache*>(this)->GetSSBO(Binding));
+ }
+
+ static constexpr const Uint16 InvalidResourceOffset = 0xFFFF;
+ static constexpr const Uint16 m_UBsOffset = 0;
+ Uint16 m_SmplrsOffset = InvalidResourceOffset;
+ Uint16 m_ImgsOffset = InvalidResourceOffset;
+ Uint16 m_SSBOsOffset = InvalidResourceOffset;
+ Uint16 m_MemoryEndOffset = InvalidResourceOffset;
+
+ Uint8* m_pResourceData = nullptr;
+
+#ifdef _DEBUG
+ IMemoryAllocator* m_pdbgMemoryAllocator = nullptr;
+#endif
+
+};
+
+}
diff --git a/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.h b/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.h
index 703841cc..74faad45 100644
--- a/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.h
+++ b/Graphics/GraphicsEngineOpenGL/include/GLProgramResources.h
@@ -25,17 +25,9 @@
#include <vector>
-#include "GLObjectWrapper.h"
-#include "HashUtils.h"
-#include "ShaderBase.h"
-#include "SamplerGLImpl.h"
-#include "HashUtils.h"
-#include "ShaderResourceVariableBase.h"
+#include "Object.h"
#include "StringPool.h"
-
-#ifdef _DEBUG
-# define VERIFY_RESOURCE_BINDINGS
-#endif
+#include "HashUtils.h"
namespace Diligent
{
@@ -50,91 +42,75 @@ namespace Diligent
GLProgramResources& operator = (const GLProgramResources&) = delete;
GLProgramResources& operator = ( GLProgramResources&&) = delete;
- void LoadUniforms(IObject& Owner,
- class RenderDeviceGLImpl* pDeviceGLImpl,
- SHADER_TYPE ShaderStages,
- GLuint GLProgram);
+ void LoadUniforms(SHADER_TYPE ShaderStages,
+ const GLObjectWrappers::GLProgramObj& GLProgram,
+ class GLContextState& State,
+ Uint32& UniformBufferBinding,
+ Uint32& SamplerBinding,
+ Uint32& ImageBinding,
+ Uint32& StorageBufferBinding);
-
- void Clone(class RenderDeviceGLImpl* pDeviceGLImpl,
- IObject& Owner,
- const GLProgramResources& SrcResources,
- const PipelineResourceLayoutDesc& ResourceLayout,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes);
-
- struct GLProgramVariableBase : ShaderVariableBase
+ struct GLResourceAttribs
{
-/* 0 */ // ShaderVariableBase
-/* 16 */ const Char* Name;
-/* 24 */ const SHADER_RESOURCE_VARIABLE_TYPE VariableType;
-/* 25 */ const SHADER_RESOURCE_TYPE ResourceType;
-/* 26 */ const Uint16 VariableIndex;
-/* 28 */ Uint32 ArraySize;
-/* 32 */ RefCntAutoPtr<IDeviceObject>* const pResources;
-/* 40 */ //End of data
-
- GLProgramVariableBase(IObject& _Owner,
- const Char* _Name,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- SHADER_RESOURCE_TYPE _ResourceType,
- Uint16 _VariableIndex,
- Uint32 _ArraySize,
- RefCntAutoPtr<IDeviceObject>* _pResources) :
- ShaderVariableBase(_Owner),
- Name (_Name),
- VariableType (_VariableType),
- ResourceType (_ResourceType),
- VariableIndex (_VariableIndex),
- ArraySize (_ArraySize),
- pResources (_pResources)
- {
- VERIFY_EXPR(_ArraySize >= 1);
- }
-
- bool IsCompatibleWith(const GLProgramVariableBase& Var)const
- {
- return VariableType == Var.VariableType &&
- ResourceType == Var.ResourceType &&
- ArraySize == Var.ArraySize;
- }
-
- size_t GetHash()const
+/* 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
+
+ GLResourceAttribs(const Char* _Name,
+ SHADER_TYPE _ShaderStages,
+ SHADER_RESOURCE_TYPE _ResourceType,
+ Uint32 _Binding,
+ Uint32 _ArraySize)noexcept :
+ Name {_Name },
+ ShaderStages {_ShaderStages},
+ ResourceType {_ResourceType},
+ Binding {_Binding },
+ ArraySize {_ArraySize }
{
- return ComputeHash(static_cast<Int32>(VariableType), static_cast<Int32>(ResourceType), ArraySize);
+ VERIFY(_ShaderStages != SHADER_TYPE_UNKNOWN, "At least one shader stage must be specified");
+ VERIFY(_ResourceType != SHADER_RESOURCE_TYPE_UNKNOWN, "Unknown shader resource type");
+ VERIFY(_ArraySize >= 1, "Array size must be greater than 1");
}
- virtual void Set(IDeviceObject* pObject)override final
+ GLResourceAttribs(const GLResourceAttribs& Attribs,
+ StringPool& NamesPool)noexcept :
+ GLResourceAttribs
+ {
+ NamesPool.CopyString(Attribs.Name),
+ Attribs.ShaderStages,
+ Attribs.ResourceType,
+ Attribs.Binding,
+ Attribs.ArraySize
+ }
{
- VERIFY(pResources != nullptr, "This variable has no resource cache attached");
- pResources[0] = pObject;
}
- virtual void SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements)override final
+ bool IsCompatibleWith(const GLResourceAttribs& Var)const
{
- VERIFY(pResources, "This variable has no resource cache attached");
- VERIFY(FirstElement + NumElements <= ArraySize, "Array indices are out of range");
- for (Uint32 i=0; i < NumElements; ++i)
- pResources[FirstElement + i] = ppObjects[i];
- }
-
- virtual SHADER_RESOURCE_VARIABLE_TYPE GetType()const override final
- {
- return VariableType;
+ return ShaderStages == Var.ShaderStages &&
+ ResourceType == Var.ResourceType &&
+ Binding == Var.Binding &&
+ ArraySize == Var.ArraySize;
}
- virtual Uint32 GetIndex()const override final
+ size_t GetHash()const
{
- return VariableIndex;
+ return ComputeHash(static_cast<Uint32>(ShaderStages), static_cast<Uint32>(ResourceType), Binding, ArraySize);
}
- virtual bool IsBound(Uint32 ArrayIndex) const override final
+ String GetPrintName(Uint32 ArrayInd)const
{
- VERIFY(ArrayIndex < ArraySize, "Array index (", ArrayIndex, ") is out of range");
- return pResources[ArrayIndex] != nullptr;
+ VERIFY_EXPR(ArrayInd < ArraySize);
+ if (ArraySize > 1)
+ return String(Name) + '[' + std::to_string(ArrayInd) + ']';
+ else
+ return Name;
}
- virtual ShaderResourceDesc GetResourceDesc()const override final
+ ShaderResourceDesc GetResourceDesc()const
{
ShaderResourceDesc ResourceDesc;
ResourceDesc.Name = Name;
@@ -144,34 +120,38 @@ namespace Diligent
}
};
- struct UniformBufferInfo final : GLProgramVariableBase
+ struct UniformBufferInfo final : GLResourceAttribs
{
UniformBufferInfo (const UniformBufferInfo&) = delete;
UniformBufferInfo& operator= (const UniformBufferInfo&) = delete;
UniformBufferInfo ( UniformBufferInfo&&) = default;
UniformBufferInfo& operator= ( UniformBufferInfo&&) = delete;
- UniformBufferInfo(IObject& _Owner,
- const Char* _Name,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- SHADER_RESOURCE_TYPE _ResourceType,
- Uint16 _VariableIndex,
- Uint32 _ArraySize,
- RefCntAutoPtr<IDeviceObject>* _pResources,
- GLuint _UBIndex) :
- GLProgramVariableBase(_Owner, _Name, _VariableType, _ResourceType, _VariableIndex, _ArraySize, _pResources),
- UBIndex(_UBIndex)
+ UniformBufferInfo(const Char* _Name,
+ SHADER_TYPE _ShaderStages,
+ SHADER_RESOURCE_TYPE _ResourceType,
+ Uint32 _Binding,
+ Uint32 _ArraySize,
+ GLuint _UBIndex)noexcept :
+ GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _Binding, _ArraySize},
+ UBIndex {_UBIndex}
+ {}
+
+ UniformBufferInfo(const UniformBufferInfo& UB,
+ StringPool& NamesPool)noexcept :
+ GLResourceAttribs{UB, NamesPool},
+ UBIndex {UB.UBIndex }
{}
- bool IsCompatibleWith(const UniformBufferInfo& UBI)const
+ bool IsCompatibleWith(const UniformBufferInfo& UB)const
{
- return UBIndex == UBI.UBIndex &&
- GLProgramVariableBase::IsCompatibleWith(UBI);
+ return UBIndex == UB.UBIndex &&
+ GLResourceAttribs::IsCompatibleWith(UB);
}
size_t GetHash()const
{
- return ComputeHash(UBIndex, GLProgramVariableBase::GetHash());
+ return ComputeHash(UBIndex, GLResourceAttribs::GetHash());
}
const GLuint UBIndex;
@@ -179,79 +159,86 @@ namespace Diligent
static_assert((sizeof(UniformBufferInfo) % sizeof(void*)) == 0, "sizeof(UniformBufferInfo) must be multiple of sizeof(void*)");
- struct SamplerInfo final : GLProgramVariableBase
+ struct SamplerInfo final : GLResourceAttribs
{
SamplerInfo (const SamplerInfo&) = delete;
SamplerInfo& operator= (const SamplerInfo&) = delete;
SamplerInfo ( SamplerInfo&&) = default;
SamplerInfo& operator= ( SamplerInfo&&) = delete;
- SamplerInfo(IObject& _Owner,
- const Char* _Name,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- SHADER_RESOURCE_TYPE _ResourceType,
- Uint16 _VariableIndex,
- Uint32 _ArraySize,
- RefCntAutoPtr<IDeviceObject>* _pResources,
- GLint _Location,
- GLenum _SamplerType,
- class SamplerGLImpl* _pStaticSampler) :
- GLProgramVariableBase(_Owner, _Name, _VariableType, _ResourceType, _VariableIndex, _ArraySize, _pResources),
- Location (_Location),
- SamplerType (_SamplerType),
- pStaticSampler(_pStaticSampler)
+ 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}
{}
- bool IsCompatibleWith(const SamplerInfo& SI)const
+ SamplerInfo(const SamplerInfo& Sam,
+ StringPool& NamesPool)noexcept :
+ GLResourceAttribs{Sam, NamesPool},
+ Location {Sam.Location },
+ SamplerType {Sam.SamplerType}
+ {}
+
+ bool IsCompatibleWith(const SamplerInfo& Sam)const
{
- return Location == SI.Location &&
- pStaticSampler == SI.pStaticSampler &&
- GLProgramVariableBase::IsCompatibleWith(SI);
+ return Location == Sam.Location &&
+ SamplerType == Sam.SamplerType &&
+ GLResourceAttribs::IsCompatibleWith(Sam);
}
size_t GetHash()const
{
- return ComputeHash(Location, SamplerType, GLProgramVariableBase::GetHash());
+ return ComputeHash(Location, SamplerType, GLResourceAttribs::GetHash());
}
- const GLint Location;
- const GLenum SamplerType;
- RefCntAutoPtr<class SamplerGLImpl> pStaticSampler;
+ const GLint Location;
+ const GLenum SamplerType;
};
static_assert((sizeof(SamplerInfo) % sizeof(void*)) == 0, "sizeof(SamplerInfo) must be multiple of sizeof(void*)");
- struct ImageInfo final : GLProgramVariableBase
+ struct ImageInfo final : GLResourceAttribs
{
ImageInfo (const ImageInfo&) = delete;
ImageInfo& operator= (const ImageInfo&) = delete;
ImageInfo ( ImageInfo&&) = default;
ImageInfo& operator= ( ImageInfo&&) = delete;
- ImageInfo(IObject& _Owner,
- const Char* _Name,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- SHADER_RESOURCE_TYPE _ResourceType,
- Uint16 _VariableIndex,
- Uint32 _ArraySize,
- RefCntAutoPtr<IDeviceObject>* _pResources,
- GLint _Location,
- GLenum _ImageType) :
- GLProgramVariableBase(_Owner, _Name, _VariableType, _ResourceType, _VariableIndex, _ArraySize, _pResources),
- Location (_Location),
- ImageType (_ImageType)
+ 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}
+ {}
+
+ ImageInfo(const ImageInfo& Img,
+ StringPool& NamesPool)noexcept :
+ GLResourceAttribs{Img, NamesPool},
+ Location {Img.Location },
+ ImageType {Img.ImageType}
{}
- bool IsCompatibleWith(const ImageInfo& II)const
+ bool IsCompatibleWith(const ImageInfo& Img)const
{
- return Location == II.Location &&
- ImageType == II.ImageType &&
- GLProgramVariableBase::IsCompatibleWith(II);
+ return Location == Img.Location &&
+ ImageType == Img.ImageType &&
+ GLResourceAttribs::IsCompatibleWith(Img);
}
size_t GetHash()const
{
- return ComputeHash(Location, ImageType, GLProgramVariableBase::GetHash());
+ return ComputeHash(Location, ImageType, GLResourceAttribs::GetHash());
}
const GLint Location;
@@ -260,34 +247,38 @@ namespace Diligent
static_assert((sizeof(ImageInfo) % sizeof(void*)) == 0, "sizeof(ImageInfo) must be multiple of sizeof(void*)");
- struct StorageBlockInfo final : GLProgramVariableBase
+ struct StorageBlockInfo final : GLResourceAttribs
{
StorageBlockInfo (const StorageBlockInfo&) = delete;
StorageBlockInfo& operator= (const StorageBlockInfo&) = delete;
StorageBlockInfo ( StorageBlockInfo&&) = default;
StorageBlockInfo& operator= ( StorageBlockInfo&&) = delete;
- StorageBlockInfo(IObject& _Owner,
- const Char* _Name,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- SHADER_RESOURCE_TYPE _ResourceType,
- Uint16 _VariableIndex,
- Uint32 _ArraySize,
- RefCntAutoPtr<IDeviceObject>* _pResources,
- GLint _SBIndex) :
- GLProgramVariableBase(_Owner, _Name, _VariableType, _ResourceType, _VariableIndex, _ArraySize, _pResources),
- SBIndex(_SBIndex)
+ StorageBlockInfo(const Char* _Name,
+ SHADER_TYPE _ShaderStages,
+ SHADER_RESOURCE_TYPE _ResourceType,
+ Uint32 _Binding,
+ Uint32 _ArraySize,
+ GLint _SBIndex)noexcept :
+ GLResourceAttribs{_Name, _ShaderStages, _ResourceType, _Binding, _ArraySize},
+ SBIndex {_SBIndex}
{}
- bool IsCompatibleWith(const StorageBlockInfo& SBI)const
+ StorageBlockInfo(const StorageBlockInfo& SB,
+ StringPool& NamesPool)noexcept :
+ GLResourceAttribs{SB, NamesPool},
+ SBIndex {SB.SBIndex}
+ {}
+
+ bool IsCompatibleWith(const StorageBlockInfo& SB)const
{
- return SBIndex == SBI.SBIndex &&
- GLProgramVariableBase::IsCompatibleWith(SBI);
+ return SBIndex == SB.SBIndex &&
+ GLResourceAttribs::IsCompatibleWith(SB);
}
size_t GetHash()const
{
- return ComputeHash(SBIndex, GLProgramVariableBase::GetHash());
+ return ComputeHash(SBIndex, GLResourceAttribs::GetHash());
}
const GLint SBIndex;
@@ -349,24 +340,12 @@ namespace Diligent
return m_StorageBlocks[Index];
}
-
Uint32 GetVariableCount()const
{
return m_NumUniformBuffers + m_NumSamplers + m_NumImages + m_NumStorageBlocks;
}
- void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags);
-
-#ifdef VERIFY_RESOURCE_BINDINGS
- void dbgVerifyResourceBindings()const;
-#endif
-
- GLProgramVariableBase* GetVariable(const Char* Name);
- GLProgramVariableBase* GetVariable(Uint32 Index)
- {
- return const_cast<GLProgramVariableBase*>(const_cast<const GLProgramResources*>(this)->GetVariable(Index));
- }
- const GLProgramVariableBase* GetVariable(Uint32 Index)const;
+ ShaderResourceDesc GetResourceDesc(Uint32 Index)const;
bool IsCompatibleWith(const GLProgramResources& Res)const;
size_t GetHash()const;
@@ -380,27 +359,51 @@ namespace Diligent
void ProcessConstResources(THandleUB HandleUB,
THandleSampler HandleSampler,
THandleImg HandleImg,
- THandleSB HandleSB)const
+ THandleSB HandleSB,
+ const PipelineResourceLayoutDesc* pResourceLayout = nullptr,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr,
+ Uint32 NumAllowedTypes = 0)const
{
+ const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
+ auto CheckResourceType = [&](const char* Name)
+ {
+ if (pResourceLayout == nullptr)
+ return true;
+ else
+ {
+ auto VarType = GetShaderVariableType(m_ShaderStages, Name, *pResourceLayout);
+ return IsAllowedType(VarType, AllowedTypeBits);
+ }
+ };
+
for (Uint32 ub=0; ub < m_NumUniformBuffers; ++ub)
- HandleUB(GetUniformBuffer(ub));
+ {
+ const auto& UB = GetUniformBuffer(ub);
+ if (CheckResourceType(UB.Name))
+ HandleUB(UB);
+ }
for (Uint32 s=0; s < m_NumSamplers; ++s)
- HandleSampler(GetSampler(s));
+ {
+ const auto& Sam = GetSampler(s);
+ if (CheckResourceType(Sam.Name))
+ HandleSampler(Sam);
+ }
for (Uint32 img=0; img < m_NumImages; ++img)
- HandleImg(GetImage(img));
+ {
+ const auto& Img = GetImage(img);
+ if (CheckResourceType(Img.Name))
+ HandleImg(Img);
+ }
for (Uint32 sb=0; sb < m_NumStorageBlocks; ++sb)
- HandleSB(GetStorageBlock(sb));
+ {
+ const auto& SB = GetStorageBlock(sb);
+ if (CheckResourceType(SB.Name))
+ HandleSB(SB);
+ }
}
- private:
- void AllocateResources(IObject& Owner,
- std::vector<UniformBufferInfo>& UniformBlocks,
- std::vector<SamplerInfo>& Samplers,
- std::vector<ImageInfo>& Images,
- std::vector<StorageBlockInfo>& StorageBlocks,
- bool InitializeResourceCache);
template<typename THandleUB,
typename THandleSampler,
@@ -424,19 +427,38 @@ namespace Diligent
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<ImageInfo>& Images,
+ std::vector<StorageBlockInfo>& StorageBlocks);
+
+
// There could be more than one stage if using non-separable programs
SHADER_TYPE m_ShaderStages = SHADER_TYPE_UNKNOWN;
// Memory layout:
//
- // | Uniform buffers | Samplers | Images | Storage Blocks | Resource Cache | String Pool Data |
+ // | Uniform buffers | Samplers | Images | Storage Blocks | String Pool Data |
//
- UniformBufferInfo* m_UniformBuffers = nullptr;
- SamplerInfo* m_Samplers = nullptr;
- ImageInfo* m_Images = nullptr;
- StorageBlockInfo* m_StorageBlocks = nullptr;
- RefCntAutoPtr<IDeviceObject>* m_ResourceCache = nullptr;
+ UniformBufferInfo* m_UniformBuffers = nullptr;
+ SamplerInfo* m_Samplers = nullptr;
+ ImageInfo* m_Images = nullptr;
+ StorageBlockInfo* m_StorageBlocks = nullptr;
StringPool m_StringPool;
diff --git a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h
index 67980f15..baa96a90 100644
--- a/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h
+++ b/Graphics/GraphicsEngineOpenGL/include/PipelineStateGLImpl.h
@@ -27,10 +27,12 @@
#include "PipelineStateGL.h"
#include "PipelineStateBase.h"
#include "RenderDevice.h"
-#include "GLProgram.h"
#include "GLObjectWrapper.h"
#include "GLContext.h"
#include "RenderDeviceGLImpl.h"
+#include "GLProgramResources.h"
+#include "GLPipelineResourceLayout.h"
+#include "GLProgramResourceCache.h"
namespace Diligent
{
@@ -64,22 +66,33 @@ public:
virtual bool IsCompatibleWith(const IPipelineState* pPSO)const override final;
- GLProgram& GetGLProgram(){return m_GLProgram;}
- GLObjectWrappers::GLPipelineObj& GetGLProgramPipeline(GLContext::NativeGLContextType Context);
+ void CommitProgram(GLContextState& State);
+
+ void InitializeSRBResourceCache(GLProgramResourceCache& ResourceCache)const;
- GLProgramResources& GetStaticResources(Uint32 s)
- {
- return m_StaticResources[s];
- }
+ const GLPipelineResourceLayout& GetStaticResourceLayout()const {return m_StaticResourceLayout;}
private:
- void LinkGLProgram(bool bIsProgramPipelineSupported);
+ GLObjectWrappers::GLPipelineObj& GetGLProgramPipeline(GLContext::NativeGLContextType Context);
+ void InitStaticSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache)const;
+
+ std::vector<GLObjectWrappers::GLProgramObj> m_GLPrograms;
- GLProgram m_GLProgram;
ThreadingTools::LockFlag m_ProgPipelineLockFlag;
std::vector< std::pair<GLContext::NativeGLContextType, GLObjectWrappers::GLPipelineObj > > m_GLProgPipelines;
- std::vector<GLProgramResources> m_StaticResources;
- Int8 m_ResourceLayoutIndex[6] = {-1, -1, -1, -1, -1, -1};
+
+ GLPipelineResourceLayout m_ResourceLayout;
+ GLPipelineResourceLayout m_StaticResourceLayout;
+ GLProgramResourceCache m_StaticResourceCache;
+
+ std::vector<GLProgramResources> m_ProgramResources;
+
+ Uint32 m_TotalUniformBufferBindings = 0;
+ Uint32 m_TotalSamplerBindings = 0;
+ Uint32 m_TotalImageBindings = 0;
+ Uint32 m_TotalStorageBufferBindings = 0;
+
+ std::vector<RefCntAutoPtr<ISampler>> m_StaticSamplers;
};
}
diff --git a/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.h
index 32e2cd47..53a01a85 100644
--- a/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.h
+++ b/Graphics/GraphicsEngineOpenGL/include/ShaderGLImpl.h
@@ -28,8 +28,8 @@
#include "ShaderBase.h"
#include "RenderDevice.h"
#include "GLObjectWrapper.h"
-#include "GLProgram.h"
#include "RenderDeviceGLImpl.h"
+#include "GLProgramResources.h"
namespace Diligent
{
@@ -70,7 +70,10 @@ class ShaderGLImpl final : public ShaderBase<IShaderGL, RenderDeviceGLImpl>
public:
using TShaderBase = ShaderBase<IShaderGL, RenderDeviceGLImpl>;
- ShaderGLImpl( IReferenceCounters *pRefCounters, RenderDeviceGLImpl *pDeviceGL, const ShaderCreateInfo &ShaderCreateInfo, bool bIsDeviceInternal = false );
+ ShaderGLImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceGLImpl* pDeviceGL,
+ const ShaderCreateInfo& ShaderCreateInfo,
+ bool bIsDeviceInternal = false);
~ShaderGLImpl();
virtual void QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface)override final;
@@ -78,15 +81,11 @@ public:
virtual Uint32 GetResourceCount()const override final;
virtual ShaderResourceDesc GetResource(Uint32 Index)const override final;
- GLProgram& GetGlProgram(){return m_GlProgObj;}
+ static GLObjectWrappers::GLProgramObj LinkProgram(IShader** ppShaders, Uint32 NumShaders, bool IsSeparableProgram);
private:
-
- friend class PipelineStateGLImpl;
- friend class DeviceContextGLImpl;
-
- GLProgram m_GlProgObj; // Used if program pipeline supported
- GLObjectWrappers::GLShaderObj m_GLShaderObj; // Used if program pipelines are not supported
+ GLObjectWrappers::GLShaderObj m_GLShaderObj;
+ GLProgramResources m_Resources;
};
}
diff --git a/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h
index 56503cfb..962e3bc6 100644
--- a/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h
+++ b/Graphics/GraphicsEngineOpenGL/include/ShaderResourceBindingGLImpl.h
@@ -31,6 +31,8 @@
#include "ShaderResourceBindingBase.h"
#include "GLProgramResources.h"
#include "ShaderBase.h"
+#include "GLProgramResourceCache.h"
+#include "GLPipelineResourceLayout.h"
namespace Diligent
{
@@ -44,7 +46,10 @@ class ShaderResourceBindingGLImpl final : public ShaderResourceBindingBase<IShad
public:
using TBase = ShaderResourceBindingBase<IShaderResourceBindingGL>;
- ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters, PipelineStateGLImpl* pPSO);
+ ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters,
+ PipelineStateGLImpl* pPSO,
+ GLProgramResources* ProgramResources,
+ Uint32 NumPrograms);
~ShaderResourceBindingGLImpl();
virtual void QueryInterface( const INTERFACE_ID& IID, IObject** ppInterface )override final;
@@ -59,13 +64,12 @@ public:
virtual void InitializeStaticResources(const IPipelineState* pPipelineState)override final;
- GLProgramResources& GetResources(Uint32 Ind, PipelineStateGLImpl* pdbgPSO);
+ const GLProgramResourceCache& GetResourceCache(PipelineStateGLImpl* pdbgPSO);
private:
- bool IsUsingSeparatePrograms()const;
-
- Int8 m_ResourceIndex[6] = {-1, -1, -1, -1, -1, -1};
- std::vector<GLProgramResources> m_Resources;
+ GLPipelineResourceLayout m_ResourceLayout;
+ GLProgramResourceCache m_ResourceCache;
+ bool m_bIsStaticResourcesBound = false;
};
}
diff --git a/Graphics/GraphicsEngineOpenGL/include/pch.h b/Graphics/GraphicsEngineOpenGL/include/pch.h
index 0ef48b8d..260ae5ae 100644
--- a/Graphics/GraphicsEngineOpenGL/include/pch.h
+++ b/Graphics/GraphicsEngineOpenGL/include/pch.h
@@ -131,3 +131,9 @@
if( err != GL_NO_ERROR ) \
LogError<true>(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__, "\nGL Error Code: ", err); \
}
+
+#ifdef DEVELOPMENT
+# define DEV_CHECK_GL_ERROR CHECK_GL_ERROR
+#else
+# define DEV_CHECK_GL_ERROR(...) do{}while(false)
+#endif
diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp
index c04d54ea..dfb2acb3 100644
--- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp
@@ -353,336 +353,190 @@ namespace Diligent
void DeviceContextGLImpl::BindProgramResources(Uint32& NewMemoryBarriers, IShaderResourceBinding* pResBinding)
{
- auto* pRenderDeviceGL = m_pDevice.RawPtr<RenderDeviceGLImpl>();
if (!m_pPipelineState)
{
- LOG_ERROR("No pipeline state is bound");
+ LOG_ERROR_MESSAGE("No pipeline state is bound");
return;
}
+
+ if (pResBinding == nullptr)
+ return;
+
auto* pShaderResBindingGL = ValidatedCast<ShaderResourceBindingGLImpl>(pResBinding);
+ const auto& ResourceCache = pShaderResBindingGL->GetResourceCache(m_pPipelineState);
- const auto& DeviceCaps = pRenderDeviceGL->GetDeviceCaps();
- auto& Prog = m_pPipelineState->GetGLProgram();
- auto ProgramPipelineSupported = DeviceCaps.bSeparableProgramSupported;
+ VERIFY_EXPR(m_BoundWritableTextures.empty());
+ VERIFY_EXPR(m_BoundWritableBuffers.empty());
- // 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!!!
- // So make sure that glUseProgram(0) has been called if pipeline is in use
- m_ContextState.SetProgram(Prog);
- if (ProgramPipelineSupported)
+ for (Uint32 ub = 0; ub < ResourceCache.GetUBCount(); ++ub)
{
- VERIFY(Prog == 0, "Program must be null when program pipeline is used");
- auto& Pipeline = m_pPipelineState->GetGLProgramPipeline( m_ContextState.GetCurrentGLContext() );
- VERIFY(Pipeline != 0, "Program pipeline must not be null");
- m_ContextState.SetPipeline( Pipeline );
- }
- else
- {
- VERIFY(Prog != 0, "Program must not be null");
+ const auto& UB = ResourceCache.GetUB(ub);
+ if (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
+ m_ContextState);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, ub, pBufferGL->m_GlBuffer);
+ DEV_CHECK_GL_ERROR("Failed to bind uniform buffer to slot ", ub);
+ //glBindBufferRange(GL_UNIFORM_BUFFER, it->Index, pBufferGL->m_GlBuffer, 0, pBufferGL->GetDesc().uiSizeInBytes);
+ }
}
- Uint32 NumPrograms = ProgramPipelineSupported ? m_pPipelineState->GetNumShaders() : 1;
- GLuint UnifromBufferBindSlot = 0;
- GLuint StorageBufferBindSlot = 0;
- GLuint TextureBindSlot = 0;
- GLuint ImageBindSlot = 0;
- m_BoundWritableTextures.clear();
- m_BoundWritableBuffers.clear();
- for (Uint32 ProgNum = 0; ProgNum < NumPrograms; ++ProgNum)
+ for (Uint32 s = 0; s < ResourceCache.GetSamplerCount(); ++s)
{
- auto* pShaderGL = m_pPipelineState->GetShader<ShaderGLImpl>(ProgNum);
- auto& GLProgramObj = ProgramPipelineSupported ? pShaderGL->m_GlProgObj : Prog;
-
- GLProgramResources* pSRBResources = pShaderResBindingGL ? &pShaderResBindingGL->GetResources(ProgNum, m_pPipelineState) : nullptr;
-#ifdef VERIFY_RESOURCE_BINDINGS
- //GLProgramObj.dbgVerifyBindingCompleteness(pDynamicResources, m_pPipelineState);
-#endif
-
- for (int BindSRBResources = 0; BindSRBResources < (pShaderResBindingGL ? 2 : 1); ++BindSRBResources)
+ const auto& Sam = ResourceCache.GetSampler(s);
+ // We must check 'pTexture' first as 'pBuffer' is in union with 'pSampler'
+ if (Sam.pTexture != nullptr)
{
- GLProgramResources& ProgResources = BindSRBResources ? *pSRBResources : m_pPipelineState->GetStaticResources(ProgNum);
-
-#ifdef VERIFY_RESOURCE_BINDINGS
- ProgResources.dbgVerifyResourceBindings();
-#endif
-
- GLuint GLProgID = GLProgramObj;
- for (Uint32 ub = 0; ub < ProgResources.GetNumUniformBuffers(); ++ub)
+ 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());
+
+ pTextureGL->TextureMemoryBarrier(
+ 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
+ m_ContextState);
+
+ if (Sam.pSampler)
{
- auto& UB = ProgResources.GetUniformBuffer(ub);
- for(Uint32 ArrInd = 0; ArrInd < UB.ArraySize; ++ArrInd)
- {
- auto& Resource = UB.pResources[ArrInd];
- if (Resource)
- {
- auto* pBufferGL = Resource.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
- m_ContextState);
-
- glBindBufferBase(GL_UNIFORM_BUFFER, UnifromBufferBindSlot, pBufferGL->m_GlBuffer);
- CHECK_GL_ERROR("Failed to bind uniform buffer");
- //glBindBufferRange(GL_UNIFORM_BUFFER, it->Index, pBufferGL->m_GlBuffer, 0, pBufferGL->GetDesc().uiSizeInBytes);
-
- glUniformBlockBinding(GLProgID, UB.UBIndex + ArrInd, UnifromBufferBindSlot);
- CHECK_GL_ERROR("glUniformBlockBinding() failed");
-
- ++UnifromBufferBindSlot;
- }
- else
- {
-#define LOG_MISSING_BINDING(VarType, Res, ArrInd)\
- do{ \
- if(Res.ArraySize > 1) \
- LOG_ERROR_MESSAGE( "No ", VarType, " is bound to '", Res.Name, '[', ArrInd, "]' variable in shader '", pShaderGL->GetDesc().Name, "'" );\
- else \
- LOG_ERROR_MESSAGE( "No ", VarType, " is bound to '", Res.Name, "' variable in shader '", pShaderGL->GetDesc().Name, "'" );\
- }while(false)
-
- LOG_MISSING_BINDING("uniform buffer", UB, ArrInd);
- }
- }
+ m_ContextState.BindSampler(s, Sam.pSampler->GetHandle());
}
-
- for (Uint32 sam = 0; sam < ProgResources.GetNumSamplers(); ++sam)
+ else
{
- auto& Sam = ProgResources.GetSampler(sam);
- for (Uint32 ArrInd = 0; ArrInd < Sam.ArraySize; ++ArrInd)
- {
- auto& Resource = Sam.pResources[ArrInd];
- if (Resource)
- {
- if (Sam.SamplerType == GL_SAMPLER_BUFFER ||
- Sam.SamplerType == GL_INT_SAMPLER_BUFFER ||
- Sam.SamplerType == GL_UNSIGNED_INT_SAMPLER_BUFFER)
- {
- auto* pBufViewGL = Resource.RawPtr<BufferViewGLImpl>();
- auto* pBuffer = pBufViewGL->GetBuffer();
-
- m_ContextState.BindTexture(TextureBindSlot, GL_TEXTURE_BUFFER, pBufViewGL->GetTexBufferHandle());
- m_ContextState.BindSampler(TextureBindSlot, GLObjectWrappers::GLSamplerObj(false)); // Use default texture sampling parameters
-
- ValidatedCast<BufferGLImpl>(pBuffer)->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
- m_ContextState);
- }
- else
- {
- auto* pTexViewGL = Resource.RawPtr<TextureViewGLImpl>();
- m_ContextState.BindTexture(TextureBindSlot, pTexViewGL->GetBindTarget(), pTexViewGL->GetHandle());
-
- auto* pTexture = pTexViewGL->GetTexture();
- ValidatedCast<TextureBaseGL>(pTexture)->TextureMemoryBarrier(
- 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
- m_ContextState);
-
- SamplerGLImpl* pSamplerGL = nullptr;
- if (Sam.pStaticSampler)
- {
- pSamplerGL = Sam.pStaticSampler;
- }
- else
- {
- auto pSampler = pTexViewGL->GetSampler();
- pSamplerGL = ValidatedCast<SamplerGLImpl>(pSampler);
- }
-
- if (pSamplerGL)
- {
- m_ContextState.BindSampler(TextureBindSlot, pSamplerGL->GetHandle());
- }
- else
- {
- m_ContextState.BindSampler(TextureBindSlot, GLObjectWrappers::GLSamplerObj(false));
- }
- }
-
- // Texture is now bound to texture slot TextureIndex.
- // We now need to set the program uniform to use that slot
- if (ProgramPipelineSupported)
- {
- // glProgramUniform1i does not require program to be bound to the pipeline
- glProgramUniform1i(GLProgramObj, Sam.Location + ArrInd, TextureBindSlot);
- }
- else
- {
- // glUniform1i requires program to be bound to the pipeline
- glUniform1i(Sam.Location + ArrInd, TextureBindSlot);
- }
- CHECK_GL_ERROR("Failed to set binding point for sampler uniform '", Sam.Name, '\'');
-
- ++TextureBindSlot;
- }
- else
- {
- LOG_MISSING_BINDING("texture sampler", Sam, ArrInd);
- }
- }
+ m_ContextState.BindSampler(s, GLObjectWrappers::GLSamplerObj(false));
}
+ }
+ else if (Sam.pBuffer != nullptr)
+ {
+ auto* pBufViewGL = Sam.pView.RawPtr<BufferViewGLImpl>();
+ 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
+
+ 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
+ m_ContextState);
+ }
+ }
#if GL_ARB_shader_image_load_store
- for (Uint32 img = 0; img < ProgResources.GetNumImages(); ++img)
+ for (Uint32 img = 0; img < ResourceCache.GetImageCount(); ++img)
+ {
+ const auto& Img = ResourceCache.GetImage(img);
+ // We must check 'pTexture' first as 'pBuffer' is in union with 'pSampler'
+ if (Img.pTexture != nullptr)
+ {
+ auto* pTexViewGL = Img.pView.RawPtr<TextureViewGLImpl>();
+ auto* pTextureGL = ValidatedCast<TextureBaseGL>(Img.pTexture);
+ VERIFY_EXPR(pTextureGL == pTexViewGL->GetTexture());
+
+ const auto& ViewDesc = pTexViewGL->GetDesc();
+ VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, "Unexpected buffer view type" );
+
+ if (ViewDesc.AccessFlags & UAV_ACCESS_FLAG_WRITE)
{
- auto& Img = ProgResources.GetImage(img);
- for (Uint32 ArrInd = 0; ArrInd < Img.ArraySize; ++ArrInd)
- {
- auto& Resource = Img.pResources[ArrInd];
- if (Resource)
- {
- if (Img.ImageType == GL_IMAGE_BUFFER ||
- Img.ImageType == GL_INT_IMAGE_BUFFER ||
- Img.ImageType == GL_UNSIGNED_INT_IMAGE_BUFFER)
- {
- auto* pBuffViewGL = Resource.RawPtr<BufferViewGLImpl>();
- const auto& ViewDesc = pBuffViewGL->GetDesc();
- VERIFY( ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Unexpected buffer view type" );
-
- auto* pBufferGL = pBuffViewGL->GetBuffer<BufferGLImpl>();
- 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.
- m_ContextState);
-
- m_BoundWritableBuffers.push_back(pBufferGL);
-
- auto GlFormat = TypeToGLTexFormat(ViewDesc.Format.ValueType, ViewDesc.Format.NumComponents, ViewDesc.Format.IsNormalized);
- m_ContextState.BindImage(ImageBindSlot, pBuffViewGL, GL_READ_WRITE, GlFormat);
- }
- else
- {
- auto* pTexViewGL = Resource.RawPtr<TextureViewGLImpl>();
- const auto& ViewDesc = pTexViewGL->GetDesc();
- VERIFY( ViewDesc.ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, "Unexpected buffer view type" );
-
- if (ViewDesc.AccessFlags & UAV_ACCESS_FLAG_WRITE)
- {
- auto* pTexGL = pTexViewGL->GetTexture<TextureBaseGL>();
- pTexGL->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.
- m_ContextState);
- // We cannot set pending memory barriers here, because
- // if some texture is bound twice, the logic will fail
- m_BoundWritableTextures.push_back( pTexGL );
- }
-
- #ifdef _DEBUG
- // Check that the texure being bound has immutable storage
- {
- m_ContextState.BindTexture(-1, pTexViewGL->GetBindTarget(), pTexViewGL->GetHandle());
- GLint IsImmutable = 0;
- glGetTexParameteriv( pTexViewGL->GetBindTarget(), GL_TEXTURE_IMMUTABLE_FORMAT, &IsImmutable );
- CHECK_GL_ERROR( "glGetTexParameteriv() failed" );
- VERIFY( IsImmutable, "Only immutable textures can be bound to pipeline using glBindImageTexture()" );
- m_ContextState.BindTexture( -1, pTexViewGL->GetBindTarget(), GLObjectWrappers::GLTextureObj(false) );
- }
- #endif
- auto GlTexFormat = TexFormatToGLInternalTexFormat( ViewDesc.Format );
- // Note that if a format qulifier is specified in the shader, the format
- // must match it
-
- GLboolean Layered = ViewDesc.NumArraySlices > 1 && ViewDesc.FirstArraySlice == 0;
- // If "layered" is TRUE, the entire Mip level is bound. Layer parameter is ignored in this
- // case. If "layered" is FALSE, only the single layer identified by "layer" will
- // be bound. When "layered" is FALSE, the single bound layer is treated as a 2D texture.
- GLint Layer = ViewDesc.FirstArraySlice;
-
- auto GLAccess = AccessFlags2GLAccess(ViewDesc.AccessFlags);
- // WARNING: Texture being bound to the image unit must be complete
- // 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(ImageBindSlot, pTexViewGL, ViewDesc.MostDetailedMip, Layered, Layer, GLAccess, GlTexFormat);
- // Do not use binding points from reflection as they may not be initialized
- }
-
- // Image is now bound to binding slot ImageIndex.
- // We now need to set the program uniform to use that slot
- if (ProgramPipelineSupported)
- {
- // glProgramUniform1i does not require program to be bound to the pipeline
- glProgramUniform1i(GLProgramObj, Img.Location + ArrInd, ImageBindSlot);
- }
- else
- {
- // glUniform1i requires program to be bound to the pipeline
- glUniform1i(Img.Location + ArrInd, ImageBindSlot);
- }
- CHECK_GL_ERROR("Failed to set binding point for image uniform '", Img.Name, '\'');
-
- ++ImageBindSlot;
- }
- else
- {
- LOG_MISSING_BINDING("image", Img, ArrInd);
- }
- }
+ 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.
+ m_ContextState);
+ // We cannot set pending memory barriers here, because
+ // if some texture is bound twice, the logic will fail
+ m_BoundWritableTextures.push_back( pTextureGL );
}
-#endif
-#if GL_ARB_shader_storage_buffer_object
- for (Uint32 sb=0; sb < ProgResources.GetNumStorageBlocks(); ++sb)
+#ifdef _DEBUG
+ // Check that the texure being bound has immutable storage
{
- auto& SB = ProgResources.GetStorageBlock(sb);
- for (Uint32 ArrInd = 0; ArrInd < SB.ArraySize; ++ArrInd)
- {
- auto& Resource = SB.pResources[ArrInd];
- if (Resource)
- {
- auto* pBufferViewGL = Resource.RawPtr<BufferViewGLImpl>();
- const auto& ViewDesc = pBufferViewGL->GetDesc();
- VERIFY( ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS || ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Unexpected buffer view type" );
-
- auto* pBufferGL = pBufferViewGL->GetBuffer<BufferGLImpl>();
- pBufferGL->BufferMemoryBarrier(
- GL_SHADER_STORAGE_BARRIER_BIT,// Accesses to shader storage blocks after the barrier
- // will reflect writes prior to the barrier
- m_ContextState);
-
- glBindBufferRange(GL_SHADER_STORAGE_BUFFER, StorageBufferBindSlot, pBufferGL->m_GlBuffer, ViewDesc.ByteOffset, ViewDesc.ByteWidth);
- CHECK_GL_ERROR("Failed to bind shader storage buffer");
-
- if (glShaderStorageBlockBinding)
- {
- glShaderStorageBlockBinding(GLProgID, SB.SBIndex + ArrInd, StorageBufferBindSlot);
- CHECK_GL_ERROR("glShaderStorageBlockBinding() failed");
- }
- else
- {
- LOG_WARNING_MESSAGE_ONCE("glShaderStorageBlockBinding is not available on this device and "
- "the engine is unable to automatically assign shader storage block bindindg points. "
- "To make shader storage blocks work properly, all binding points must be explicitly assigned "
- "in the shader starting from 0 and proceeding in the storage block declaration order. "
- "Note that the binding points are properly assigned by HLSL->GLSL converter.");
- }
-
- ++StorageBufferBindSlot;
-
- if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS)
- m_BoundWritableBuffers.push_back(pBufferGL);
- }
- else
- {
- LOG_MISSING_BINDING("shader storage block", SB, ArrInd);
- }
- }
+ m_ContextState.BindTexture(-1, pTexViewGL->GetBindTarget(), pTexViewGL->GetHandle());
+ GLint IsImmutable = 0;
+ glGetTexParameteriv( pTexViewGL->GetBindTarget(), GL_TEXTURE_IMMUTABLE_FORMAT, &IsImmutable );
+ CHECK_GL_ERROR( "glGetTexParameteriv() failed" );
+ VERIFY( IsImmutable, "Only immutable textures can be bound to pipeline using glBindImageTexture()" );
+ m_ContextState.BindTexture( -1, pTexViewGL->GetBindTarget(), GLObjectWrappers::GLTextureObj(false) );
}
#endif
+ auto GlTexFormat = TexFormatToGLInternalTexFormat( ViewDesc.Format );
+ // Note that if a format qulifier is specified in the shader, the format
+ // must match it
+
+ GLboolean Layered = ViewDesc.NumArraySlices > 1 && ViewDesc.FirstArraySlice == 0;
+ // If "layered" is TRUE, the entire Mip level is bound. Layer parameter is ignored in this
+ // case. If "layered" is FALSE, only the single layer identified by "layer" will
+ // be bound. When "layered" is FALSE, the single bound layer is treated as a 2D texture.
+ GLint Layer = ViewDesc.FirstArraySlice;
+
+ auto GLAccess = AccessFlags2GLAccess(ViewDesc.AccessFlags);
+ // WARNING: Texture being bound to the image unit must be complete
+ // 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);
+ // Do not use binding points from reflection as they may not be initialized
+ }
+ else if (Img.pBuffer != nullptr)
+ {
+ auto* pBuffViewGL = Img.pView.RawPtr<BufferViewGLImpl>();
+ auto* pBufferGL = ValidatedCast<BufferGLImpl>(Img.pBuffer);
+ VERIFY_EXPR(pBufferGL == pBuffViewGL->GetBuffer());
+
+ const auto& ViewDesc = pBuffViewGL->GetDesc();
+ 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.
+ 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);
}
}
+#endif
+
+
+#if GL_ARB_shader_storage_buffer_object
+ for (Uint32 ssbo = 0; ssbo < ResourceCache.GetSSBOCount(); ++ssbo)
+ {
+ const auto& SSBO = ResourceCache.GetSSBO(ssbo);
+ if (SSBO.pBufferView)
+ {
+ auto* pBufferViewGL = SSBO.pBufferView.RawPtr<BufferViewGLImpl>();
+ const auto& ViewDesc = pBufferViewGL->GetDesc();
+ VERIFY( ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS || ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Unexpected buffer view type" );
+
+ auto* pBufferGL = pBufferViewGL->GetBuffer<BufferGLImpl>();
+ pBufferGL->BufferMemoryBarrier(
+ GL_SHADER_STORAGE_BARRIER_BIT,// Accesses to shader storage blocks after the barrier
+ // will reflect writes prior to the barrier
+ m_ContextState);
+
+ glBindBufferRange(GL_SHADER_STORAGE_BUFFER, ssbo, pBufferGL->m_GlBuffer, ViewDesc.ByteOffset, ViewDesc.ByteWidth);
+ DEV_CHECK_GL_ERROR("Failed to bind shader storage buffer");
+
+ if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS)
+ m_BoundWritableBuffers.push_back(pBufferGL);
+ }
+ }
+#endif
+
#if GL_ARB_shader_image_load_store
// Go through the list of textures bound as AUVs and set the required memory barriers
@@ -714,6 +568,7 @@ namespace Diligent
// Set new required barriers for the time when texture is used next time
pWritableTex->SetPendingMemoryBarriers(TextureMemBarriers);
}
+ m_BoundWritableTextures.clear();
for (auto* pWritableBuff : m_BoundWritableBuffers)
{
@@ -732,6 +587,7 @@ namespace Diligent
// Set new required barriers for the time when buffer is used next time
pWritableBuff->SetPendingMemoryBarriers( BufferMemoryBarriers );
}
+ m_BoundWritableBuffers.clear();
#endif
}
@@ -745,6 +601,8 @@ namespace Diligent
DvpVerifyRenderTargets();
#endif
+ m_pPipelineState->CommitProgram(m_ContextState);
+
auto* pRenderDeviceGL = m_pDevice.RawPtr<RenderDeviceGLImpl>();
auto CurrNativeGLContext = pRenderDeviceGL->m_GLContext.GetCurrentNativeGLContext();
const auto& PipelineDesc = m_pPipelineState->GetDesc().GraphicsPipeline;
@@ -829,7 +687,7 @@ namespace Diligent
//} DrawElementsIndirectCommand;
glDrawElementsIndirect( GlTopology, IndexType, reinterpret_cast<const void*>( static_cast<size_t>(drawAttribs.IndirectDrawArgsOffset) ) );
// Note that on GLES 3.1, baseInstance is present but reserved and must be zero
- CHECK_GL_ERROR( "glDrawElementsIndirect() failed" );
+ DEV_CHECK_GL_ERROR( "glDrawElementsIndirect() failed" );
}
else
{
@@ -841,12 +699,12 @@ namespace Diligent
//} DrawArraysIndirectCommand;
glDrawArraysIndirect( GlTopology, reinterpret_cast<const void*>( static_cast<size_t>(drawAttribs.IndirectDrawArgsOffset) ) );
// Note that on GLES 3.1, baseInstance is present but reserved and must be zero
- CHECK_GL_ERROR( "glDrawArraysIndirect() failed" );
+ DEV_CHECK_GL_ERROR( "glDrawArraysIndirect() failed" );
}
glBindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 );
#else
- UNSUPPORTED("Indirect rendering is not supported");
+ LOG_ERROR_MESSAGE("Indirect rendering is not supported");
#endif
}
else
@@ -890,7 +748,7 @@ namespace Diligent
else
glDrawArrays(GlTopology, drawAttribs.StartVertexLocation, drawAttribs.NumVertices);
}
- CHECK_GL_ERROR( "OpenGL draw command failed" );
+ DEV_CHECK_GL_ERROR( "OpenGL draw command failed" );
}
// IMPORTANT: new pending memory barriers in the context must be set
@@ -909,6 +767,8 @@ namespace Diligent
#endif
#if GL_ARB_compute_shader
+ m_pPipelineState->CommitProgram(m_ContextState);
+
if (DispatchAttrs.pIndirectDispatchAttribs)
{
CHECK_DYNAMIC_TYPE( BufferGLImpl, DispatchAttrs.pIndirectDispatchAttribs );
diff --git a/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp b/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp
index 4d0b2bad..e7886e8d 100644
--- a/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/GLContextState.cpp
@@ -80,7 +80,7 @@ namespace Diligent
glBindVertexArray( 0 );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
- CHECK_GL_ERROR( "Failed to reset GL context state" );
+ DEV_CHECK_GL_ERROR( "Failed to reset GL context state" );
m_GLProgId = -1;
m_GLPipelineId = -1;
@@ -132,7 +132,7 @@ namespace Diligent
if( UpdateBoundObject( m_GLProgId, GLProgram, GLProgHandle ) )
{
glUseProgram( GLProgHandle );
- CHECK_GL_ERROR( "Failed to set GL program" );
+ DEV_CHECK_GL_ERROR( "Failed to set GL program" );
}
}
@@ -142,7 +142,7 @@ namespace Diligent
if( UpdateBoundObject( m_GLPipelineId, GLPipeline, GLPipelineHandle ) )
{
glBindProgramPipeline( GLPipelineHandle );
- CHECK_GL_ERROR( "Failed to bind program pipeline" );
+ DEV_CHECK_GL_ERROR( "Failed to bind program pipeline" );
}
}
@@ -152,7 +152,7 @@ namespace Diligent
if( UpdateBoundObject( m_VAOId, VAO, VAOHandle ) )
{
glBindVertexArray( VAOHandle );
- CHECK_GL_ERROR( "Failed to set VAO" );
+ DEV_CHECK_GL_ERROR( "Failed to set VAO" );
}
}
@@ -169,9 +169,9 @@ namespace Diligent
// level is NOT level_base, the texture MUST BE MIPMAP COMPLETE
// If image is part of a cubemap texture, the texture must also be mipmap cube complete.
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, FBOHandle );
- CHECK_GL_ERROR( "Failed to bind FBO as draw framebuffer" );
+ DEV_CHECK_GL_ERROR( "Failed to bind FBO as draw framebuffer" );
glBindFramebuffer( GL_READ_FRAMEBUFFER, FBOHandle );
- CHECK_GL_ERROR( "Failed to bind FBO as read framebuffer" );
+ DEV_CHECK_GL_ERROR( "Failed to bind FBO as read framebuffer" );
}
}
@@ -195,7 +195,7 @@ namespace Diligent
if( m_iActiveTexture != Index )
{
glActiveTexture( GL_TEXTURE0 + Index );
- CHECK_GL_ERROR( "Failed to activate texture slot ", Index );
+ DEV_CHECK_GL_ERROR( "Failed to activate texture slot ", Index );
m_iActiveTexture = Index;
}
}
@@ -215,7 +215,7 @@ namespace Diligent
if( UpdateBoundObjectsArr( m_BoundTextures, Index, Tex, GLTexHandle ) )
{
glBindTexture( BindTarget, GLTexHandle );
- CHECK_GL_ERROR( "Failed to bind texture to slot ", Index );
+ DEV_CHECK_GL_ERROR( "Failed to bind texture to slot ", Index );
}
}
@@ -225,7 +225,7 @@ namespace Diligent
if( UpdateBoundObjectsArr( m_BoundSamplers, Index, GLSampler, GLSamplerHandle ) )
{
glBindSampler( Index, GLSamplerHandle );
- CHECK_GL_ERROR( "Failed to bind sampler to slot ", Index );
+ DEV_CHECK_GL_ERROR( "Failed to bind sampler to slot ", Index );
}
}
@@ -253,7 +253,7 @@ namespace Diligent
m_BoundImages[Index] = NewImageInfo;
GLint GLTexHandle = pTexView->GetHandle();
glBindImageTexture( Index, GLTexHandle, MipLevel, IsLayered, Layer, Access, Format );
- CHECK_GL_ERROR( "glBindImageTexture() failed" );
+ DEV_CHECK_GL_ERROR( "glBindImageTexture() failed" );
}
#else
UNSUPPORTED("GL_ARB_shader_image_load_store is not supported");
@@ -278,7 +278,7 @@ namespace Diligent
m_BoundImages[Index] = NewImageInfo;
GLint GLBuffHandle = pBuffView->GetTexBufferHandle();
glBindImageTexture( Index, GLBuffHandle, 0, GL_FALSE, 0, Access, Format );
- CHECK_GL_ERROR( "glBindImageTexture() failed" );
+ DEV_CHECK_GL_ERROR( "glBindImageTexture() failed" );
}
#else
UNSUPPORTED("GL_ARB_shader_image_load_store is not supported");
@@ -322,7 +322,7 @@ namespace Diligent
if( RequiredBarriers )
{
glMemoryBarrier( RequiredBarriers );
- CHECK_GL_ERROR( "glMemoryBarrier() failed" );
+ DEV_CHECK_GL_ERROR( "glMemoryBarrier() failed" );
m_PendingMemoryBarriers &= ~RequiredBarriers;
}
@@ -346,12 +346,12 @@ namespace Diligent
if( bEnable )
{
glEnable( GL_DEPTH_TEST );
- CHECK_GL_ERROR( "Failed to enable detph test" );
+ DEV_CHECK_GL_ERROR( "Failed to enable detph test" );
}
else
{
glDisable( GL_DEPTH_TEST );
- CHECK_GL_ERROR( "Failed to disable detph test" );
+ DEV_CHECK_GL_ERROR( "Failed to disable detph test" );
}
m_DSState.m_DepthEnableState = bEnable;
}
@@ -363,7 +363,7 @@ namespace Diligent
{
// If mask is non-zero, the depth buffer is enabled for writing; otherwise, it is disabled.
glDepthMask( bEnable ? 1 : 0 );
- CHECK_GL_ERROR( "Failed to enale/disable depth writes" );
+ DEV_CHECK_GL_ERROR( "Failed to enale/disable depth writes" );
m_DSState.m_DepthWritesEnableState = bEnable;
}
}
@@ -374,7 +374,7 @@ namespace Diligent
{
auto GlCmpFunc = CompareFuncToGLCompareFunc( CmpFunc );
glDepthFunc( GlCmpFunc );
- CHECK_GL_ERROR( "Failed to set GL comparison function" );
+ DEV_CHECK_GL_ERROR( "Failed to set GL comparison function" );
m_DSState.m_DepthCmpFunc = CmpFunc;
}
}
@@ -386,12 +386,12 @@ namespace Diligent
if( bEnable )
{
glEnable( GL_STENCIL_TEST );
- CHECK_GL_ERROR( "Failed to enable stencil test" );
+ DEV_CHECK_GL_ERROR( "Failed to enable stencil test" );
}
else
{
glDisable( GL_STENCIL_TEST );
- CHECK_GL_ERROR( "Failed to disable stencil test" );
+ DEV_CHECK_GL_ERROR( "Failed to disable stencil test" );
}
m_DSState.m_StencilTestEnableState = bEnable;
}
@@ -411,7 +411,7 @@ namespace Diligent
auto& FaceStencilOp = m_DSState.m_StencilOpState[Face == GL_FRONT ? 0 : 1];
auto GlStencilFunc = CompareFuncToGLCompareFunc( FaceStencilOp.Func );
glStencilFuncSeparate( Face, GlStencilFunc, Ref, FaceStencilOp.Mask );
- CHECK_GL_ERROR( "Failed to set stencil function" );
+ DEV_CHECK_GL_ERROR( "Failed to set stencil function" );
}
void GLContextState::SetStencilFunc( GLenum Face, COMPARISON_FUNCTION Func, Int32 Ref, Uint32 Mask )
@@ -441,7 +441,7 @@ namespace Diligent
auto dppass = StencilOp2GlStencilOp( StencilPassOp );
glStencilOpSeparate( Face, glsfail, dpfail, dppass );
- CHECK_GL_ERROR( "Failed to set stencil operation" );
+ DEV_CHECK_GL_ERROR( "Failed to set stencil operation" );
FaceStencilOp.StencilFailOp = StencilFailOp;
FaceStencilOp.StencilDepthFailOp = StencilDepthFailOp;
@@ -459,7 +459,7 @@ namespace Diligent
{
auto PolygonMode = FillMode == FILL_MODE_WIREFRAME ? GL_LINE : GL_FILL;
glPolygonMode( GL_FRONT_AND_BACK, PolygonMode );
- CHECK_GL_ERROR( "Failed to set polygon mode" );
+ DEV_CHECK_GL_ERROR( "Failed to set polygon mode" );
}
else
{
@@ -484,16 +484,16 @@ namespace Diligent
if( CullMode == CULL_MODE_NONE )
{
glDisable( GL_CULL_FACE );
- CHECK_GL_ERROR( "Failed to disable face culling" );
+ DEV_CHECK_GL_ERROR( "Failed to disable face culling" );
}
else
{
VERIFY( CullMode == CULL_MODE_FRONT || CullMode == CULL_MODE_BACK, "Unexpected cull mode" );
glEnable( GL_CULL_FACE );
- CHECK_GL_ERROR( "Failed to enable face culling" );
+ DEV_CHECK_GL_ERROR( "Failed to enable face culling" );
auto CullFace = CullMode == CULL_MODE_BACK ? GL_BACK : GL_FRONT;
glCullFace( CullFace );
- CHECK_GL_ERROR( "Failed to set cull face" );
+ DEV_CHECK_GL_ERROR( "Failed to set cull face" );
}
m_RSState.CullMode = CullMode;
@@ -506,7 +506,7 @@ namespace Diligent
{
auto FrontFace = FrontCounterClockwise ? GL_CCW : GL_CW;
glFrontFace( FrontFace );
- CHECK_GL_ERROR( "Failed to set front face" );
+ DEV_CHECK_GL_ERROR( "Failed to set front face" );
m_RSState.FrontCounterClockwise = FrontCounterClockwise;
}
}
@@ -519,16 +519,16 @@ namespace Diligent
if( fDepthBias != 0 || fSlopeScaledDepthBias != 0 )
{
glEnable( GL_POLYGON_OFFSET_FILL );
- CHECK_GL_ERROR( "Failed to enable polygon offset fill" );
+ DEV_CHECK_GL_ERROR( "Failed to enable polygon offset fill" );
}
else
{
glDisable( GL_POLYGON_OFFSET_FILL );
- CHECK_GL_ERROR( "Failed to disable polygon offset fill" );
+ DEV_CHECK_GL_ERROR( "Failed to disable polygon offset fill" );
}
glPolygonOffset( fSlopeScaledDepthBias, fDepthBias );
- CHECK_GL_ERROR( "Failed to set polygon offset" );
+ DEV_CHECK_GL_ERROR( "Failed to set polygon offset" );
m_RSState.fDepthBias = fDepthBias;
m_RSState.fSlopeScaledDepthBias = fSlopeScaledDepthBias;
@@ -550,7 +550,7 @@ namespace Diligent
if( GL_DEPTH_CLAMP )
{
glEnable( GL_DEPTH_CLAMP );
- CHECK_GL_ERROR( "Failed to enable depth clamp" );
+ DEV_CHECK_GL_ERROR( "Failed to enable depth clamp" );
}
}
else
@@ -558,7 +558,7 @@ namespace Diligent
if( GL_DEPTH_CLAMP )
{
glDisable( GL_DEPTH_CLAMP );
- CHECK_GL_ERROR( "Failed to disable depth clamp" );
+ DEV_CHECK_GL_ERROR( "Failed to disable depth clamp" );
}
else
{
@@ -577,12 +577,12 @@ namespace Diligent
if( bEnableScissorTest )
{
glEnable( GL_SCISSOR_TEST );
- CHECK_GL_ERROR( "Failed to enable scissor test" );
+ DEV_CHECK_GL_ERROR( "Failed to enable scissor test" );
}
else
{
glDisable( GL_SCISSOR_TEST );
- CHECK_GL_ERROR( "Failed to disable scissor clamp" );
+ DEV_CHECK_GL_ERROR( "Failed to disable scissor clamp" );
}
m_RSState.ScissorTestEnable = bEnableScissorTest;
@@ -592,7 +592,7 @@ namespace Diligent
void GLContextState::SetBlendFactors(const float *BlendFactors)
{
glBlendColor( BlendFactors[0], BlendFactors[1], BlendFactors[2], BlendFactors[3] );
- CHECK_GL_ERROR( "Failed to set blend color" );
+ DEV_CHECK_GL_ERROR( "Failed to set blend color" );
}
void GLContextState::SetBlendState( const BlendStateDesc &BSDsc, Uint32 SampleMask )
@@ -629,17 +629,17 @@ namespace Diligent
{
// Sets the blend enable flag for ALL color buffers.
glEnable( GL_BLEND );
- CHECK_GL_ERROR( "Failed to enable alpha blending" );
+ DEV_CHECK_GL_ERROR( "Failed to enable alpha blending" );
if( BSDsc.AlphaToCoverageEnable )
{
glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE );
- CHECK_GL_ERROR( "Failed to enable alpha to coverage" );
+ DEV_CHECK_GL_ERROR( "Failed to enable alpha to coverage" );
}
else
{
glDisable( GL_SAMPLE_ALPHA_TO_COVERAGE );
- CHECK_GL_ERROR( "Failed to disable alpha to coverage" );
+ DEV_CHECK_GL_ERROR( "Failed to disable alpha to coverage" );
}
if( BSDsc.IndependentBlendEnable )
@@ -658,23 +658,23 @@ namespace Diligent
if( RT.BlendEnable )
{
glEnablei( GL_BLEND, i );
- CHECK_GL_ERROR( "Failed to enable alpha blending" );
+ DEV_CHECK_GL_ERROR( "Failed to enable alpha blending" );
auto srcFactorRGB = BlendFactor2GLBlend( RT.SrcBlend );
auto dstFactorRGB = BlendFactor2GLBlend( RT.DestBlend );
auto srcFactorAlpha = BlendFactor2GLBlend( RT.SrcBlendAlpha );
auto dstFactorAlpha = BlendFactor2GLBlend( RT.DestBlendAlpha );
glBlendFuncSeparatei( i, srcFactorRGB, dstFactorRGB, srcFactorAlpha, dstFactorAlpha );
- CHECK_GL_ERROR( "Failed to set separate blending factors" );
+ DEV_CHECK_GL_ERROR( "Failed to set separate blending factors" );
auto modeRGB = BlendOperation2GLBlendOp( RT.BlendOp );
auto modeAlpha = BlendOperation2GLBlendOp( RT.BlendOpAlpha );
glBlendEquationSeparatei( i, modeRGB, modeAlpha );
- CHECK_GL_ERROR( "Failed to set separate blending equations" );
+ DEV_CHECK_GL_ERROR( "Failed to set separate blending equations" );
}
else
{
glDisablei( GL_BLEND, i );
- CHECK_GL_ERROR( "Failed to disable alpha blending" );
+ DEV_CHECK_GL_ERROR( "Failed to disable alpha blending" );
}
}
}
@@ -686,19 +686,19 @@ namespace Diligent
auto srcFactorAlpha = BlendFactor2GLBlend( RT0.SrcBlendAlpha );
auto dstFactorAlpha = BlendFactor2GLBlend( RT0.DestBlendAlpha );
glBlendFuncSeparate( srcFactorRGB, dstFactorRGB, srcFactorAlpha, dstFactorAlpha );
- CHECK_GL_ERROR( "Failed to set blending factors" );
+ DEV_CHECK_GL_ERROR( "Failed to set blending factors" );
auto modeRGB = BlendOperation2GLBlendOp( RT0.BlendOp );
auto modeAlpha = BlendOperation2GLBlendOp( RT0.BlendOpAlpha );
glBlendEquationSeparate( modeRGB, modeAlpha );
- CHECK_GL_ERROR( "Failed to set blending equations" );
+ DEV_CHECK_GL_ERROR( "Failed to set blending equations" );
}
}
else
{
// Sets the blend disable flag for ALL color buffers.
glDisable( GL_BLEND );
- CHECK_GL_ERROR( "Failed to disable alpha blending" );
+ DEV_CHECK_GL_ERROR( "Failed to disable alpha blending" );
}
}
@@ -724,7 +724,7 @@ namespace Diligent
(WriteMask & COLOR_MASK_GREEN) ? GL_TRUE : GL_FALSE,
(WriteMask & COLOR_MASK_BLUE) ? GL_TRUE : GL_FALSE,
(WriteMask & COLOR_MASK_ALPHA) ? GL_TRUE : GL_FALSE );
- CHECK_GL_ERROR( "Failed to set GL color mask" );
+ DEV_CHECK_GL_ERROR( "Failed to set GL color mask" );
m_ColorWriteMasks[RTIndex] = WriteMask;
}
@@ -735,7 +735,7 @@ namespace Diligent
(WriteMask & COLOR_MASK_GREEN) ? GL_TRUE : GL_FALSE,
(WriteMask & COLOR_MASK_BLUE) ? GL_TRUE : GL_FALSE,
(WriteMask & COLOR_MASK_ALPHA) ? GL_TRUE : GL_FALSE );
- CHECK_GL_ERROR( "Failed to set GL color mask" );
+ DEV_CHECK_GL_ERROR( "Failed to set GL color mask" );
for( int rt = 0; rt < _countof( m_ColorWriteMasks ); ++rt )
m_ColorWriteMasks[rt] = WriteMask;
@@ -759,7 +759,7 @@ namespace Diligent
{
m_NumPatchVertices = NumVertices;
glPatchParameteri(GL_PATCH_VERTICES, static_cast<GLint>(NumVertices));
- CHECK_GL_ERROR( "Failed to set the number of patch vertices" );
+ DEV_CHECK_GL_ERROR( "Failed to set the number of patch vertices" );
}
#endif
}
diff --git a/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp b/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp
new file mode 100644
index 00000000..ba1574b8
--- /dev/null
+++ b/Graphics/GraphicsEngineOpenGL/src/GLPipelineResourceLayout.cpp
@@ -0,0 +1,880 @@
+/* Copyright 2019 Diligent Graphics LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include <array>
+#include "GLPipelineResourceLayout.h"
+#include "Align.h"
+#include "PlatformMisc.h"
+#include "ShaderBase.h"
+
+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);
+ }
+
+ size_t RequiredSize = Counters.NumUBs * sizeof(UniformBuffBindInfo) +
+ Counters.NumSamplers * sizeof(SamplerBindInfo) +
+ Counters.NumImages * sizeof(ImageBindInfo) +
+ Counters.NumStorageBlocks * sizeof(StorageBufferBindInfo) +
+ NumPrograms * sizeof(GLProgramResources::ResourceCounters);
+ return RequiredSize;
+}
+
+void GLPipelineResourceLayout::Initialize(GLProgramResources* ProgramResources,
+ Uint32 NumPrograms,
+ 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, ")");
+ auto Offset = static_cast<OffsetType>(CurrentOffset);
+ CurrentOffset += NumBytes;
+ return Offset;
+ };
+
+ 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);
+ 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));
+
+ 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);
+ }
+
+ VERIFY_EXPR(Counters.NumUBs == GetNumUBs() );
+ VERIFY_EXPR(Counters.NumSamplers == GetNumSamplers() );
+ VERIFY_EXPR(Counters.NumImages == GetNumImages() );
+ VERIFY_EXPR(Counters.NumStorageBlocks == GetNumStorageBuffers());
+
+ // Current resource index for every resource type
+ GLProgramResources::ResourceCounters VarCounters = {};
+
+ Uint32 UniformBindingSlots = 0;
+ Uint32 SamplerBindingSlots = 0;
+ Uint32 ImageBindingSlots = 0;
+ Uint32 SSBOBindingSlots = 0;
+
+#ifdef _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 StaticSamplerIdx = -1;
+ if (Sam.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV)
+ {
+ StaticSamplerIdx = FindStaticSampler(ResourceLayout.StaticSamplers, ResourceLayout.NumStaticSamplers, ShaderStages,
+ Sam.Name, nullptr);
+ }
+ auto* pSamVar = new (&GetResource<SamplerBindInfo>(VarCounters.NumSamplers++)) SamplerBindInfo
+ {
+ Sam,
+ *this,
+ VarType,
+ StaticSamplerIdx
+ };
+ 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 = GetShaderTypeIndex(Stage);
+ m_ProgramIndex[ShaderInd] = static_cast<Int8>(prog);
+ ShaderStages = static_cast<SHADER_TYPE>(Uint32{ShaderStages} & ~Stage);
+ }
+ }
+
+ 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");
+
+ 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()
+{
+ HandleResources(
+ [&](UniformBuffBindInfo& ub)
+ {
+ ub.~UniformBuffBindInfo();
+ },
+
+ [&](SamplerBindInfo& sam)
+ {
+ sam.~SamplerBindInfo();
+ },
+
+ [&](ImageBindInfo& img)
+ {
+ img.~ImageBindInfo();
+ },
+
+ [&](StorageBufferBindInfo& ssbo)
+ {
+ ssbo.~StorageBufferBindInfo();
+ }
+ );
+}
+
+#define LOG_RESOURCE_BINDING_ERROR(ResType, pResource, Attribs, ArrayInd, ...)\
+do{ \
+ const auto* ResName = pResource->GetDesc().Name; \
+ if (Attribs.ArraySize > 1) \
+ LOG_ERROR_MESSAGE( "Failed to bind ", ResType, " '", ResName, "' to variable '", Attribs.Name,\
+ "[", ArrayInd, "]'. ", __VA_ARGS__ ); \
+ else \
+ LOG_ERROR_MESSAGE( "Failed to bind ", ResType, " '", ResName, "' to variable '", Attribs.Name,\
+ "'. ", __VA_ARGS__ ); \
+}while(false)
+
+
+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 DEVELOPMENT
+ if (pBuffer && !pBuffGLImpl)
+ LOG_RESOURCE_BINDING_ERROR("buffer", pBuffer, m_Attribs, ArrayIndex, "Incorrect resource type: buffer is expected.");
+
+ if (pBuffGLImpl && (pBuffGLImpl->GetDesc().BindFlags & BIND_UNIFORM_BUFFER) == 0)
+ {
+ LOG_RESOURCE_BINDING_ERROR("buffer", pBuffer, m_Attribs, ArrayIndex, "Buffer was not created with BIND_UNIFORM_BUFFER flag.");
+ pBuffGLImpl.Release();
+ }
+
+ if (GetType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ const auto& CachedUB = const_cast<const GLProgramResourceCache&>(ResourceCache).GetUB(m_Attribs.Binding + ArrayIndex);
+ if (CachedUB.pBuffer != nullptr && CachedUB.pBuffer != pBuffGLImpl)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(GetType());
+ LOG_ERROR_MESSAGE( "Non-null uniform buffer is already bound to ", VarTypeStr, " shader variable '", m_Attribs.GetPrintName(ArrayIndex), "'. Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic." );
+ }
+ }
+#endif
+
+ ResourceCache.SetUniformBuffer(m_Attribs.Binding + ArrayIndex, std::move(pBuffGLImpl) );
+}
+
+
+
+#ifdef DEVELOPMENT
+template<typename TResourceViewType, ///< Type of the view (ITextureViewGL or IBufferViewGL)
+ typename TViewTypeEnum> ///< Type of the expected view enum
+bool dbgVerifyViewType( const char* ViewTypeName,
+ TResourceViewType pViewGL,
+ const GLProgramResources::GLResourceAttribs& Attribs,
+ Uint32 ArrayIndex,
+ TViewTypeEnum dbgExpectedViewType)
+{
+ const auto& ViewDesc = pViewGL->GetDesc();
+ auto ViewType = ViewDesc.ViewType;
+ if (ViewType == dbgExpectedViewType)
+ {
+ return true;
+ }
+ else
+ {
+ const auto* ExpectedViewTypeName = GetViewTypeLiteralName( dbgExpectedViewType );
+ const auto* ActualViewTypeName = GetViewTypeLiteralName( ViewType );
+ LOG_RESOURCE_BINDING_ERROR(ViewTypeName, pViewGL, Attribs, ArrayIndex, "Incorrect view type: ",
+ ExpectedViewTypeName, " is expected, ", ActualViewTypeName, " is provided.");
+ return false;
+ }
+}
+#endif
+
+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 DEVELOPMENT
+ if (pView && !pViewGL)
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, m_Attribs, ArrayIndex, "Incorect resource type: texture view is expected.");
+ if (pViewGL && !dbgVerifyViewType("texture view", pViewGL.RawPtr(), m_Attribs, ArrayIndex, TEXTURE_VIEW_SHADER_RESOURCE))
+ pViewGL.Release();
+
+ auto& CachedTexSampler = const_cast<const GLProgramResourceCache&>(ResourceCache).GetSampler(m_Attribs.Binding + ArrayIndex);
+ if (GetType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ if (CachedTexSampler.pView != nullptr && CachedTexSampler.pView != pViewGL)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(GetType());
+ LOG_ERROR_MESSAGE( "Non-null texture sampler is already bound to ", VarTypeStr, " shader variable '", m_Attribs.GetPrintName(ArrayIndex), "'. Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic." );
+ }
+ }
+ if (m_StaticSamplerIdx >= 0)
+ {
+ VERIFY(CachedTexSampler.pSampler != nullptr, "Static samplers must be initialized by PipelineStateGLImpl::InitializeSRBResourceCache!");
+ }
+#endif
+ ResourceCache.SetTexSampler(m_Attribs.Binding + ArrayIndex, std::move(pViewGL), m_StaticSamplerIdx < 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 DEVELOPMENT
+ if (pView && !pViewGL)
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, m_Attribs, ArrayIndex, "Incorect resource type: buffer view is expected.");
+ if (pViewGL && !dbgVerifyViewType("buffer view", pViewGL.RawPtr(), m_Attribs, ArrayIndex, BUFFER_VIEW_SHADER_RESOURCE))
+ pViewGL.Release();
+
+ if (GetType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ auto& CachedBuffSampler = const_cast<const GLProgramResourceCache&>(ResourceCache).GetSampler(m_Attribs.Binding + ArrayIndex);
+ if (CachedBuffSampler.pView != nullptr && CachedBuffSampler.pView != pViewGL)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(GetType());
+ LOG_ERROR_MESSAGE( "Non-null buffer sampler is already bound to ", VarTypeStr, " shader variable '", m_Attribs.GetPrintName(ArrayIndex), "'. Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic." );
+ }
+ }
+#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 DEVELOPMENT
+ if (pView && !pViewGL)
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, m_Attribs, ArrayIndex, "Incorect resource type: texture view is expected.");
+ if (pViewGL && !dbgVerifyViewType("texture view", pViewGL.RawPtr(), m_Attribs, ArrayIndex, TEXTURE_VIEW_UNORDERED_ACCESS))
+ pViewGL.Release();
+
+ if (GetType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ auto& CachedUAV = const_cast<const GLProgramResourceCache&>(ResourceCache).GetImage(m_Attribs.Binding + ArrayIndex);
+ if (CachedUAV.pView != nullptr && CachedUAV.pView != pViewGL)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(GetType());
+ LOG_ERROR_MESSAGE("Non-null texture image is already bound to ", VarTypeStr, " shader variable '", m_Attribs.GetPrintName(ArrayIndex), "'. Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic.");
+ }
+ }
+#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 DEVELOPMENT
+ if (pView && !pViewGL)
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, m_Attribs, ArrayIndex, "Incorect resource type: buffer view is expected.");
+ if (pViewGL && !dbgVerifyViewType("buffer view", pViewGL.RawPtr(), m_Attribs, ArrayIndex, BUFFER_VIEW_UNORDERED_ACCESS) )
+ pViewGL.Release();
+
+ if (GetType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ auto& CachedUAV = const_cast<const GLProgramResourceCache&>(ResourceCache).GetImage(m_Attribs.Binding + ArrayIndex);
+ if (CachedUAV.pView != nullptr && CachedUAV.pView != pViewGL)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(GetType());
+ LOG_ERROR_MESSAGE( "Non-null buffer image is already bound to ", VarTypeStr, " shader variable '", m_Attribs.GetPrintName(ArrayIndex), "'. Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic." );
+ }
+ }
+#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 DEVELOPMENT
+ if (pView && !pViewGL)
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, m_Attribs, ArrayIndex, "Incorect resource type: buffer view is expected.");
+ if (pViewGL)
+ {
+ auto ViewType = pViewGL->GetDesc().ViewType;
+ // Structured buffers are mapped to SSBOs
+ if (ViewType != BUFFER_VIEW_UNORDERED_ACCESS && ViewType != BUFFER_VIEW_SHADER_RESOURCE)
+ {
+ LOG_RESOURCE_BINDING_ERROR("resource", pView, m_Attribs, ArrayIndex, "Incorect view type: buffer SRV or UAV is expected.");
+ pViewGL.Release();
+ }
+ }
+
+ if (GetType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ auto& CachedSSBO = const_cast<const GLProgramResourceCache&>(ResourceCache).GetSSBO(m_Attribs.Binding + ArrayIndex);
+ if (CachedSSBO.pBufferView != nullptr && CachedSSBO.pBufferView != pViewGL)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(GetType());
+ LOG_ERROR_MESSAGE("Non-null storage block is already bound to ", VarTypeStr, " shader variable '", m_Attribs.GetPrintName(ArrayIndex), "'. Attempting to bind another resource or null is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic.");
+ }
+ }
+#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) :
+ ResourceMapping (RM),
+ ShaderStage (SS),
+ Flags (Fl)
+ {
+ }
+
+ 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);
+
+ HandleResources(
+ [&](UniformBuffBindInfo& ub)
+ {
+ BindResHelper.Bind(ub);
+ },
+
+ [&](SamplerBindInfo& sam)
+ {
+ BindResHelper.Bind(sam);
+ },
+
+ [&](ImageBindInfo& img)
+ {
+ BindResHelper.Bind(img);
+ },
+
+ [&](StorageBufferBindInfo& ssbo)
+ {
+ BindResHelper.Bind(ssbo);
+ }
+ );
+}
+
+
+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)
+{
+ 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(IsPowerOfTwo(Uint32{ShaderStage}), "Only one shader stage must be specified");
+ auto ShaderInd = GetShaderTypeIndex(ShaderStage);
+ auto ProgIdx = m_ProgramIndex[ShaderInd];
+
+ if (ProgIdx < 0)
+ return 0;
+
+ const auto& VariableEndOffset = GetProgramVarEndOffsets(ProgIdx);
+ const auto& VariableStartOffset = ProgIdx > 0 ? GetProgramVarEndOffsets(ProgIdx-1) : GLProgramResources::ResourceCounters{};
+
+ Uint32 NumVars = VariableEndOffset.NumUBs - VariableStartOffset.NumUBs +
+ VariableEndOffset.NumSamplers - VariableStartOffset.NumSamplers +
+ VariableEndOffset.NumImages - VariableStartOffset.NumImages +
+ VariableEndOffset.NumStorageBlocks - VariableStartOffset.NumStorageBlocks;
+#ifdef _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) :
+ Layout {_Layout},
+ Index {_Index}
+ {
+ }
+
+ 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 = GetShaderTypeIndex(ShaderStage);
+ 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) :
+ Layout (_Layout),
+ VarOffset(reinterpret_cast<const Uint8*>(&Variable) - reinterpret_cast<const Uint8*>(_Layout.m_ResourceBuffer.get()))
+ {}
+
+ 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[GetShaderTypeIndex(FirstStage)];
+ 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;
+ 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" );
+
+ HandleConstResources(
+ [&](const UniformBuffBindInfo& UB)
+ {
+ for (auto binding = UB.m_Attribs.Binding; binding < UB.m_Attribs.Binding + UB.m_Attribs.ArraySize; ++binding)
+ {
+ auto pBufferGL = SrcCache.GetUB(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.GetSampler(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.GetImage(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.GetSSBO(binding).pBufferView;
+ DstCache.SetSSBO(binding, std::move(pBufferView));
+ }
+ }
+ );
+}
+
+#ifdef DEVELOPMENT
+bool GLPipelineResourceLayout::dvpVerifyBindings()const
+{
+#define LOG_MISSING_BINDING(VarType, BindInfo, BindPt)\
+do{ \
+ if (BindInfo.m_Attribs.ArraySize == 1) \
+ LOG_ERROR_MESSAGE( "No resource is bound to ", VarType, " variable '", BindInfo.m_Attribs.Name, "'" ); \
+ else \
+ LOG_ERROR_MESSAGE( "No resource is bound to ", VarType, " variable '", BindInfo.m_Attribs.Name, "[", BindPt - BindInfo.m_Attribs.Binding, "]'");\
+}while(false)
+
+ 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 (!m_pResourceCache->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 (!m_pResourceCache->IsSamplerBound(BindPoint, sam.m_Attribs.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV))
+ {
+ LOG_MISSING_BINDING("texture", sam, BindPoint);
+ BindingsOK = false;
+ }
+ else
+ {
+ const auto& CachedSampler = const_cast<const GLProgramResourceCache*>(m_pResourceCache)->GetSampler(BindPoint);
+ if (sam.m_StaticSamplerIdx >= 0 && CachedSampler.pSampler == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Static 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 (!m_pResourceCache->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 (!m_pResourceCache->IsSSBOBound(BindPoint))
+ {
+ LOG_MISSING_BINDING("buffer", ssbo, BindPoint);
+ BindingsOK = false;
+ }
+ }
+ }
+ );
+#undef LOG_MISSING_BINDING
+
+ return BindingsOK;
+}
+
+#endif
+
+}
diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgram.cpp b/Graphics/GraphicsEngineOpenGL/src/GLProgram.cpp
deleted file mode 100644
index 226f991b..00000000
--- a/Graphics/GraphicsEngineOpenGL/src/GLProgram.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright 2019 Diligent Graphics LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include "pch.h"
-#include "GLProgram.h"
-#include "ShaderBase.h"
-#include "ShaderResourceBindingGLImpl.h"
-
-namespace Diligent
-{
- GLProgram::GLProgram( bool CreateObject ) :
- GLObjectWrappers::GLProgramObj( CreateObject )
- {}
-
- GLProgram::GLProgram( GLProgram&& Program ):
- GLObjectWrappers::GLProgramObj(std::move(Program ) ),
- m_AllResources (std::move(Program.m_AllResources))
- {}
-
- void GLProgram::InitResources(RenderDeviceGLImpl* pDeviceGLImpl,
- SHADER_TYPE ShaderStage,
- IObject& Owner)
- {
- GLuint GLProgram = static_cast<GLuint>(*this);
- m_AllResources.LoadUniforms(Owner, pDeviceGLImpl, ShaderStage, GLProgram);
- }
-}
diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp b/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp
new file mode 100644
index 00000000..f8b73d8d
--- /dev/null
+++ b/Graphics/GraphicsEngineOpenGL/src/GLProgramResourceCache.cpp
@@ -0,0 +1,112 @@
+/* Copyright 2019 Diligent Graphics LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "GLProgramResourceCache.h"
+
+namespace Diligent
+{
+
+size_t GLProgramResourceCache::GetRequriedMemorySize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount)
+{
+ auto MemSize =
+ sizeof(CachedUB) * UBCount +
+ sizeof(CachedResourceView) * SamplerCount +
+ sizeof(CachedResourceView) * ImageCount +
+ sizeof(CachedSSBO) * SSBOCount;
+ return MemSize;
+}
+
+void GLProgramResourceCache::Initialize(Uint32 UBCount, Uint32 SamplerCount, Uint32 ImageCount, Uint32 SSBOCount, class IMemoryAllocator& MemAllocator)
+{
+ 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);
+
+ VERIFY_EXPR(GetUBCount() == static_cast<Uint32>(UBCount));
+ VERIFY_EXPR(GetSamplerCount() == static_cast<Uint32>(SamplerCount));
+ VERIFY_EXPR(GetImageCount() == static_cast<Uint32>(ImageCount));
+ VERIFY_EXPR(GetSSBOCount() == static_cast<Uint32>(SSBOCount));
+
+ VERIFY_EXPR(m_pResourceData == nullptr);
+ size_t BufferSize = m_MemoryEndOffset;
+
+ VERIFY_EXPR(BufferSize == GetRequriedMemorySize(UBCount, SamplerCount, ImageCount, SSBOCount));
+
+#ifdef _DEBUG
+ m_pdbgMemoryAllocator = &MemAllocator;
+#endif
+ if( BufferSize > 0 )
+ {
+ m_pResourceData = ALLOCATE(MemAllocator, "Shader resource cache data buffer", Uint8, BufferSize);
+ memset(m_pResourceData, 0, BufferSize);
+ }
+
+ // Explicitly construct all objects
+ for (Uint32 cb = 0; cb < UBCount; ++cb)
+ new(&GetUB(cb)) CachedUB;
+
+ for (Uint32 s = 0; s < SamplerCount; ++s)
+ new(&GetSampler(s)) CachedResourceView;
+
+ for (Uint32 i = 0; i < ImageCount; ++i)
+ new(&GetImage(i)) CachedResourceView;
+
+ for (Uint32 s = 0; s < SSBOCount; ++s)
+ new(&GetSSBO(s)) CachedSSBO;
+}
+
+GLProgramResourceCache::~GLProgramResourceCache()
+{
+ VERIFY( !IsInitialized(), "Shader resource cache memory must be released with GLProgramResourceCache::Destroy()" );
+}
+
+void GLProgramResourceCache::Destroy(class IMemoryAllocator& MemAllocator)
+{
+ VERIFY( IsInitialized(), "Resource cache is not initialized");
+ VERIFY( m_pdbgMemoryAllocator == &MemAllocator, "The allocator does not match the one used to create resources");
+
+ for (Uint32 cb = 0; cb < GetUBCount(); ++cb)
+ GetUB(cb).~CachedUB();
+
+ for (Uint32 s = 0; s < GetSamplerCount(); ++s)
+ GetSampler(s).~CachedResourceView();
+
+ for (Uint32 i = 0; i < GetImageCount(); ++i)
+ GetImage(i).~CachedResourceView();
+
+ for (Uint32 s = 0; s < GetSSBOCount(); ++s)
+ GetSSBO(s).~CachedSSBO();
+
+ if (m_pResourceData != nullptr)
+ MemAllocator.Free(m_pResourceData);
+
+ m_pResourceData = nullptr;
+ m_SmplrsOffset = InvalidResourceOffset;
+ m_ImgsOffset = InvalidResourceOffset;
+ m_SSBOsOffset = InvalidResourceOffset;
+ m_MemoryEndOffset = InvalidResourceOffset;
+}
+
+}
diff --git a/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp b/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp
index 91bdf371..2ad23df1 100644
--- a/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/GLProgramResources.cpp
@@ -23,931 +23,686 @@
#include "pch.h"
#include <unordered_set>
+#include "GLContextState.h"
#include "GLProgramResources.h"
#include "RenderDeviceGLImpl.h"
#include "ShaderResourceBindingBase.h"
+#include "ShaderResourceVariableBase.h"
#include "Align.h"
namespace Diligent
{
- GLProgramResources::GLProgramResources(GLProgramResources&& Program)noexcept :
- m_ShaderStages (Program.m_ShaderStages),
- m_UniformBuffers (Program.m_UniformBuffers),
- m_Samplers (Program.m_Samplers),
- m_Images (Program.m_Images),
- m_StorageBlocks (Program.m_StorageBlocks),
- m_ResourceCache (Program.m_ResourceCache),
- m_StringPool (std::move(Program.m_StringPool)),
- m_NumUniformBuffers(Program.m_NumUniformBuffers),
- m_NumSamplers (Program.m_NumSamplers),
- m_NumImages (Program.m_NumImages),
- m_NumStorageBlocks (Program.m_NumStorageBlocks)
- {
- Program.m_UniformBuffers = nullptr;
- Program.m_Samplers = nullptr;
- Program.m_Images = nullptr;
- Program.m_StorageBlocks = nullptr;
- Program.m_ResourceCache = nullptr;
-
- Program.m_NumUniformBuffers = 0;
- Program.m_NumSamplers = 0;
- Program.m_NumImages = 0;
- Program.m_NumStorageBlocks = 0;
- }
- inline void RemoveArrayBrackets(char *Str)
- {
- auto* OpenBacketPtr = strchr(Str, '[');
- if (OpenBacketPtr != nullptr)
- *OpenBacketPtr = 0;
- }
+GLProgramResources::GLProgramResources(GLProgramResources&& Program)noexcept :
+ m_ShaderStages {Program.m_ShaderStages },
+ m_UniformBuffers {Program.m_UniformBuffers },
+ m_Samplers {Program.m_Samplers },
+ m_Images {Program.m_Images },
+ m_StorageBlocks {Program.m_StorageBlocks },
+ m_StringPool {std::move(Program.m_StringPool)},
+ m_NumUniformBuffers{Program.m_NumUniformBuffers },
+ m_NumSamplers {Program.m_NumSamplers },
+ m_NumImages {Program.m_NumImages },
+ m_NumStorageBlocks {Program.m_NumStorageBlocks }
+{
+ Program.m_UniformBuffers = nullptr;
+ Program.m_Samplers = nullptr;
+ Program.m_Images = nullptr;
+ Program.m_StorageBlocks = nullptr;
+
+ Program.m_NumUniformBuffers = 0;
+ Program.m_NumSamplers = 0;
+ Program.m_NumImages = 0;
+ Program.m_NumStorageBlocks = 0;
+}
- void GLProgramResources::AllocateResources(IObject& Owner,
- std::vector<UniformBufferInfo>& UniformBlocks,
- std::vector<SamplerInfo>& Samplers,
- std::vector<ImageInfo>& Images,
- std::vector<StorageBlockInfo>& StorageBlocks,
- bool InitializeResourceCache)
- {
- VERIFY(m_UniformBuffers == nullptr, "Resources have already been allocated!");
+inline void RemoveArrayBrackets(char *Str)
+{
+ auto* OpenBacketPtr = strchr(Str, '[');
+ if (OpenBacketPtr != nullptr)
+ *OpenBacketPtr = 0;
+}
- m_NumUniformBuffers = static_cast<Uint32>(UniformBlocks.size());
- m_NumSamplers = static_cast<Uint32>(Samplers.size());
- m_NumImages = static_cast<Uint32>(Images.size());
- m_NumStorageBlocks = static_cast<Uint32>(StorageBlocks.size());
+void GLProgramResources::AllocateResources(std::vector<UniformBufferInfo>& UniformBlocks,
+ std::vector<SamplerInfo>& Samplers,
+ std::vector<ImageInfo>& Images,
+ std::vector<StorageBlockInfo>& StorageBlocks)
+{
+ VERIFY(m_UniformBuffers == nullptr, "Resources have already been allocated!");
- size_t StringPoolDataSize = 0;
- size_t ResourceCacheSize = 0;
- for (const auto& ub : UniformBlocks)
- {
- StringPoolDataSize += strlen(ub.Name) + 1;
- ResourceCacheSize += ub.ArraySize;
- }
+ m_NumUniformBuffers = static_cast<Uint32>(UniformBlocks.size());
+ m_NumSamplers = static_cast<Uint32>(Samplers.size());
+ m_NumImages = static_cast<Uint32>(Images.size());
+ m_NumStorageBlocks = static_cast<Uint32>(StorageBlocks.size());
- for (const auto& sam : Samplers)
- {
- StringPoolDataSize += strlen(sam.Name) + 1;
- ResourceCacheSize += sam.ArraySize;
- }
+ size_t StringPoolDataSize = 0;
+ for (const auto& ub : UniformBlocks)
+ {
+ StringPoolDataSize += strlen(ub.Name) + 1;
+ }
- for (const auto& img : Images)
- {
- StringPoolDataSize += strlen(img.Name) + 1;
- ResourceCacheSize += img.ArraySize;
- }
+ for (const auto& sam : Samplers)
+ {
+ StringPoolDataSize += strlen(sam.Name) + 1;
+ }
- for (const auto& sb : StorageBlocks)
- {
- StringPoolDataSize += strlen(sb.Name) + 1;
- ResourceCacheSize += sb.ArraySize;
- }
+ for (const auto& img : Images)
+ {
+ StringPoolDataSize += strlen(img.Name) + 1;
+ }
- auto AlignedStringPoolDataSize = Align(StringPoolDataSize, sizeof(void*));
+ for (const auto& sb : StorageBlocks)
+ {
+ StringPoolDataSize += strlen(sb.Name) + 1;
+ }
- size_t TotalMemorySize =
- m_NumUniformBuffers * sizeof(UniformBufferInfo) +
- m_NumSamplers * sizeof(SamplerInfo) +
- m_NumImages * sizeof(ImageInfo) +
- m_NumStorageBlocks * sizeof(StorageBlockInfo);
-
- if (TotalMemorySize == 0)
- {
- m_UniformBuffers = nullptr;
- m_Samplers = nullptr;
- m_Images = nullptr;
- m_StorageBlocks = nullptr;
- m_ResourceCache = nullptr;
-
- m_NumUniformBuffers = 0;
- m_NumSamplers = 0;
- m_NumImages = 0;
- m_NumStorageBlocks = 0;
-
- return;
- }
+ auto AlignedStringPoolDataSize = Align(StringPoolDataSize, sizeof(void*));
- if (InitializeResourceCache)
- TotalMemorySize += ResourceCacheSize * sizeof(RefCntAutoPtr<IDeviceObject>);
+ size_t TotalMemorySize =
+ m_NumUniformBuffers * sizeof(UniformBufferInfo) +
+ m_NumSamplers * sizeof(SamplerInfo) +
+ m_NumImages * sizeof(ImageInfo) +
+ m_NumStorageBlocks * sizeof(StorageBlockInfo);
- TotalMemorySize += AlignedStringPoolDataSize * sizeof(Char);
+ if (TotalMemorySize == 0)
+ {
+ m_UniformBuffers = nullptr;
+ m_Samplers = nullptr;
+ m_Images = nullptr;
+ m_StorageBlocks = nullptr;
- auto& MemAllocator = GetRawAllocator();
- void* RawMemory = ALLOCATE_RAW(MemAllocator, "Memory buffer for GLProgramResources", TotalMemorySize);
-
- 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_StorageBlocks = reinterpret_cast<StorageBlockInfo*>(m_Images + m_NumImages);
- void* EndOfResourceData = m_StorageBlocks + m_NumStorageBlocks;
- Char* StringPoolData = nullptr;
- if (InitializeResourceCache)
- {
- m_ResourceCache = reinterpret_cast<RefCntAutoPtr<IDeviceObject>*>(EndOfResourceData);
- StringPoolData = reinterpret_cast<Char*>(m_ResourceCache + ResourceCacheSize);
- for (Uint32 res=0; res < ResourceCacheSize; ++res)
- new (m_ResourceCache+res) RefCntAutoPtr<IDeviceObject>{};
- }
- else
- {
- m_ResourceCache = nullptr;
- StringPoolData = reinterpret_cast<Char*>(EndOfResourceData);
- }
+ m_NumUniformBuffers = 0;
+ m_NumSamplers = 0;
+ m_NumImages = 0;
+ m_NumStorageBlocks = 0;
- m_StringPool.AssignMemory(StringPoolData, StringPoolDataSize);
+ return;
+ }
- Uint16 VariableIndex = 0;
- auto* pCurrResource = m_ResourceCache;
- for (Uint32 ub=0; ub < m_NumUniformBuffers; ++ub)
- {
- auto& SrcUB = UniformBlocks[ub];
- new (m_UniformBuffers + ub) UniformBufferInfo
- {
- Owner,
- m_StringPool.CopyString(SrcUB.Name),
- SrcUB.VariableType,
- SrcUB.ResourceType,
- VariableIndex++,
- SrcUB.ArraySize,
- pCurrResource,
- SrcUB.UBIndex
- };
- if (pCurrResource != nullptr)
- pCurrResource += SrcUB.ArraySize;
- }
+ TotalMemorySize += AlignedStringPoolDataSize * sizeof(Char);
- for (Uint32 s=0; s < m_NumSamplers; ++s)
- {
- auto& SrcSam = Samplers[s];
- new (m_Samplers + s) SamplerInfo
- {
- Owner,
- m_StringPool.CopyString(SrcSam.Name),
- SrcSam.VariableType,
- SrcSam.ResourceType,
- VariableIndex++,
- SrcSam.ArraySize,
- pCurrResource,
- SrcSam.Location,
- SrcSam.SamplerType,
- SrcSam.pStaticSampler
- };
- if (pCurrResource != nullptr)
- pCurrResource += SrcSam.ArraySize;
- }
+ auto& MemAllocator = GetRawAllocator();
+ void* RawMemory = ALLOCATE_RAW(MemAllocator, "Memory buffer for GLProgramResources", TotalMemorySize);
- for (Uint32 img=0; img < m_NumImages; ++img)
- {
- auto& SrcImg = Images[img];
- new (m_Images + img) ImageInfo
- {
- Owner,
- m_StringPool.CopyString(SrcImg.Name),
- SrcImg.VariableType,
- SrcImg.ResourceType,
- VariableIndex++,
- SrcImg.ArraySize,
- pCurrResource,
- SrcImg.Location,
- SrcImg.ImageType
- };
- if (pCurrResource != nullptr)
- pCurrResource += SrcImg.ArraySize;
- }
+ 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_StorageBlocks = reinterpret_cast<StorageBlockInfo*>(m_Images + m_NumImages);
+ void* EndOfResourceData = m_StorageBlocks + m_NumStorageBlocks;
+ Char* StringPoolData = reinterpret_cast<Char*>(EndOfResourceData);
- for (Uint32 sb=0; sb < m_NumStorageBlocks; ++sb)
- {
- auto& SrcSB = StorageBlocks[sb];
- new (m_StorageBlocks + sb) StorageBlockInfo
- {
- Owner,
- m_StringPool.CopyString(SrcSB.Name),
- SrcSB.VariableType,
- SrcSB.ResourceType,
- VariableIndex++,
- SrcSB.ArraySize,
- pCurrResource,
- SrcSB.SBIndex
- };
-
- if (pCurrResource != nullptr)
- pCurrResource += SrcSB.ArraySize;
- }
+ m_StringPool.AssignMemory(StringPoolData, StringPoolDataSize);
- VERIFY_EXPR(VariableIndex == GetVariableCount());
- VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0);
- VERIFY_EXPR(pCurrResource == nullptr || static_cast<size_t>(pCurrResource - m_ResourceCache) == ResourceCacheSize);
+ for (Uint32 ub=0; ub < m_NumUniformBuffers; ++ub)
+ {
+ auto& SrcUB = UniformBlocks[ub];
+ new (m_UniformBuffers + ub) UniformBufferInfo{SrcUB, m_StringPool};
}
- GLProgramResources::~GLProgramResources()
+ for (Uint32 s=0; s < m_NumSamplers; ++s)
{
- Uint32 ResourceCacheSize = 0;
- ProcessResources(
- [&](UniformBufferInfo& UB)
- {
- ResourceCacheSize += UB.ArraySize;
- UB.~UniformBufferInfo();
- },
- [&](SamplerInfo& Sam)
- {
- ResourceCacheSize += Sam.ArraySize;
- Sam.~SamplerInfo();
- },
- [&](ImageInfo& Img)
- {
- ResourceCacheSize += Img.ArraySize;
- Img.~ImageInfo();
- },
- [&](StorageBlockInfo& SB)
- {
- ResourceCacheSize += SB.ArraySize;
- SB.~StorageBlockInfo();
- }
- );
-
- if (m_ResourceCache != nullptr)
- {
- for (Uint32 res=0; res < ResourceCacheSize; ++res)
- m_ResourceCache[res].~RefCntAutoPtr();
- }
-
- void* RawMemory = m_UniformBuffers;
- if (RawMemory != nullptr)
- {
- auto& MemAllocator = GetRawAllocator();
- MemAllocator.Free(RawMemory);
- }
+ auto& SrcSam = Samplers[s];
+ new (m_Samplers + s) SamplerInfo{SrcSam, m_StringPool};
}
-
- void GLProgramResources::LoadUniforms(IObject& Owner,
- RenderDeviceGLImpl* pDeviceGLImpl,
- SHADER_TYPE ShaderStages,
- GLuint GLProgram)
+ for (Uint32 img=0; img < m_NumImages; ++img)
{
- std::vector<UniformBufferInfo> UniformBlocks;
- std::vector<SamplerInfo> Samplers;
- std::vector<ImageInfo> Images;
- std::vector<StorageBlockInfo> StorageBlocks;
- std::unordered_set<String> NamesPool;
+ auto& SrcImg = Images[img];
+ new (m_Images + img) ImageInfo{SrcImg, m_StringPool};
+ }
- VERIFY(GLProgram != 0, "Null GL program");
+ for (Uint32 sb=0; sb < m_NumStorageBlocks; ++sb)
+ {
+ auto& SrcSB = StorageBlocks[sb];
+ new (m_StorageBlocks + sb) StorageBlockInfo{SrcSB, m_StringPool};
+ }
- m_ShaderStages = ShaderStages;
+ VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0);
+}
- GLint numActiveUniforms = 0;
- glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
- CHECK_GL_ERROR_AND_THROW("Unable to get the number of active uniforms\n");
+GLProgramResources::~GLProgramResources()
+{
+ ProcessResources(
+ [&](UniformBufferInfo& UB)
+ {
+ UB.~UniformBufferInfo();
+ },
+ [&](SamplerInfo& Sam)
+ {
+ Sam.~SamplerInfo();
+ },
+ [&](ImageInfo& Img)
+ {
+ Img.~ImageInfo();
+ },
+ [&](StorageBlockInfo& SB)
+ {
+ SB.~StorageBlockInfo();
+ }
+ );
- // Query the maximum name length of the active uniform (including null terminator)
- GLint activeUniformMaxLength = 0;
- glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength);
- CHECK_GL_ERROR_AND_THROW("Unable to get the maximum uniform name length\n");
+ void* RawMemory = m_UniformBuffers;
+ if (RawMemory != nullptr)
+ {
+ auto& MemAllocator = GetRawAllocator();
+ MemAllocator.Free(RawMemory);
+ }
+}
- GLint numActiveUniformBlocks = 0;
- glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks);
- CHECK_GL_ERROR_AND_THROW("Unable to get the number of active uniform blocks\n");
- //
- // #### This parameter is currently unsupported by Intel OGL drivers.
- //
- // Query the maximum name length of the active uniform block (including null terminator)
- GLint activeUniformBlockMaxLength = 0;
- // On Intel driver, this call might fail:
- glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &activeUniformBlockMaxLength);
- //CHECK_GL_ERROR_AND_THROW("Unable to get the maximum uniform block name length\n");
- if (glGetError() != GL_NO_ERROR)
- {
- LOG_WARNING_MESSAGE( "Unable to get the maximum uniform block name length. Using 1024 as a workaround\n" );
- activeUniformBlockMaxLength = 1024;
- }
+void GLProgramResources::LoadUniforms(SHADER_TYPE ShaderStages,
+ const GLObjectWrappers::GLProgramObj& GLProgram,
+ GLContextState& State,
+ Uint32& UniformBufferBinding,
+ Uint32& SamplerBinding,
+ Uint32& ImageBinding,
+ Uint32& StorageBufferBinding)
+{
+ std::vector<UniformBufferInfo> UniformBlocks;
+ std::vector<SamplerInfo> Samplers;
+ std::vector<ImageInfo> Images;
+ std::vector<StorageBlockInfo> StorageBlocks;
+ std::unordered_set<String> NamesPool;
+
+ VERIFY(GLProgram != 0, "Null GL program");
+ State.SetProgram(GLProgram);
+
+ m_ShaderStages = ShaderStages;
+
+ GLint numActiveUniforms = 0;
+ glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
+ CHECK_GL_ERROR_AND_THROW("Unable to get the number of active uniforms\n");
+
+ // Query the maximum name length of the active uniform (including null terminator)
+ GLint activeUniformMaxLength = 0;
+ glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformMaxLength);
+ CHECK_GL_ERROR_AND_THROW("Unable to get the maximum uniform name length\n");
+
+ GLint numActiveUniformBlocks = 0;
+ glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveUniformBlocks);
+ CHECK_GL_ERROR_AND_THROW("Unable to get the number of active uniform blocks\n");
+
+ //
+ // #### This parameter is currently unsupported by Intel OGL drivers.
+ //
+ // Query the maximum name length of the active uniform block (including null terminator)
+ GLint activeUniformBlockMaxLength = 0;
+ // On Intel driver, this call might fail:
+ glGetProgramiv(GLProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &activeUniformBlockMaxLength);
+ //CHECK_GL_ERROR_AND_THROW("Unable to get the maximum uniform block name length\n");
+ if (glGetError() != GL_NO_ERROR)
+ {
+ LOG_WARNING_MESSAGE( "Unable to get the maximum uniform block name length. Using 1024 as a workaround\n" );
+ activeUniformBlockMaxLength = 1024;
+ }
- auto MaxNameLength = std::max(activeUniformMaxLength, activeUniformBlockMaxLength);
+ auto MaxNameLength = std::max(activeUniformMaxLength, activeUniformBlockMaxLength);
#if GL_ARB_program_interface_query
- GLint numActiveShaderStorageBlocks = 0;
- if (glGetProgramInterfaceiv)
- {
- glGetProgramInterfaceiv(GLProgram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numActiveShaderStorageBlocks);
- CHECK_GL_ERROR_AND_THROW( "Unable to get the number of shader storage blocks blocks\n" );
-
- // Query the maximum name length of the active shader storage block (including null terminator)
- GLint MaxShaderStorageBlockNameLen = 0;
- glGetProgramInterfaceiv(GLProgram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &MaxShaderStorageBlockNameLen);
- CHECK_GL_ERROR_AND_THROW( "Unable to get the maximum shader storage block name length\n" );
- MaxNameLength = std::max( MaxNameLength, MaxShaderStorageBlockNameLen );
- }
+ GLint numActiveShaderStorageBlocks = 0;
+ if (glGetProgramInterfaceiv)
+ {
+ glGetProgramInterfaceiv(GLProgram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numActiveShaderStorageBlocks);
+ CHECK_GL_ERROR_AND_THROW( "Unable to get the number of shader storage blocks blocks\n" );
+
+ // Query the maximum name length of the active shader storage block (including null terminator)
+ GLint MaxShaderStorageBlockNameLen = 0;
+ glGetProgramInterfaceiv(GLProgram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &MaxShaderStorageBlockNameLen);
+ CHECK_GL_ERROR_AND_THROW( "Unable to get the maximum shader storage block name length\n" );
+ MaxNameLength = std::max( MaxNameLength, MaxShaderStorageBlockNameLen );
+ }
#endif
- MaxNameLength = std::max(MaxNameLength, 512);
- std::vector<GLchar> Name(MaxNameLength + 1);
- for (int i = 0; i < numActiveUniforms; i++)
- {
- GLenum dataType = 0;
- GLint size = 0;
- GLint NameLen = 0;
- // If one or more elements of an array are active, the name of the array is returned in 'name',
- // the type is returned in 'type', and the 'size' parameter returns the highest array element index used,
- // plus one, as determined by the compiler and/or linker.
- // Only one active uniform variable will be reported for a uniform array.
- // Uniform variables other than arrays will have a size of 1
- glGetActiveUniform(GLProgram, i, MaxNameLength, &NameLen, &size, &dataType, Name.data());
- CHECK_GL_ERROR_AND_THROW("Unable to get active uniform\n");
- VERIFY(NameLen < MaxNameLength && static_cast<size_t>(NameLen) == strlen( Name.data() ), "Incorrect uniform name");
- VERIFY(size >= 1, "Size is expected to be at least 1");
- // Note that
- // glGetActiveUniform( program, index, bufSize, length, size, type, name );
- //
- // is equivalent to
- //
- // const enum props[] = { ARRAY_SIZE, TYPE };
- // glGetProgramResourceName( program, UNIFORM, index, bufSize, length, name );
- // glGetProgramResourceiv( program, GL_UNIFORM, index, 1, &props[0], 1, NULL, size );
- // glGetProgramResourceiv( program, GL_UNIFORM, index, 1, &props[1], 1, NULL, (int *)type );
- //
- // The latter is only available in GL 4.4 and GLES 3.1
-
- switch (dataType)
+ MaxNameLength = std::max(MaxNameLength, 512);
+ std::vector<GLchar> Name(MaxNameLength + 1);
+ for (int i = 0; i < numActiveUniforms; i++)
+ {
+ GLenum dataType = 0;
+ GLint size = 0;
+ GLint NameLen = 0;
+ // If one or more elements of an array are active, the name of the array is returned in 'name',
+ // the type is returned in 'type', and the 'size' parameter returns the highest array element index used,
+ // plus one, as determined by the compiler and/or linker.
+ // Only one active uniform variable will be reported for a uniform array.
+ // Uniform variables other than arrays will have a size of 1
+ glGetActiveUniform(GLProgram, i, MaxNameLength, &NameLen, &size, &dataType, Name.data());
+ CHECK_GL_ERROR_AND_THROW("Unable to get active uniform\n");
+ VERIFY(NameLen < MaxNameLength && static_cast<size_t>(NameLen) == strlen( Name.data() ), "Incorrect uniform name");
+ VERIFY(size >= 1, "Size is expected to be at least 1");
+ // Note that
+ // glGetActiveUniform( program, index, bufSize, length, size, type, name );
+ //
+ // is equivalent to
+ //
+ // const enum props[] = { ARRAY_SIZE, TYPE };
+ // glGetProgramResourceName( program, UNIFORM, index, bufSize, length, name );
+ // glGetProgramResourceiv( program, GL_UNIFORM, index, 1, &props[0], 1, NULL, size );
+ // glGetProgramResourceiv( program, GL_UNIFORM, index, 1, &props[1], 1, NULL, (int *)type );
+ //
+ // The latter is only available in GL 4.4 and GLES 3.1
+
+ switch (dataType)
+ {
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+
+ 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:
+
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+
+ case GL_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
{
- case GL_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
-
- case GL_SAMPLER_1D_ARRAY:
- case GL_SAMPLER_2D_ARRAY:
- case GL_SAMPLER_1D_ARRAY_SHADOW:
- case GL_SAMPLER_2D_ARRAY_SHADOW:
- case GL_SAMPLER_CUBE_SHADOW:
-
- case GL_INT_SAMPLER_1D:
- case GL_INT_SAMPLER_2D:
- case GL_INT_SAMPLER_3D:
- case GL_INT_SAMPLER_CUBE:
- case GL_INT_SAMPLER_1D_ARRAY:
- case GL_INT_SAMPLER_2D_ARRAY:
- case GL_UNSIGNED_INT_SAMPLER_1D:
- case GL_UNSIGNED_INT_SAMPLER_2D:
- case GL_UNSIGNED_INT_SAMPLER_3D:
- case GL_UNSIGNED_INT_SAMPLER_CUBE:
- case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
- case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
-
- 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:
-
- case GL_SAMPLER_2D_MULTISAMPLE:
- case GL_INT_SAMPLER_2D_MULTISAMPLE:
- case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
- case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
- case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
- case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
-
- case GL_SAMPLER_BUFFER:
- 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
+ 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
- const auto ResourceType = dataType == GL_SAMPLER_BUFFER ||
- dataType == GL_INT_SAMPLER_BUFFER ||
- dataType == GL_UNSIGNED_INT_SAMPLER_BUFFER ?
- SHADER_RESOURCE_TYPE_BUFFER_SRV : SHADER_RESOURCE_TYPE_TEXTURE_SRV;
+ const auto ResourceType = dataType == GL_SAMPLER_BUFFER ||
+ dataType == GL_INT_SAMPLER_BUFFER ||
+ dataType == GL_UNSIGNED_INT_SAMPLER_BUFFER ?
+ SHADER_RESOURCE_TYPE_BUFFER_SRV : SHADER_RESOURCE_TYPE_TEXTURE_SRV;
- RemoveArrayBrackets(Name.data());
+ RemoveArrayBrackets(Name.data());
- Samplers.emplace_back(
- Owner,
- NamesPool.emplace(Name.data()).first->c_str(),
- SHADER_RESOURCE_VARIABLE_TYPE_STATIC,
- ResourceType,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
- static_cast<Uint32>(size),
- nullptr, // pResources
- UniformLocation,
- dataType,
- nullptr
- );
- break;
+ Samplers.emplace_back(
+ NamesPool.emplace(Name.data()).first->c_str(),
+ ShaderStages,
+ ResourceType,
+ SamplerBinding,
+ static_cast<Uint32>(size),
+ UniformLocation,
+ dataType
+ );
+
+ 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;
+ }
+
#if GL_ARB_shader_image_load_store
- case GL_IMAGE_1D:
- case GL_IMAGE_2D:
- case GL_IMAGE_3D:
- case GL_IMAGE_2D_RECT:
- case GL_IMAGE_CUBE:
- case GL_IMAGE_BUFFER:
- case GL_IMAGE_1D_ARRAY:
- case GL_IMAGE_2D_ARRAY:
- case GL_IMAGE_CUBE_MAP_ARRAY:
- case GL_IMAGE_2D_MULTISAMPLE:
- case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
- case GL_INT_IMAGE_1D:
- case GL_INT_IMAGE_2D:
- case GL_INT_IMAGE_3D:
- case GL_INT_IMAGE_2D_RECT:
- case GL_INT_IMAGE_CUBE:
- case GL_INT_IMAGE_BUFFER:
- case GL_INT_IMAGE_1D_ARRAY:
- case GL_INT_IMAGE_2D_ARRAY:
- case GL_INT_IMAGE_CUBE_MAP_ARRAY:
- case GL_INT_IMAGE_2D_MULTISAMPLE:
- case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
- case GL_UNSIGNED_INT_IMAGE_1D:
- case GL_UNSIGNED_INT_IMAGE_2D:
- case GL_UNSIGNED_INT_IMAGE_3D:
- case GL_UNSIGNED_INT_IMAGE_2D_RECT:
- case GL_UNSIGNED_INT_IMAGE_CUBE:
- case GL_UNSIGNED_INT_IMAGE_BUFFER:
- case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
- case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
- case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
- case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
- case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ {
+ auto UniformLocation = glGetUniformLocation( GLProgram, Name.data() );
+
+ const auto ResourceType = dataType == GL_IMAGE_BUFFER ||
+ dataType == GL_INT_IMAGE_BUFFER ||
+ dataType == GL_UNSIGNED_INT_IMAGE_BUFFER ?
+ SHADER_RESOURCE_TYPE_BUFFER_UAV : SHADER_RESOURCE_TYPE_TEXTURE_UAV;
+
+ RemoveArrayBrackets(Name.data());
+
+ Images.emplace_back(
+ NamesPool.emplace(Name.data()).first->c_str(),
+ ShaderStages,
+ ResourceType,
+ ImageBinding,
+ static_cast<Uint32>(size),
+ UniformLocation,
+ dataType );
+
+ for (GLint arr_ind = 0; arr_ind < size; ++arr_ind)
{
- auto UniformLocation = glGetUniformLocation( GLProgram, Name.data() );
-
- const auto ResourceType = dataType == GL_IMAGE_BUFFER ||
- dataType == GL_INT_IMAGE_BUFFER ||
- dataType == GL_UNSIGNED_INT_IMAGE_BUFFER ?
- SHADER_RESOURCE_TYPE_BUFFER_UAV : SHADER_RESOURCE_TYPE_TEXTURE_UAV;
-
- RemoveArrayBrackets(Name.data());
-
- Images.emplace_back(
- Owner,
- NamesPool.emplace(Name.data()).first->c_str(),
- SHADER_RESOURCE_VARIABLE_TYPE_STATIC,
- ResourceType,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
- static_cast<Uint32>(size),
- nullptr, // pResources
- UniformLocation,
- dataType );
- break;
+ // 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 the shader source."
+ " Note that bindings are properly assigned by HLSL->GLSL converter.");
+ }
+ 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 the shader source."
+ " Note that bindings are properly assigned by HLSL->GLSL converter.");
+ }
+ }
}
-#endif
- default:
- // Some other uniform type like scalar, matrix etc.
- break;
+
+ break;
}
+#endif
+ default:
+ // Some other uniform type like scalar, matrix etc.
+ break;
}
+ }
- for (int i = 0; i < numActiveUniformBlocks; i++)
+ for (int i = 0; i < numActiveUniformBlocks; i++)
+ {
+ // In contrast to shader uniforms, every element in uniform block array is enumerated individually
+ GLsizei NameLen = 0;
+ glGetActiveUniformBlockName(GLProgram, i, MaxNameLength, &NameLen, Name.data());
+ CHECK_GL_ERROR_AND_THROW("Unable to get active uniform block name\n");
+ VERIFY(NameLen < MaxNameLength && static_cast<size_t>(NameLen) == strlen( Name.data() ), "Incorrect uniform block name");
+
+ // glGetActiveUniformBlockName( program, uniformBlockIndex, bufSize, length, uniformBlockName );
+ // is equivalent to
+ // glGetProgramResourceName(program, GL_UNIFORM_BLOCK, uniformBlockIndex, bufSize, length, uniformBlockName);
+
+ auto UniformBlockIndex = glGetUniformBlockIndex(GLProgram, Name.data());
+ CHECK_GL_ERROR_AND_THROW("Unable to get active uniform block index\n");
+ // glGetUniformBlockIndex( program, uniformBlockName );
+ // is equivalent to
+ // glGetProgramResourceIndex( program, GL_UNIFORM_BLOCK, uniformBlockName );
+
+ bool IsNewBlock = true;
+
+ GLint ArraySize = 1;
+ auto* OpenBacketPtr = strchr(Name.data(), '[');
+ if (OpenBacketPtr != nullptr)
{
- // In contrast to shader uniforms, every element in uniform block array is enumerated individually
- GLsizei NameLen = 0;
- glGetActiveUniformBlockName(GLProgram, i, MaxNameLength, &NameLen, Name.data());
- CHECK_GL_ERROR_AND_THROW("Unable to get active uniform block name\n");
- VERIFY(NameLen < MaxNameLength && static_cast<size_t>(NameLen) == strlen( Name.data() ), "Incorrect uniform block name");
-
- // glGetActiveUniformBlockName( program, uniformBlockIndex, bufSize, length, uniformBlockName );
- // is equivalent to
- // glGetProgramResourceName(program, GL_UNIFORM_BLOCK, uniformBlockIndex, bufSize, length, uniformBlockName);
-
- auto UniformBlockIndex = glGetUniformBlockIndex(GLProgram, Name.data());
- CHECK_GL_ERROR_AND_THROW("Unable to get active uniform block index\n");
- // glGetUniformBlockIndex( program, uniformBlockName );
- // is equivalent to
- // glGetProgramResourceIndex( program, GL_UNIFORM_BLOCK, uniformBlockName );
-
- GLint ArraySize = 1;
- auto* OpenBacketPtr = strchr(Name.data(), '[');
- if (OpenBacketPtr != nullptr)
+ auto Ind = atoi(OpenBacketPtr+1);
+ ArraySize = std::max(ArraySize, Ind+1);
+ *OpenBacketPtr = 0;
+ if (!UniformBlocks.empty())
{
- auto Ind = atoi(OpenBacketPtr+1);
- ArraySize = std::max(ArraySize, Ind+1);
- *OpenBacketPtr = 0;
- if (UniformBlocks.size() > 0)
+ // Look at previous uniform block to check if it is the same array
+ auto& LastBlock = UniformBlocks.back();
+ if (strcmp(LastBlock.Name, Name.data()) == 0)
+ {
+ ArraySize = std::max(ArraySize, static_cast<GLint>(LastBlock.ArraySize));
+ VERIFY(UniformBlockIndex == LastBlock.UBIndex + Ind, "Uniform block indices are expected to be continuous");
+ LastBlock.ArraySize = ArraySize;
+ IsNewBlock = false;
+ }
+ else
{
- // Look at previous uniform block to check if it is the same array
- auto& LastBlock = UniformBlocks.back();
- if ( strcmp(LastBlock.Name, Name.data()) == 0)
- {
- ArraySize = std::max(ArraySize, static_cast<GLint>(LastBlock.ArraySize));
- VERIFY(UniformBlockIndex == LastBlock.UBIndex + Ind, "Uniform block indices are expected to be continuous");
- LastBlock.ArraySize = ArraySize;
- continue;
- }
- else
- {
#ifdef _DEBUG
- for (const auto& ub : UniformBlocks)
- VERIFY(strcmp(ub.Name, Name.data()) != 0, "Uniform block with the name '", ub.Name, "' has already been enumerated");
+ for (const auto& ub : UniformBlocks)
+ VERIFY(strcmp(ub.Name, Name.data()) != 0, "Uniform block with the name '", ub.Name, "' has already been enumerated");
#endif
- }
}
}
+ }
+ if (IsNewBlock)
+ {
UniformBlocks.emplace_back(
- Owner,
NamesPool.emplace(Name.data()).first->c_str(),
- SHADER_RESOURCE_VARIABLE_TYPE_STATIC,
+ ShaderStages,
SHADER_RESOURCE_TYPE_CONSTANT_BUFFER,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
+ UniformBufferBinding,
static_cast<Uint32>(ArraySize),
- nullptr, // pResources
UniformBlockIndex
);
}
+ glUniformBlockBinding(GLProgram, UniformBlockIndex, UniformBufferBinding++);
+ CHECK_GL_ERROR("glUniformBlockBinding() failed");
+ }
+
#if GL_ARB_shader_storage_buffer_object
- for (int i = 0; i < numActiveShaderStorageBlocks; ++i)
- {
- GLsizei Length = 0;
- glGetProgramResourceName(GLProgram, GL_SHADER_STORAGE_BLOCK, i, MaxNameLength, &Length, Name.data());
- CHECK_GL_ERROR_AND_THROW("Unable to get shader storage block name\n");
- VERIFY( Length < MaxNameLength && static_cast<size_t>(Length) == strlen( Name.data() ), "Incorrect shader storage block name" );
+ for (int i = 0; i < numActiveShaderStorageBlocks; ++i)
+ {
+ GLsizei Length = 0;
+ glGetProgramResourceName(GLProgram, GL_SHADER_STORAGE_BLOCK, i, MaxNameLength, &Length, Name.data());
+ CHECK_GL_ERROR_AND_THROW("Unable to get shader storage block name\n");
+ VERIFY( Length < MaxNameLength && static_cast<size_t>(Length) == strlen( Name.data() ), "Incorrect shader storage block name" );
- auto SBIndex = glGetProgramResourceIndex(GLProgram, GL_SHADER_STORAGE_BLOCK, Name.data());
- CHECK_GL_ERROR_AND_THROW("Unable to get shader storage block index\n");
+ auto SBIndex = glGetProgramResourceIndex(GLProgram, GL_SHADER_STORAGE_BLOCK, Name.data());
+ CHECK_GL_ERROR_AND_THROW("Unable to get shader storage block index\n");
- Int32 ArraySize = 1;
- auto* OpenBacketPtr = strchr(Name.data(), '[');
- if (OpenBacketPtr != nullptr)
+ bool IsNewBlock = true;
+ Int32 ArraySize = 1;
+ auto* OpenBacketPtr = strchr(Name.data(), '[');
+ if (OpenBacketPtr != nullptr)
+ {
+ auto Ind = atoi(OpenBacketPtr+1);
+ ArraySize = std::max(ArraySize, Ind+1);
+ *OpenBacketPtr = 0;
+ if (!StorageBlocks.empty())
{
- auto Ind = atoi(OpenBacketPtr+1);
- ArraySize = std::max(ArraySize, Ind+1);
- *OpenBacketPtr = 0;
- if (StorageBlocks.size() > 0)
+ // Look at previous storage block to check if it is the same array
+ auto& LastBlock = StorageBlocks.back();
+ if (strcmp(LastBlock.Name, Name.data()) == 0)
+ {
+ ArraySize = std::max(ArraySize, static_cast<GLint>(LastBlock.ArraySize));
+ VERIFY(static_cast<GLint>(SBIndex) == LastBlock.SBIndex + Ind, "Storage block indices are expected to be continuous");
+ LastBlock.ArraySize = ArraySize;
+ IsNewBlock = false;
+ }
+ else
{
- // Look at previous storage block to check if it is the same array
- auto& LastBlock = StorageBlocks.back();
- if ( strcmp(LastBlock.Name, Name.data()) == 0)
- {
- ArraySize = std::max(ArraySize, static_cast<GLint>(LastBlock.ArraySize));
- VERIFY(static_cast<GLint>(SBIndex) == LastBlock.SBIndex + Ind, "Storage block indices are expected to be continuous");
- LastBlock.ArraySize = ArraySize;
- continue;
- }
- else
- {
#ifdef _DEBUG
- for (const auto& sb : StorageBlocks)
- VERIFY(strcmp(sb.Name, Name.data()) != 0, "Storage block with the name \"", sb.Name, "\" has already been enumerated");
+ for (const auto& sb : StorageBlocks)
+ VERIFY(strcmp(sb.Name, Name.data()) != 0, "Storage block with the name \"", sb.Name, "\" has already been enumerated");
#endif
- }
}
}
+ }
+ if (IsNewBlock)
+ {
StorageBlocks.emplace_back(
- Owner,
NamesPool.emplace(Name.data()).first->c_str(),
- SHADER_RESOURCE_VARIABLE_TYPE_STATIC,
+ ShaderStages,
SHADER_RESOURCE_TYPE_BUFFER_UAV,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
+ StorageBufferBinding,
static_cast<Uint32>(ArraySize),
- nullptr, // pResources
SBIndex
);
}
-#endif
- AllocateResources(Owner, UniformBlocks, Samplers, Images, StorageBlocks, false);
- }
-
-
- void GLProgramResources::Clone(RenderDeviceGLImpl* pDeviceGLImpl,
- IObject& Owner,
- const GLProgramResources& SrcResources,
- const PipelineResourceLayoutDesc& ResourceLayout,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes)
- {
- std::vector<UniformBufferInfo> UniformBlocks;
- std::vector<SamplerInfo> Samplers;
- std::vector<ImageInfo> Images;
- std::vector<StorageBlockInfo> StorageBlocks;
-
- m_ShaderStages = SrcResources.m_ShaderStages;
- const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
- for (Uint32 ub=0; ub < SrcResources.GetNumUniformBuffers(); ++ub)
+ if (glShaderStorageBlockBinding)
{
- const auto& SrcUB = SrcResources.GetUniformBuffer(ub);
- auto VarType = GetShaderVariableType(m_ShaderStages, SrcUB.Name, ResourceLayout);
- if (IsAllowedType(VarType, AllowedTypeBits))
- {
- UniformBlocks.emplace_back(
- Owner,
- SrcUB.Name,
- VarType,
- SrcUB.ResourceType,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
- SrcUB.ArraySize,
- nullptr, // pResources
- SrcUB.UBIndex
- );
- }
- }
-
- for (Uint32 sam = 0; sam < SrcResources.GetNumSamplers(); ++sam)
- {
- const auto& SrcSam = SrcResources.GetSampler(sam);
- auto VarType = GetShaderVariableType(m_ShaderStages, SrcSam.Name, ResourceLayout);
- if (IsAllowedType(VarType, AllowedTypeBits))
- {
- RefCntAutoPtr<ISampler> pStaticSampler;
- for (Uint32 s = 0; s < ResourceLayout.NumStaticSamplers; ++s)
- {
- const auto& StSam = ResourceLayout.StaticSamplers[s];
- if (strcmp(SrcSam.Name, StSam.SamplerOrTextureName) == 0)
- {
- pDeviceGLImpl->CreateSampler(StSam.Desc, &pStaticSampler);
- break;
- }
- }
- Samplers.emplace_back(
- Owner,
- SrcSam.Name,
- VarType,
- SrcSam.ResourceType,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
- SrcSam.ArraySize,
- nullptr, // pResources
- SrcSam.Location,
- SrcSam.SamplerType,
- pStaticSampler.RawPtr<SamplerGLImpl>()
- );
- }
+ glShaderStorageBlockBinding(GLProgram, SBIndex, StorageBufferBinding);
+ CHECK_GL_ERROR("glShaderStorageBlockBinding() failed");
}
-
- for (Uint32 img = 0; img < SrcResources.GetNumImages(); ++img)
- {
- const auto& SrcImg = SrcResources.GetImage(img);
- auto VarType = GetShaderVariableType(m_ShaderStages, SrcImg.Name, ResourceLayout);
- if (IsAllowedType(VarType, AllowedTypeBits))
- {
- Images.emplace_back(
- Owner,
- SrcImg.Name,
- VarType,
- SrcImg.ResourceType,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
- SrcImg.ArraySize,
- nullptr, // pResources
- SrcImg.Location,
- SrcImg.ImageType
- );
- }
- }
-
- for (Uint32 sb = 0; sb < SrcResources.GetNumStorageBlocks(); ++sb)
+ else
{
- const auto& SrcSB = SrcResources.GetStorageBlock(sb);
- auto VarType = GetShaderVariableType(m_ShaderStages, SrcSB.Name, ResourceLayout);
- if (IsAllowedType(VarType, AllowedTypeBits))
- {
- StorageBlocks.emplace_back(
- Owner,
- SrcSB.Name,
- VarType,
- SrcSB.ResourceType,
- Uint16{0xFFFF}, // Variable index is assigned by AllocateResources
- SrcSB.ArraySize,
- nullptr, // pResources
- SrcSB.SBIndex
- );
- }
+ 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 the shader source."
+ " Note that bindings are properly assigned by HLSL->GLSL converter.");
}
-
- AllocateResources(Owner, UniformBlocks, Samplers, Images, StorageBlocks, true);
+ ++StorageBufferBinding;
}
+#endif
+ State.SetProgram(GLObjectWrappers::GLProgramObj{false});
+ AllocateResources(UniformBlocks, Samplers, Images, StorageBlocks);
+}
- GLProgramResources::GLProgramVariableBase* GLProgramResources::GetVariable(const Char* Name)
- {
- // Name will be implicitly converted to HashMapStringKey without making a copy
- for (Uint32 ub=0; ub < m_NumUniformBuffers; ++ub)
- {
- auto& UB = GetUniformBuffer(ub);
- if (strcmp(UB.Name, Name) == 0)
- return &UB;
- }
-
- for (Uint32 s=0; s < m_NumSamplers; ++s)
- {
- auto& Sam = GetSampler(s);
- if (strcmp(Sam.Name, Name) == 0)
- return &Sam;
- }
+ShaderResourceDesc GLProgramResources::GetResourceDesc(Uint32 Index)const
+{
+ if (Index < m_NumUniformBuffers)
+ return GetUniformBuffer(Index).GetResourceDesc();
+ else
+ Index -= m_NumUniformBuffers;
+
+ if (Index < m_NumSamplers)
+ return GetSampler(Index).GetResourceDesc();
+ else
+ Index -= m_NumSamplers;
+
+ if (Index < m_NumImages)
+ return GetImage(Index).GetResourceDesc();
+ else
+ Index -= m_NumImages;
+
+ if (Index < m_NumStorageBlocks)
+ return GetStorageBlock(Index).GetResourceDesc();
+ else
+ Index -= m_NumStorageBlocks;
+
+ LOG_ERROR_MESSAGE("Resource index ", Index + GetVariableCount(), " is invalid");
+ return ShaderResourceDesc{};
+}
- for (Uint32 img=0; img < m_NumImages; ++img)
- {
- auto& Img = GetImage(img);
- if (strcmp(Img.Name, Name) == 0)
- return &Img;
- }
+void GLProgramResources::CountResources(const PipelineResourceLayoutDesc& ResourceLayout,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ ResourceCounters& Counters)const
+{
+ 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
+ );
+}
- for (Uint32 sb=0; sb < m_NumStorageBlocks; ++sb)
- {
- auto& SB = GetStorageBlock(sb);
- if (strcmp(SB.Name, Name) == 0)
- return &SB;
- }
+bool GLProgramResources::IsCompatibleWith(const GLProgramResources& Res)const
+{
+ if (GetNumUniformBuffers() != Res.GetNumUniformBuffers() ||
+ GetNumSamplers() != Res.GetNumSamplers() ||
+ GetNumImages() != Res.GetNumImages() ||
+ GetNumStorageBlocks() != Res.GetNumStorageBlocks())
+ return false;
- return nullptr;
+ for (Uint32 ub = 0; ub < GetNumUniformBuffers(); ++ub)
+ {
+ const auto& UB0 = GetUniformBuffer(ub);
+ const auto& UB1 = Res.GetUniformBuffer(ub);
+ if (!UB0.IsCompatibleWith(UB1))
+ return false;
}
- const GLProgramResources::GLProgramVariableBase* GLProgramResources::GetVariable(Uint32 Index)const
+ for (Uint32 sam = 0; sam < GetNumSamplers(); ++sam)
{
- if (Index < GetNumUniformBuffers())
- return &GetUniformBuffer(Index);
- else
- Index -= GetNumUniformBuffers();
-
- if (Index < GetNumSamplers())
- return &GetSampler(Index);
- else
- Index -= GetNumSamplers();
-
- if (Index < GetNumImages())
- return &GetImage(Index);
- else
- Index -= GetNumImages();
-
- if (Index < GetNumStorageBlocks())
- return &GetStorageBlock(Index);
- else
- Index -= GetNumStorageBlocks();
-
- return nullptr;
+ const auto& Sam0 = GetSampler(sam);
+ const auto& Sam1 = Res.GetSampler(sam);
+ if (!Sam0.IsCompatibleWith(Sam1))
+ return false;
}
-
- static void BindResourcesHelper(GLProgramResources::GLProgramVariableBase& res, IResourceMapping* pResourceMapping, Uint32 Flags)
+ for (Uint32 img = 0; img < GetNumImages(); ++img)
{
- if ( (Flags & (1 << res.VariableType)) == 0 )
- return;
-
- auto& Name = res.Name;
- for (Uint32 ArrInd = 0; ArrInd < res.ArraySize; ++ArrInd)
- {
- auto& CurrResource = res.pResources[ArrInd];
-
- if ( (Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) != 0 && CurrResource )
- continue; // Skip already resolved resources
-
- RefCntAutoPtr<IDeviceObject> pNewRes;
- pResourceMapping->GetResource( Name, static_cast<IDeviceObject**>(&pNewRes), ArrInd );
-
- if (pNewRes != nullptr)
- {
- if(res.VariableType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC && CurrResource != nullptr && CurrResource != pNewRes )
- LOG_ERROR_MESSAGE( "Updating binding for static variable \"", Name, "\" is invalid and may result in an undefined behavior" );
- CurrResource = pNewRes;
- }
- else
- {
- if ( CurrResource == nullptr && (Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) )
- LOG_ERROR_MESSAGE("Resource \"", Name, "\" is not found in the resource mapping");
- }
- }
+ const auto& Img0 = GetImage(img);
+ const auto& Img1 = Res.GetImage(img);
+ if (!Img0.IsCompatibleWith(Img1))
+ return false;
}
-
- void GLProgramResources::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags )
+ for (Uint32 sb = 0; sb < GetNumStorageBlocks(); ++sb)
{
- if( !pResourceMapping )
- return;
-
- if ( (Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0 )
- Flags |= BIND_SHADER_RESOURCES_UPDATE_ALL;
-
- ProcessResources(
- [&](UniformBufferInfo& UB)
- {
- BindResourcesHelper(UB, pResourceMapping, Flags);
- },
- [&](SamplerInfo& Sam)
- {
- BindResourcesHelper(Sam, pResourceMapping, Flags);
- },
- [&](ImageInfo& Img)
- {
- BindResourcesHelper(Img, pResourceMapping, Flags);
- },
- [&](StorageBlockInfo& SB)
- {
- BindResourcesHelper(SB, pResourceMapping, Flags);
- }
- );
+ const auto& SB0 = GetStorageBlock(sb);
+ const auto& SB1 = Res.GetStorageBlock(sb);
+ if (!SB0.IsCompatibleWith(SB1))
+ return false;
}
+ return true;
+}
- bool GLProgramResources::IsCompatibleWith(const GLProgramResources& Res)const
- {
- if (GetNumUniformBuffers() != Res.GetNumUniformBuffers() ||
- GetNumSamplers() != Res.GetNumSamplers() ||
- GetNumImages() != Res.GetNumImages() ||
- GetNumStorageBlocks() != Res.GetNumStorageBlocks())
- return false;
- for (Uint32 ub = 0; ub < GetNumUniformBuffers(); ++ub)
- {
- const auto& UB0 = GetUniformBuffer(ub);
- const auto& UB1 = Res.GetUniformBuffer(ub);
- if (!UB0.IsCompatibleWith(UB1))
- return false;
- }
+size_t GLProgramResources::GetHash()const
+{
+ size_t hash = ComputeHash(GetNumUniformBuffers(), GetNumSamplers(), GetNumImages(), GetNumStorageBlocks());
- for (Uint32 sam = 0; sam < GetNumSamplers(); ++sam)
+ ProcessConstResources(
+ [&](const UniformBufferInfo& UB)
{
- const auto& Sam0 = GetSampler(sam);
- const auto& Sam1 = Res.GetSampler(sam);
- if (!Sam0.IsCompatibleWith(Sam1))
- return false;
- }
-
- for (Uint32 img = 0; img < GetNumImages(); ++img)
+ HashCombine(hash, UB.GetHash());
+ },
+ [&](const SamplerInfo& Sam)
{
- const auto& Img0 = GetImage(img);
- const auto& Img1 = Res.GetImage(img);
- if (!Img0.IsCompatibleWith(Img1))
- return false;
- }
-
- for (Uint32 sb = 0; sb < GetNumStorageBlocks(); ++sb)
+ HashCombine(hash, Sam.GetHash());
+ },
+ [&](const ImageInfo& Img)
{
- 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());
-
- 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());
- }
- );
-
- return hash;
- }
-
-#ifdef VERIFY_RESOURCE_BINDINGS
- static void dbgVerifyResourceBindingsHelper(const GLProgramResources::GLProgramVariableBase& res, const Char* VarTypeName)
- {
- for (Uint32 ArrInd = 0; ArrInd < res.ArraySize; ++ArrInd)
+ HashCombine(hash, Img.GetHash());
+ },
+ [&](const StorageBlockInfo& SB)
{
- if (!res.pResources[ArrInd])
- {
- if( res.ArraySize > 1)
- LOG_ERROR_MESSAGE( "No resource is bound to ", VarTypeName, " variable \"", res.Name, "[", ArrInd, "]\"" );
- else
- LOG_ERROR_MESSAGE( "No resource is bound to ", VarTypeName, " variable \"", res.Name, "\"" );
- }
+ HashCombine(hash, SB.GetHash());
}
- }
+ );
- void GLProgramResources::dbgVerifyResourceBindings()const
- {
- ProcessConstResources(
- [&](const UniformBufferInfo& UB)
- {
- dbgVerifyResourceBindingsHelper(UB, "uniform block");
- },
- [&](const SamplerInfo& Sam)
- {
- dbgVerifyResourceBindingsHelper(Sam, "sampler");
- },
- [&](const ImageInfo& Img)
- {
- dbgVerifyResourceBindingsHelper(Img, "image");
- },
- [&](const StorageBlockInfo& SB)
- {
- dbgVerifyResourceBindingsHelper(SB, "shader storage block");
- }
- );
- }
-#endif
+ return hash;
+}
}
diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp
index 3d0e597c..aa67f70c 100644
--- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp
@@ -27,6 +27,7 @@
#include "ShaderGLImpl.h"
#include "ShaderResourceBindingGLImpl.h"
#include "EngineMemory.h"
+#include "DeviceContextGLImpl.h"
namespace Diligent
{
@@ -36,7 +37,8 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters,
const PipelineStateDesc& PipelineDesc,
bool bIsDeviceInternal) :
TPipelineStateBase(pRefCounters, pDeviceGL, PipelineDesc, bIsDeviceInternal),
- m_GLProgram(false)
+ m_ResourceLayout (*this),
+ m_StaticResourceLayout(*this)
{
if (!m_Desc.IsComputePipeline && m_pPS == nullptr)
{
@@ -52,96 +54,78 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters,
m_ppShaders[m_NumShaders++] = m_pPS;
}
- auto &DeviceCaps = pDeviceGL->GetDeviceCaps();
+ auto& DeviceCaps = pDeviceGL->GetDeviceCaps();
VERIFY( DeviceCaps.DevType != DeviceType::Undefined, "Device caps are not initialized" );
- bool bIsProgramPipelineSupported = DeviceCaps.bSeparableProgramSupported;
- LinkGLProgram(bIsProgramPipelineSupported);
-}
+ auto pImmediateCtx = m_pDevice->GetImmediateContext();
+ VERIFY_EXPR(pImmediateCtx);
+ auto& GLState = pImmediateCtx.RawPtr<DeviceContextGLImpl>()->GetContextState();
-void PipelineStateGLImpl::LinkGLProgram(bool bIsProgramPipelineSupported)
-{
- if (bIsProgramPipelineSupported)
{
- // Program pipelines are not shared between GL contexts, so we cannot create
- // it now
- m_ShaderResourceLayoutHash = 0;
- m_StaticResources.resize(m_NumShaders);
- for (Uint32 Shader = 0; Shader < m_NumShaders; ++Shader)
+ m_TotalUniformBufferBindings = 0;
+ m_TotalSamplerBindings = 0;
+ m_TotalImageBindings = 0;
+ m_TotalStorageBufferBindings = 0;
+ if (DeviceCaps.bSeparableProgramSupported)
{
- auto* pShaderGL = GetShader<ShaderGLImpl>(Shader);
- const SHADER_RESOURCE_VARIABLE_TYPE StaticVars[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
- m_StaticResources[Shader].Clone(GetDevice(), *this, pShaderGL->GetGlProgram().GetResources(), m_Desc.ResourceLayout, StaticVars, _countof(StaticVars));
-
- const auto ShaderType = pShaderGL->GetDesc().ShaderType;
- const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType);
- m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(Shader);
-
- HashCombine(m_ShaderResourceLayoutHash, pShaderGL->m_GlProgObj.GetResources().GetHash());
+ // Program pipelines are not shared between GL contexts, so we cannot create
+ // it now
+ m_ShaderResourceLayoutHash = 0;
+ m_ProgramResources.resize(m_NumShaders);
+ m_GLPrograms.reserve(m_NumShaders);
+ for (Uint32 i = 0; i < m_NumShaders; ++i)
+ {
+ auto* pShaderGL = GetShader<ShaderGLImpl>(i);
+ const auto& ShaderDesc = pShaderGL->GetDesc();
+ m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(&m_ppShaders[i], 1, true));
+ 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
- {
- // Create new progam
- m_GLProgram.Create();
- for (Uint32 Shader = 0; Shader < m_NumShaders; ++Shader)
+ else
{
- auto* pCurrShader = GetShader<ShaderGLImpl>(Shader);
- glAttachShader(m_GLProgram, pCurrShader->m_GLShaderObj);
- CHECK_GL_ERROR("glAttachShader() failed");
- }
- glLinkProgram(m_GLProgram);
- CHECK_GL_ERROR("glLinkProgram() failed");
- int IsLinked = GL_FALSE;
- glGetProgramiv(m_GLProgram, GL_LINK_STATUS, &IsLinked);
- CHECK_GL_ERROR("glGetProgramiv() failed");
- if (!IsLinked)
- {
- int LengthWithNull = 0, Length = 0;
- // Notice that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv.
- // The length of the info log includes a null terminator.
- glGetProgramiv(m_GLProgram, GL_INFO_LOG_LENGTH, &LengthWithNull);
-
- // The maxLength includes the NULL character
- std::vector<char> shaderProgramInfoLog(LengthWithNull);
-
- // Notice that glGetProgramInfoLog is used, not glGetShaderInfoLog.
- glGetProgramInfoLog(m_GLProgram, LengthWithNull, &Length, shaderProgramInfoLog.data());
- VERIFY(Length == LengthWithNull-1, "Incorrect program info log len");
- LOG_ERROR_MESSAGE("Failed to link shader program:\n", shaderProgramInfoLog.data(), '\n');
- UNEXPECTED("glLinkProgram failed");
- }
-
- // Detach shaders from the program object
- for (Uint32 Shader = 0; Shader < m_NumShaders; ++Shader)
- {
- auto* pCurrShader = GetShader<ShaderGLImpl>(Shader);
- glDetachShader(m_GLProgram, pCurrShader->m_GLShaderObj);
- CHECK_GL_ERROR("glDetachShader() failed");
+ m_GLPrograms.emplace_back(ShaderGLImpl::LinkProgram(m_ppShaders, m_NumShaders, false));
+ m_ProgramResources.resize(1);
+ SHADER_TYPE ShaderStages = SHADER_TYPE_UNKNOWN;
+ for (Uint32 i = 0; i < m_NumShaders; ++i)
+ {
+ const auto& ShaderDesc = m_ppShaders[i]->GetDesc();
+ ShaderStages |= ShaderDesc.ShaderType;
+ }
+ m_ProgramResources[0].LoadUniforms(ShaderStages, m_GLPrograms[0], GLState,
+ m_TotalUniformBufferBindings,
+ m_TotalSamplerBindings,
+ m_TotalImageBindings,
+ m_TotalStorageBufferBindings);
+
+ m_ShaderResourceLayoutHash = m_ProgramResources[0].GetHash();
}
- SHADER_TYPE ShaderStages = SHADER_TYPE_UNKNOWN;
- for (Uint32 Shader = 0; Shader < m_NumShaders; ++Shader)
- {
- auto* pCurrShader = GetShader<ShaderGLImpl>(Shader);
- const auto& Desc = pCurrShader->GetDesc();
- ShaderStages |= Desc.ShaderType;
- }
+ m_ResourceLayout.Initialize(m_ProgramResources.data(), static_cast<Uint32>(m_GLPrograms.size()), m_Desc.ResourceLayout, nullptr, 0, nullptr);
+ }
+
+ m_StaticSamplers.resize(m_Desc.ResourceLayout.NumStaticSamplers);
+ for (Uint32 s=0; s < m_Desc.ResourceLayout.NumStaticSamplers; ++s)
+ {
+ pDeviceGL->CreateSampler(m_Desc.ResourceLayout.StaticSamplers[s].Desc, &m_StaticSamplers[s]);
+ }
- auto pDeviceGL = GetDevice();
- m_GLProgram.InitResources(pDeviceGL, ShaderStages, *this);
-
- m_StaticResources.resize(1);
+ {
const SHADER_RESOURCE_VARIABLE_TYPE StaticVars[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
- m_StaticResources[0].Clone(GetDevice(), *this, m_GLProgram.GetResources(), m_Desc.ResourceLayout, StaticVars, _countof(StaticVars));
-
- m_ShaderResourceLayoutHash = m_GLProgram.GetResources().GetHash();
- }
+ m_StaticResourceLayout.Initialize(m_ProgramResources.data(), static_cast<Uint32>(m_GLPrograms.size()), m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache);
+ InitStaticSamplersInResourceCache(m_StaticResourceLayout, m_StaticResourceCache);
+ }
}
PipelineStateGLImpl::~PipelineStateGLImpl()
{
+ m_StaticResourceCache.Destroy(GetRawAllocator());
GetDevice()->OnDestroyPSO(this);
}
@@ -152,7 +136,7 @@ void PipelineStateGLImpl::CreateShaderResourceBinding(IShaderResourceBinding** p
{
auto* pRenderDeviceGL = GetDevice();
auto& SRBAllocator = pRenderDeviceGL->GetSRBAllocator();
- auto pResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this);
+ auto pResBinding = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingGLImpl instance", ShaderResourceBindingGLImpl)(this, m_ProgramResources.data(), static_cast<Uint32>(m_ProgramResources.size()));
if (InitStaticResources)
pResBinding->InitializeStaticResources(this);
pResBinding->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
@@ -169,13 +153,43 @@ bool PipelineStateGLImpl::IsCompatibleWith(const IPipelineState* pPSO)const
if (m_ShaderResourceLayoutHash != pPSOGL->m_ShaderResourceLayoutHash)
return false;
- return m_GLProgram.GetResources().IsCompatibleWith(pPSOGL->m_GLProgram.GetResources());
+ if (m_ProgramResources.size() != pPSOGL->m_ProgramResources.size())
+ return false;
+
+ for (size_t i=0; i < m_ProgramResources.size(); ++i)
+ {
+ if (!m_ProgramResources[i].IsCompatibleWith(pPSOGL->m_ProgramResources[i]))
+ return false;
+ }
+
+ return true;
+}
+
+void PipelineStateGLImpl::CommitProgram(GLContextState& State)
+{
+ auto ProgramPipelineSupported = m_pDevice->GetDeviceCaps().bSeparableProgramSupported;
+
+ if (ProgramPipelineSupported)
+ {
+ // 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!
+ // So make sure that glUseProgram(0) has been called if pipeline is in use
+ State.SetProgram(GLObjectWrappers::GLProgramObj{false});
+ auto& Pipeline = GetGLProgramPipeline(State.GetCurrentGLContext());
+ VERIFY(Pipeline != 0, "Program pipeline must not be null");
+ State.SetPipeline( Pipeline );
+ }
+ else
+ {
+ VERIFY_EXPR(m_GLPrograms.size() == 1);
+ State.SetProgram(m_GLPrograms[0]);
+ }
}
GLObjectWrappers::GLPipelineObj& PipelineStateGLImpl::GetGLProgramPipeline(GLContext::NativeGLContextType Context)
{
ThreadingTools::LockHelper Lock(m_ProgPipelineLockFlag);
- for(auto& ctx_pipeline : m_GLProgPipelines)
+ for (auto& ctx_pipeline : m_GLProgPipelines)
{
if (ctx_pipeline.first == Context)
return ctx_pipeline.second;
@@ -185,66 +199,57 @@ GLObjectWrappers::GLPipelineObj& PipelineStateGLImpl::GetGLProgramPipeline(GLCon
m_GLProgPipelines.emplace_back(Context, true);
auto& ctx_pipeline = m_GLProgPipelines.back();
GLuint Pipeline = ctx_pipeline.second;
- for (Uint32 Shader = 0; Shader < m_NumShaders; ++Shader)
+ for (Uint32 i = 0; i < m_NumShaders; ++i)
{
- auto* pCurrShader = GetShader<ShaderGLImpl>(Shader);
+ auto* pCurrShader = GetShader<ShaderGLImpl>(i);
auto GLShaderBit = ShaderTypeToGLShaderBit(pCurrShader->GetDesc().ShaderType);
// If the program has an active code for each stage mentioned in set flags,
// then that code will be used by the pipeline. If program is 0, then the given
// stages are cleared from the pipeline.
- glUseProgramStages(Pipeline, GLShaderBit, pCurrShader->m_GlProgObj);
+ glUseProgramStages(Pipeline, GLShaderBit, m_GLPrograms[i]);
CHECK_GL_ERROR("glUseProgramStages() failed");
}
return ctx_pipeline.second;
}
+void PipelineStateGLImpl::InitializeSRBResourceCache(GLProgramResourceCache& ResourceCache)const
+{
+ ResourceCache.Initialize(m_TotalUniformBufferBindings, m_TotalSamplerBindings, m_TotalImageBindings, m_TotalStorageBufferBindings, GetRawAllocator());
+ InitStaticSamplersInResourceCache(m_ResourceLayout, ResourceCache);
+}
-void PipelineStateGLImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags)
+void PipelineStateGLImpl::InitStaticSamplersInResourceCache(const GLPipelineResourceLayout& ResourceLayout, GLProgramResourceCache& Cache)const
{
- for(auto& StaticRes : m_StaticResources)
+ for (Uint32 s=0; s < ResourceLayout.GetNumResources<GLPipelineResourceLayout::SamplerBindInfo>(); ++s)
{
- if ((StaticRes.GetShaderStages() & ShaderFlags)!=0)
- StaticRes.BindResources(pResourceMapping, Flags);
+ const auto& Sam = ResourceLayout.GetConstResource<GLPipelineResourceLayout::SamplerBindInfo>(s);
+ if (Sam.m_StaticSamplerIdx >= 0)
+ {
+ ISampler* pSampler = m_StaticSamplers[Sam.m_StaticSamplerIdx].RawPtr<ISampler>();
+ for (Uint32 binding = Sam.m_Attribs.Binding; binding < Sam.m_Attribs.Binding + Sam.m_Attribs.ArraySize; ++binding)
+ Cache.SetStaticSampler(binding, pSampler);
+ }
}
}
+
+void PipelineStateGLImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags)
+{
+ m_StaticResourceLayout.BindResources(static_cast<SHADER_TYPE>(ShaderFlags), pResourceMapping, Flags, m_StaticResourceCache);
+}
Uint32 PipelineStateGLImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const
{
- if (m_GLProgram)
- {
- return (m_StaticResources[0].GetShaderStages() & ShaderType) != 0 ? m_StaticResources[0].GetVariableCount() : 0;
- }
- else
- {
- const auto LayoutInd = m_ResourceLayoutIndex[GetShaderTypeIndex(ShaderType)];
- return LayoutInd >= 0 ? m_StaticResources[LayoutInd].GetVariableCount() : 0;
- }
+ return m_StaticResourceLayout.GetNumVariables(ShaderType);
}
IShaderResourceVariable* PipelineStateGLImpl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name)
{
- if (m_GLProgram)
- {
- return (m_StaticResources[0].GetShaderStages() & ShaderType) != 0 ? m_StaticResources[0].GetVariable(Name) : nullptr;
- }
- else
- {
- const auto LayoutInd = m_ResourceLayoutIndex[GetShaderTypeIndex(ShaderType)];
- return LayoutInd >= 0 ? m_StaticResources[LayoutInd].GetVariable(Name) : nullptr;
- }
+ return m_StaticResourceLayout.GetShaderVariable(ShaderType, Name);
}
IShaderResourceVariable* PipelineStateGLImpl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index)
{
- if (m_GLProgram)
- {
- return (m_StaticResources[0].GetShaderStages() & ShaderType) != 0 ? m_StaticResources[0].GetVariable(Index) : nullptr;
- }
- else
- {
- const auto LayoutInd = m_ResourceLayoutIndex[GetShaderTypeIndex(ShaderType)];
- return LayoutInd >= 0 ? m_StaticResources[LayoutInd].GetVariable(Index) : nullptr;
- }
+ return m_StaticResourceLayout.GetShaderVariable(ShaderType, Index);
}
}
diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp
index 61ad6dcb..26413796 100644
--- a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp
@@ -25,6 +25,7 @@
#include "ShaderGLImpl.h"
#include "RenderDeviceGLImpl.h"
+#include "DeviceContextGLImpl.h"
#include "DataBlobImpl.h"
#include "GLSLSourceBuilder.h"
@@ -38,8 +39,7 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters,
const ShaderCreateInfo& CreationAttribs,
bool bIsDeviceInternal) :
TShaderBase( pRefCounters, pDeviceGL, CreationAttribs.Desc, bIsDeviceInternal ),
- m_GlProgObj(false),
- m_GLShaderObj( false, GLObjectWrappers::GLShaderObjCreateReleaseHelper( GetGLShaderType( m_Desc.ShaderType ) ) )
+ m_GLShaderObj(true, GLObjectWrappers::GLShaderObjCreateReleaseHelper( GetGLShaderType( m_Desc.ShaderType ) ))
{
auto GLSLSource = BuildGLSLSourceString(CreationAttribs, pDeviceGL->GetDeviceCaps(), TargetGLSLCompiler::driver);
@@ -53,34 +53,31 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters,
// glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
// The log can then be queried in the same way
- // Create empty shader object
- auto GLShaderType = GetGLShaderType(m_Desc.ShaderType);
- GLObjectWrappers::GLShaderObj ShaderObj(true, GLObjectWrappers::GLShaderObjCreateReleaseHelper(GLShaderType));
// Each element in the length array may contain the length of the corresponding string
// (the null character is not counted as part of the string length).
// Not specifying lengths causes shader compilation errors on Android
- const char * ShaderStrings[] = { GLSLSource.c_str() };
+ const char* ShaderStrings[] = { GLSLSource.c_str() };
GLint Lenghts[] = { static_cast<GLint>(GLSLSource.length()) };
// Provide source strings (the strings will be saved in internal OpenGL memory)
- glShaderSource(ShaderObj, _countof(ShaderStrings), ShaderStrings, Lenghts );
+ glShaderSource(m_GLShaderObj, _countof(ShaderStrings), ShaderStrings, Lenghts );
// When the shader is compiled, it will be compiled as if all of the given strings were concatenated end-to-end.
- glCompileShader(ShaderObj);
+ glCompileShader(m_GLShaderObj);
GLint compiled = GL_FALSE;
// Get compilation status
- glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &compiled);
+ glGetShaderiv(m_GLShaderObj, GL_COMPILE_STATUS, &compiled);
if(!compiled)
{
std::string FullSource;
- for(const auto *str : ShaderStrings)
+ for(const auto* str : ShaderStrings)
FullSource.append(str);
std::stringstream ErrorMsgSS;
- ErrorMsgSS << "Failed to compile shader file \""<< (CreationAttribs.Desc.Name != nullptr ? CreationAttribs.Desc.Name : "") << '\"' << std::endl;
+ ErrorMsgSS << "Failed to compile shader file '"<< (CreationAttribs.Desc.Name != nullptr ? CreationAttribs.Desc.Name : "") << '\'' << std::endl;
int infoLogLen = 0;
// The function glGetShaderiv() tells how many bytes to allocate; the length includes the NULL terminator.
- glGetShaderiv(ShaderObj, GL_INFO_LOG_LENGTH, &infoLogLen);
+ glGetShaderiv(m_GLShaderObj, GL_INFO_LOG_LENGTH, &infoLogLen);
std::vector<GLchar> infoLog(infoLogLen);
if (infoLogLen > 0)
@@ -89,7 +86,7 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters,
// Get the log. infoLogLen is the size of infoLog. This tells OpenGL how many bytes at maximum it will write
// charsWritten is a return value, specifying how many bytes it actually wrote. One may pass NULL if he
// doesn't care
- glGetShaderInfoLog(ShaderObj, infoLogLen, &charsWritten, infoLog.data());
+ glGetShaderInfoLog(m_GLShaderObj, infoLogLen, &charsWritten, infoLog.data());
VERIFY(charsWritten == infoLogLen-1, "Unexpected info log length");
ErrorMsgSS << "InfoLog:" << std::endl << infoLog.data() << std::endl;
}
@@ -113,58 +110,18 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters* pRefCounters,
LOG_ERROR_AND_THROW(ErrorMsgSS.str().c_str());
}
- auto DeviceCaps = pDeviceGL->GetDeviceCaps();
- if( DeviceCaps.bSeparableProgramSupported )
+ if (pDeviceGL->GetDeviceCaps().bSeparableProgramSupported)
{
- m_GlProgObj.Create();
-
- // GL_PROGRAM_SEPARABLE parameter must be set before linking!
- glProgramParameteri( m_GlProgObj, GL_PROGRAM_SEPARABLE, GL_TRUE );
- glAttachShader( m_GlProgObj, ShaderObj );
- //With separable program objects, interfaces between shader stages may
- //involve the outputs from one program object and the inputs from a
- //second program object. For such interfaces, it is not possible to
- //detect mismatches at link time, because the programs are linked
- //separately. When each such program is linked, all inputs or outputs
- //interfacing with another program stage are treated as active. The
- //linker will generate an executable that assumes the presence of a
- //compatible program on the other side of the interface. If a mismatch
- //between programs occurs, no GL error will be generated, but some or all
- //of the inputs on the interface will be undefined.
- glLinkProgram( m_GlProgObj );
- CHECK_GL_ERROR( "glLinkProgram() failed" );
- int IsLinked = GL_FALSE;
- glGetProgramiv( m_GlProgObj, GL_LINK_STATUS, (int *)&IsLinked );
- CHECK_GL_ERROR( "glGetProgramiv() failed" );
- if( !IsLinked )
- {
- int LengthWithNull = 0, Length = 0;
- // Notice that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv.
- // The length of the info log includes a null terminator.
- glGetProgramiv( m_GlProgObj, GL_INFO_LOG_LENGTH, &LengthWithNull );
-
- // The maxLength includes the NULL character
- std::vector<char> shaderProgramInfoLog( LengthWithNull );
-
- // Notice that glGetProgramInfoLog is used, not glGetShaderInfoLog.
- glGetProgramInfoLog( m_GlProgObj, LengthWithNull, &Length, &shaderProgramInfoLog[0] );
- VERIFY( Length == LengthWithNull-1, "Incorrect program info log len" );
- LOG_ERROR_AND_THROW( "Failed to link shader program:\n", &shaderProgramInfoLog[0], '\n');
- }
-
- glDetachShader( m_GlProgObj, ShaderObj );
-
- // glDeleteShader() deletes the shader immediately if it is not attached to any program
- // object. Otherwise, the shader is flagged for deletion and will be deleted when it is
- // no longer attached to any program object. If an object is flagged for deletion, its
- // boolean status bit DELETE_STATUS is set to true
- ShaderObj.Release();
-
- m_GlProgObj.InitResources(pDeviceGL, m_Desc.ShaderType, *this);
- }
- else
- {
- m_GLShaderObj = std::move( ShaderObj );
+ IShader* 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();
+ VERIFY_EXPR(pImmediateCtx);
+ auto& GLState = pImmediateCtx.RawPtr<DeviceContextGLImpl>()->GetContextState();
+ m_Resources.LoadUniforms(m_Desc.ShaderType, Program, GLState, UniformBufferBinding, SamplerBinding, ImageBinding, StorageBufferBinding);
}
}
@@ -174,27 +131,86 @@ ShaderGLImpl::~ShaderGLImpl()
IMPLEMENT_QUERY_INTERFACE( ShaderGLImpl, IID_ShaderGL, TShaderBase )
+
+GLObjectWrappers::GLProgramObj ShaderGLImpl::LinkProgram(IShader** ppShaders, Uint32 NumShaders, bool IsSeparableProgram)
+{
+ VERIFY(!IsSeparableProgram || NumShaders == 1, "Number of shaders must be 1 when separable program is created");
+
+ GLObjectWrappers::GLProgramObj GLProg(true);
+
+ // GL_PROGRAM_SEPARABLE parameter must be set before linking!
+ if (IsSeparableProgram)
+ glProgramParameteri(GLProg, GL_PROGRAM_SEPARABLE, GL_TRUE);
+
+ for (Uint32 i = 0; i < NumShaders; ++i)
+ {
+ auto* pCurrShader = ValidatedCast<ShaderGLImpl>(ppShaders[i]);
+ glAttachShader(GLProg, pCurrShader->m_GLShaderObj);
+ CHECK_GL_ERROR("glAttachShader() failed");
+ }
+
+ //With separable program objects, interfaces between shader stages may
+ //involve the outputs from one program object and the inputs from a
+ //second program object. For such interfaces, it is not possible to
+ //detect mismatches at link time, because the programs are linked
+ //separately. When each such program is linked, all inputs or outputs
+ //interfacing with another program stage are treated as active. The
+ //linker will generate an executable that assumes the presence of a
+ //compatible program on the other side of the interface. If a mismatch
+ //between programs occurs, no GL error will be generated, but some or all
+ //of the inputs on the interface will be undefined.
+ glLinkProgram(GLProg);
+ CHECK_GL_ERROR("glLinkProgram() failed");
+ int IsLinked = GL_FALSE;
+ glGetProgramiv(GLProg, GL_LINK_STATUS, &IsLinked);
+ CHECK_GL_ERROR("glGetProgramiv() failed");
+ if (!IsLinked)
+ {
+ int LengthWithNull = 0, Length = 0;
+ // Notice that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv.
+ // The length of the info log includes a null terminator.
+ glGetProgramiv(GLProg, GL_INFO_LOG_LENGTH, &LengthWithNull);
+
+ // The maxLength includes the NULL character
+ std::vector<char> shaderProgramInfoLog(LengthWithNull);
+
+ // Notice that glGetProgramInfoLog is used, not glGetShaderInfoLog.
+ glGetProgramInfoLog(GLProg, LengthWithNull, &Length, shaderProgramInfoLog.data());
+ VERIFY(Length == LengthWithNull-1, "Incorrect program info log len");
+ LOG_ERROR_MESSAGE("Failed to link shader program:\n", shaderProgramInfoLog.data(), '\n');
+ UNEXPECTED("glLinkProgram failed");
+ }
+
+ for (Uint32 i = 0; i < NumShaders; ++i)
+ {
+ auto* pCurrShader = ValidatedCast<ShaderGLImpl>(ppShaders[i]);
+ glDetachShader(GLProg, pCurrShader->m_GLShaderObj);
+ CHECK_GL_ERROR("glDetachShader() failed");
+ }
+
+ return GLProg;
+}
+
Uint32 ShaderGLImpl::GetResourceCount()const
{
- Uint32 ResCount = 0;
- if (m_GlProgObj)
+ if (m_pDevice->GetDeviceCaps().bSeparableProgramSupported)
{
- return m_GlProgObj.GetResources().GetVariableCount();
+ return m_Resources.GetVariableCount();
}
else
{
LOG_WARNING_MESSAGE("Shader resource queries are not available when separate shader objects are unsupported");
+ return 0;
}
- return ResCount;
}
ShaderResourceDesc ShaderGLImpl::GetResource(Uint32 Index)const
{
ShaderResourceDesc ResourceDesc;
- if (m_GlProgObj)
+ if (m_pDevice->GetDeviceCaps().bSeparableProgramSupported)
{
DEV_CHECK_ERR(Index < GetResourceCount(), "Index is out of range");
- ResourceDesc = m_GlProgObj.GetResources().GetVariable(Index)->GetResourceDesc();
+ ResourceDesc = m_Resources.GetResourceDesc(Index);
}
else
{
diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp
index 63b7e40f..bcc2482a 100644
--- a/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/ShaderResourceBindingGLImpl.cpp
@@ -30,89 +30,48 @@
namespace Diligent
{
-ShaderResourceBindingGLImpl::ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters, PipelineStateGLImpl* pPSO) :
+ShaderResourceBindingGLImpl::ShaderResourceBindingGLImpl(IReferenceCounters* pRefCounters,
+ PipelineStateGLImpl* pPSO,
+ GLProgramResources* ProgramResources,
+ Uint32 NumPrograms) :
TBase (pRefCounters, pPSO),
- m_Resources(pPSO->GetGLProgram() == 0 ? pPSO->GetNumShaders() : 1)
+ m_ResourceLayout(*this)
{
+ pPSO->InitializeSRBResourceCache(m_ResourceCache);
+
const SHADER_RESOURCE_VARIABLE_TYPE SRBVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
- if (IsUsingSeparatePrograms())
- {
- for (Uint32 s = 0; s < pPSO->GetNumShaders(); ++s)
- {
- auto* pShaderGL = pPSO->GetShader<ShaderGLImpl>(s);
- m_Resources[s].Clone(pPSO->GetDevice(), *this, pShaderGL->GetGlProgram().GetResources(), pPSO->GetDesc().ResourceLayout, SRBVarTypes, _countof(SRBVarTypes));
- const auto ShaderType = pShaderGL->GetDesc().ShaderType;
- const auto ShaderTypeInd = GetShaderTypeIndex(ShaderType);
- m_ResourceIndex[ShaderTypeInd] = static_cast<Int8>(s);
- }
- }
- else
- {
- m_Resources[0].Clone(pPSO->GetDevice(), *this, pPSO->GetGLProgram().GetResources(), pPSO->GetDesc().ResourceLayout, SRBVarTypes, _countof(SRBVarTypes));
- }
+ const auto& ResourceLayout = pPSO->GetDesc().ResourceLayout;
+ m_ResourceLayout.Initialize(ProgramResources, NumPrograms, ResourceLayout, SRBVarTypes, _countof(SRBVarTypes), &m_ResourceCache);
}
ShaderResourceBindingGLImpl::~ShaderResourceBindingGLImpl()
{
+ m_ResourceCache.Destroy(GetRawAllocator());
}
IMPLEMENT_QUERY_INTERFACE(ShaderResourceBindingGLImpl, IID_ShaderResourceBindingGL, TBase)
-bool ShaderResourceBindingGLImpl::IsUsingSeparatePrograms()const
-{
- return GetPipelineState<PipelineStateGLImpl>()->GetGLProgram() == 0;
-}
-
void ShaderResourceBindingGLImpl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags)
{
- for(auto& Resource : m_Resources)
- {
- if ((Resource.GetShaderStages() & ShaderFlags)!=0)
- Resource.BindResources(pResMapping, Flags);
- }
+ m_ResourceLayout.BindResources(static_cast<SHADER_TYPE>(ShaderFlags), pResMapping, Flags, m_ResourceCache);
}
IShaderResourceVariable* ShaderResourceBindingGLImpl::GetVariableByName(SHADER_TYPE ShaderType, const char* Name)
{
- if (IsUsingSeparatePrograms())
- {
- auto ShaderInd = m_ResourceIndex[GetShaderTypeIndex(ShaderType)];
- return ShaderInd >= 0 ? m_Resources[ShaderInd].GetVariable(Name) : nullptr;
- }
- else
- {
- return (m_Resources[0].GetShaderStages() & ShaderType) != 0 ? m_Resources[0].GetVariable(Name) : nullptr;
- }
+ return m_ResourceLayout.GetShaderVariable(ShaderType, Name);
}
Uint32 ShaderResourceBindingGLImpl::GetVariableCount(SHADER_TYPE ShaderType) const
{
- if (IsUsingSeparatePrograms())
- {
- auto ShaderInd = m_ResourceIndex[GetShaderTypeIndex(ShaderType)];
- return ShaderInd >= 0 ? m_Resources[ShaderInd].GetVariableCount() : 0;
- }
- else
- {
- return (m_Resources[0].GetShaderStages() & ShaderType) != 0 ? m_Resources[0].GetVariableCount() : 0;
- }
+ return m_ResourceLayout.GetNumVariables(ShaderType);
}
IShaderResourceVariable* ShaderResourceBindingGLImpl::GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index)
{
- if (IsUsingSeparatePrograms())
- {
- auto ShaderInd = m_ResourceIndex[GetShaderTypeIndex(ShaderType)];
- return ShaderInd >= 0 ? m_Resources[ShaderInd].GetVariable(Index) : 0;
- }
- else
- {
- return (m_Resources[0].GetShaderStages() & ShaderType) != 0 ? m_Resources[0].GetVariable(Index) : nullptr;
- }
+ return m_ResourceLayout.GetShaderVariable(ShaderType, Index);
}
-static GLProgramResources NullProgramResources;
-GLProgramResources& ShaderResourceBindingGLImpl::GetResources(Uint32 Ind, PipelineStateGLImpl* pdbgPSO)
+const GLProgramResourceCache& ShaderResourceBindingGLImpl::GetResourceCache(PipelineStateGLImpl* pdbgPSO)
{
#ifdef _DEBUG
if (pdbgPSO->IsIncompatibleWith(GetPipelineState()))
@@ -120,12 +79,41 @@ GLProgramResources& ShaderResourceBindingGLImpl::GetResources(Uint32 Ind, Pipeli
LOG_ERROR("Shader resource binding is incompatible with the currently bound pipeline state.");
}
#endif
- return m_Resources[Ind];
+ return m_ResourceCache;
}
void ShaderResourceBindingGLImpl::InitializeStaticResources(const IPipelineState* pPipelineState)
{
- // Do nothing
+ 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 DEVELOPMENT
+ if (!StaticResLayout.dvpVerifyBindings())
+ {
+ 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;
}
}
diff --git a/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp b/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp
index 9b5c56a8..3a82b31e 100644
--- a/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/TexRegionRender.cpp
@@ -145,10 +145,10 @@ namespace Diligent
pDeviceGL->CreatePipelineState(PSODesc, &m_pPSO[Dim*3 + Fmt], IsInternalDeviceObject);
}
- m_pPSO[RESOURCE_DIM_TEX_2D*3]->CreateShaderResourceBinding(&m_pSRB);
- m_pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbConstants")->Set(m_pConstantBuffer);
- m_pSrcTexVar = m_pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "gSourceTex");
}
+ m_pPSO[RESOURCE_DIM_TEX_2D*3]->CreateShaderResourceBinding(&m_pSRB);
+ m_pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbConstants")->Set(m_pConstantBuffer);
+ m_pSrcTexVar = m_pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "gSourceTex");
}
void TexRegionRender::SetStates( DeviceContextGLImpl *pCtxGL )