diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index c66dd1a96..e6ed3e23f 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -374,7 +374,7 @@ int main() stencilPipelineInfo.stencilBack.compare = Nz::RendererComparison::Always; stencilPipelineInfo.stencilBack.depthFail = Nz::StencilOperation::Invert; - stencilPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "lighting.nzsl", {})); + stencilPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "lighting.nzsl", {})); std::shared_ptr stencilPipeline = device->InstantiateRenderPipeline(stencilPipelineInfo); diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp index c93f2e277..e39746eb0 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.hpp @@ -20,23 +20,31 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLShaderModule : public ShaderModule { public: - OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states); - OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states); + struct Shader; + + OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states = {}); + OpenGLShaderModule(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const ShaderWriter::States& states = {}); OpenGLShaderModule(const OpenGLShaderModule&) = delete; OpenGLShaderModule(OpenGLShaderModule&&) noexcept = default; ~OpenGLShaderModule() = default; - inline const std::vector& GetShaders() const; + inline const std::vector& GetShaders() const; OpenGLShaderModule& operator=(const OpenGLShaderModule&) = delete; OpenGLShaderModule& operator=(OpenGLShaderModule&&) noexcept = default; + struct Shader + { + ShaderStageType stage; + GL::Shader shader; + }; + private: void Create(OpenGLDevice& device, ShaderStageTypeFlags shaderStages, ShaderAst::StatementPtr& shaderAst, const ShaderWriter::States& states); static void CheckCompilationStatus(GL::Shader& shader); - std::vector m_shaders; + std::vector m_shaders; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl index 7cf01b6f7..afc50af68 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderModule.inl @@ -7,7 +7,7 @@ namespace Nz { - inline const std::vector& OpenGLShaderModule::GetShaders() const + inline auto OpenGLShaderModule::GetShaders() const -> const std::vector& { return m_shaders; } diff --git a/include/Nazara/Shader/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp index 394b035f1..db3f56991 100644 --- a/include/Nazara/Shader/ShaderBuilder.hpp +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -20,6 +20,7 @@ namespace Nz::ShaderBuilder struct AccessMember { inline std::unique_ptr operator()(ShaderAst::ExpressionPtr structExpr, std::vector memberIdentifiers) const; + inline std::unique_ptr operator()(ShaderAst::ExpressionPtr structExpr, std::vector memberIndices) const; }; struct Assign @@ -104,7 +105,7 @@ namespace Nz::ShaderBuilder struct Multi { - inline std::unique_ptr operator()(std::vector statements) const; + inline std::unique_ptr operator()(std::vector statements = {}) const; }; template diff --git a/include/Nazara/Shader/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl index 33227d224..867249d54 100644 --- a/include/Nazara/Shader/ShaderBuilder.inl +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -16,6 +16,15 @@ namespace Nz::ShaderBuilder return accessMemberNode; } + inline std::unique_ptr Impl::AccessMember::operator()(ShaderAst::ExpressionPtr structExpr, std::vector memberIndices) const + { + auto accessMemberNode = std::make_unique(); + accessMemberNode->structExpr = std::move(structExpr); + accessMemberNode->memberIndices = std::move(memberIndices); + + return accessMemberNode; + } + inline std::unique_ptr Impl::Assign::operator()(ShaderAst::AssignType op, ShaderAst::ExpressionPtr left, ShaderAst::ExpressionPtr right) const { auto assignNode = std::make_unique(); diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp index cda8d32f1..639104c0d 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,11 +22,37 @@ namespace Nz if (!m_program.Create(device)) throw std::runtime_error("failed to create program"); + ShaderStageTypeFlags stageFlags; + for (const auto& shaderModulePtr : m_pipelineInfo.shaderModules) { OpenGLShaderModule& shaderModule = static_cast(*shaderModulePtr); - for (const GL::Shader& shader : shaderModule.GetShaders()) - m_program.AttachShader(shader.GetObjectId()); + for (const auto& shaderEntry : shaderModule.GetShaders()) + { + m_program.AttachShader(shaderEntry.shader.GetObjectId()); + stageFlags |= shaderEntry.stage; + } + } + + // OpenGL ES programs must have both vertex and fragment shaders or a compute shader or a mesh and fragment shader. + if (device.GetReferenceContext().GetParams().type == GL::ContextType::OpenGL_ES) + { + auto GenerateIfMissing = [&](ShaderStageType stage) + { + if (!stageFlags.Test(stage)) + { + ShaderAst::StatementPtr dummyAst = ShaderBuilder::DeclareFunction(stage, "main", {}, {}); + OpenGLShaderModule shaderModule(device, stage, dummyAst); + for (const auto& shaderEntry : shaderModule.GetShaders()) + { + m_program.AttachShader(shaderEntry.shader.GetObjectId()); + stageFlags |= shaderEntry.stage; + } + } + }; + + GenerateIfMissing(ShaderStageType::Fragment); + GenerateIfMissing(ShaderStageType::Vertex); } m_program.Link(); diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp index ccf311edd..25a579766 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp @@ -44,7 +44,9 @@ namespace Nz shader.Compile(); CheckCompilationStatus(shader); - m_shaders.emplace_back(std::move(shader)); + auto& entry = m_shaders.emplace_back(); + entry.shader = std::move(shader); + entry.stage = shaderStage; break; } } @@ -130,7 +132,9 @@ namespace Nz CheckCompilationStatus(shader); - m_shaders.emplace_back(std::move(shader)); + auto& entry = m_shaders.emplace_back(); + entry.shader = std::move(shader); + entry.stage = shaderStage; } } }