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