From 099528758c31053cc18490ffcde2e1ddbdc9f3d3 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Fri, 12 Aug 2022 23:01:58 +0200 Subject: [PATCH] OpenGLRenderer: Fix explicit texture/block binding (fixes GLSL ES 3.0 support) --- .../OpenGLRenderer/OpenGLShaderModule.hpp | 14 ++++++++++- .../OpenGLRenderer/OpenGLShaderModule.inl | 4 +++ .../Nazara/OpenGLRenderer/Wrapper/Program.hpp | 1 + .../Nazara/OpenGLRenderer/Wrapper/Program.inl | 9 +++++++ .../OpenGLRenderer/OpenGLRenderPipeline.cpp | 25 +++++++++++++++++-- .../OpenGLRenderer/OpenGLShaderModule.cpp | 23 ++++++++++++----- 6 files changed, 67 insertions(+), 9 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp index ca65fd2fe..3698dd2c4 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp @@ -22,17 +22,28 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLShaderModule : public ShaderModule { public: + struct ExplicitBinding; + OpenGLShaderModule(OpenGLDevice& device, nzsl::ShaderStageTypeFlags shaderStages, const nzsl::Ast::Module& shaderModule, const nzsl::ShaderWriter::States& states = {}); OpenGLShaderModule(OpenGLDevice& device, nzsl::ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const nzsl::ShaderWriter::States& states = {}); OpenGLShaderModule(const OpenGLShaderModule&) = delete; OpenGLShaderModule(OpenGLShaderModule&&) noexcept = default; ~OpenGLShaderModule() = default; - nzsl::ShaderStageTypeFlags Attach(GL::Program& program, const nzsl::GlslWriter::BindingMapping& bindingMapping) const; + nzsl::ShaderStageTypeFlags Attach(GL::Program& program, const nzsl::GlslWriter::BindingMapping& bindingMapping, std::vector* explicitBindings) const; + + inline const std::vector& GetExplicitBindings() const; OpenGLShaderModule& operator=(const OpenGLShaderModule&) = delete; OpenGLShaderModule& operator=(OpenGLShaderModule&&) noexcept = default; + struct ExplicitBinding + { + std::string name; + unsigned int binding; + bool isBlock; + }; + private: void Create(OpenGLDevice& device, nzsl::ShaderStageTypeFlags shaderStages, const nzsl::Ast::Module& shaderModule, const nzsl::ShaderWriter::States& states); @@ -56,6 +67,7 @@ namespace Nz OpenGLDevice& m_device; nzsl::ShaderWriter::States m_states; + std::vector m_explicitBindings; std::vector m_shaders; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl index 75a1d2120..c07ab9f5b 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl @@ -7,6 +7,10 @@ namespace Nz { + inline auto OpenGLShaderModule::GetExplicitBindings() const -> const std::vector& + { + return m_explicitBindings; + } } #include diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp index e6f570b94..39433f3dc 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Program.hpp @@ -44,6 +44,7 @@ namespace Nz::GL inline void Link(); inline void Uniform(GLint uniformLocation, float value) const; + inline void Uniform(GLint uniformLocation, int value) const; inline void UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const; Program& operator=(const Program&) = delete; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Program.inl b/include/Nazara/OpenGLRenderer/Wrapper/Program.inl index e5a417fb2..4b738b44c 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Program.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Program.inl @@ -203,6 +203,15 @@ namespace Nz::GL context.glUniform1f(uniformLocation, value); } + inline void Program::Uniform(GLint uniformLocation, int value) const + { + assert(m_objectId); + + const Context& context = EnsureDeviceContext(); + context.BindProgram(m_objectId); + context.glUniform1i(uniformLocation, value); + } + inline void Program::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const { assert(m_objectId); diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp index e0e9c3e70..e915826b8 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp @@ -34,11 +34,12 @@ namespace Nz activeContext->UpdateStates(m_pipelineInfo, false); nzsl::ShaderStageTypeFlags stageFlags; + std::vector explicitBindings; for (const auto& shaderModulePtr : m_pipelineInfo.shaderModules) { OpenGLShaderModule& shaderModule = static_cast(*shaderModulePtr); - stageFlags |= shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping()); + stageFlags |= shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping(), &explicitBindings); } // OpenGL ES programs must have both vertex and fragment shaders or a compute shader or a mesh and fragment shader. @@ -53,7 +54,7 @@ namespace Nz dummyModule.rootNode->statements.push_back(nzsl::ShaderBuilder::DeclareFunction(stage, "main", {}, {})); OpenGLShaderModule shaderModule(device, stage, dummyModule); - stageFlags |= shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping()); + stageFlags |= shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping(), &explicitBindings); } }; @@ -70,6 +71,26 @@ namespace Nz m_flipYUniformLocation = m_program.GetUniformLocation(nzsl::GlslWriter::GetFlipYUniformName().data()); if (m_flipYUniformLocation != -1) m_program.Uniform(m_flipYUniformLocation, 1.f); + + for (const auto& explicitBinding : explicitBindings) + { + if (explicitBinding.isBlock) + { + GLuint blockIndex = m_program.GetUniformBlockIndex(explicitBinding.name); + if (blockIndex == GL_INVALID_INDEX) + continue; + + m_program.UniformBlockBinding(blockIndex, explicitBinding.binding); + } + else + { + int location = m_program.GetUniformLocation(explicitBinding.name); + if (location == -1) + continue; + + m_program.Uniform(location, static_cast(explicitBinding.binding)); //< FIXME: Use SafeCast + } + } } void OpenGLRenderPipeline::Apply(const GL::Context& context, bool flipViewport) const diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp index e3b5fe589..cedc2f35e 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp @@ -83,7 +83,7 @@ namespace Nz } } - nzsl::ShaderStageTypeFlags OpenGLShaderModule::Attach(GL::Program& program, const nzsl::GlslWriter::BindingMapping& bindingMapping) const + nzsl::ShaderStageTypeFlags OpenGLShaderModule::Attach(GL::Program& program, const nzsl::GlslWriter::BindingMapping& bindingMapping, std::vector* explicitBindings) const { const auto& context = m_device.GetReferenceContext(); const auto& contextParams = context.GetParams(); @@ -120,13 +120,24 @@ namespace Nz nzsl::GlslWriter::Output output = writer.Generate(shaderEntry.stage, *arg.ast, bindingMapping, m_states); shader.SetSource(output.code.data(), GLint(output.code.size())); - for (const auto& [name, bindingPoint] : output.explicitUniformBlockBinding) + if (explicitBindings) { - GLuint blockIndex = program.GetUniformBlockIndex(name); - if (blockIndex == GL_INVALID_INDEX) - continue; + explicitBindings->reserve(explicitBindings->size() + output.explicitTextureBinding.size() + output.explicitUniformBlockBinding.size()); + for (const auto& [name, bindingPoint] : output.explicitTextureBinding) + { + auto& explicitBinding = explicitBindings->emplace_back(); + explicitBinding.name = name; + explicitBinding.binding = bindingPoint; + explicitBinding.isBlock = false; + } - program.UniformBlockBinding(blockIndex, bindingPoint); + for (const auto& [name, bindingPoint] : output.explicitUniformBlockBinding) + { + auto& explicitBinding = explicitBindings->emplace_back(); + explicitBinding.name = name; + explicitBinding.binding = bindingPoint; + explicitBinding.isBlock = true; + } } } else