diff --git a/include/Nazara/Shader/Ast/AstReflect.hpp b/include/Nazara/Shader/Ast/AstReflect.hpp new file mode 100644 index 000000000..3ee91f524 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstReflect.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_AST_REFLECT_HPP +#define NAZARA_SHADER_AST_REFLECT_HPP + +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_SHADER_API AstReflect : public AstRecursiveVisitor + { + public: + struct Callbacks; + + AstReflect() = default; + AstReflect(const AstReflect&) = delete; + AstReflect(AstReflect&&) = delete; + ~AstReflect() = default; + + void Reflect(const StatementPtr& statement, const Callbacks& callbacks); + + AstReflect& operator=(const AstReflect&) = delete; + AstReflect& operator=(AstReflect&&) = delete; + + struct Callbacks + { + std::function onOptionDeclaration; + }; + + private: + void Visit(DeclareOptionStatement& node) override; + + const Callbacks* m_callbacks; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/Ast/AstReflect.inl b/include/Nazara/Shader/Ast/AstReflect.inl new file mode 100644 index 000000000..c9fe65d86 --- /dev/null +++ b/include/Nazara/Shader/Ast/AstReflect.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ +} + +#include diff --git a/src/Nazara/Graphics/UberShader.cpp b/src/Nazara/Graphics/UberShader.cpp index 9ecbb888f..dfdc22848 100644 --- a/src/Nazara/Graphics/UberShader.cpp +++ b/src/Nazara/Graphics/UberShader.cpp @@ -5,34 +5,49 @@ #include #include #include +#include +#include #include #include #include namespace Nz { - UberShader::UberShader(ShaderStageType shaderStage, ShaderAst::StatementPtr shaderAst) : - m_shaderAst(std::move(shaderAst)), + UberShader::UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst) : m_shaderStage(shaderStage) { - //std::size_t conditionCount = m_shaderAst.GetConditionCount(); - std::size_t conditionCount = 0; + ShaderAst::SanitizeVisitor::Options options; + options.removeOptionDeclaration = false; - if (conditionCount >= 64) + m_shaderAst = ShaderAst::Sanitize(shaderAst, options); + + std::size_t optionCount = 0; + + ShaderAst::AstReflect::Callbacks callbacks; + callbacks.onOptionDeclaration = [&](const std::string& optionName, const ShaderAst::ExpressionType& optionType) + { + m_optionIndexByName[optionName] = optionCount; + optionCount++; + }; + + ShaderAst::AstReflect reflect; + reflect.Reflect(m_shaderAst, callbacks); + + if (optionCount >= 64) throw std::runtime_error("Too many conditions"); m_combinationMask = std::numeric_limits::max(); - m_combinationMask <<= conditionCount; + m_combinationMask <<= optionCount; m_combinationMask = ~m_combinationMask; } - UInt64 UberShader::GetConditionFlagByName(const std::string_view& condition) const + UInt64 UberShader::GetOptionFlagByName(const std::string& optionName) const { - /*std::size_t conditionIndex = m_shaderAst.FindConditionByName(condition); - if (conditionIndex != ShaderAst::InvalidCondition) - return SetBit(0, conditionIndex); - else*/ + auto it = m_optionIndexByName.find(optionName); + if (it == m_optionIndexByName.end()) return 0; + + return SetBit(0, it->second); } const std::shared_ptr& UberShader::Get(UInt64 combination) @@ -44,6 +59,7 @@ namespace Nz { ShaderWriter::States states; states.enabledOptions = combination; + states.sanitized = true; std::shared_ptr stage = Graphics::Instance()->GetRenderDevice().InstantiateShaderModule(m_shaderStage, m_shaderAst, std::move(states)); diff --git a/src/Nazara/Shader/Ast/AstReflect.cpp b/src/Nazara/Shader/Ast/AstReflect.cpp new file mode 100644 index 000000000..350e0484f --- /dev/null +++ b/src/Nazara/Shader/Ast/AstReflect.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz::ShaderAst +{ + void AstReflect::Reflect(const StatementPtr& statement, const Callbacks& callbacks) + { + assert(statement); + + m_callbacks = &callbacks; + statement->Visit(*this); + } + + void AstReflect::Visit(DeclareOptionStatement& node) + { + assert(m_callbacks); + if (m_callbacks->onOptionDeclaration) + m_callbacks->onOptionDeclaration(node.optName, node.optType); + } +} diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index 006f830a9..b1b565a02 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -113,6 +113,7 @@ namespace Nz m_currentState = nullptr; }); + // Always sanitize for reserved identifiers ShaderAst::SanitizeVisitor::Options options; options.reservedIdentifiers = { // All reserved GLSL keywords as of GLSL ES 3.2 diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 7ec5f1333..515c9aebd 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -386,7 +386,11 @@ namespace Nz std::vector SpirvWriter::Generate(ShaderAst::StatementPtr& shader, const States& states) { - ShaderAst::StatementPtr sanitizedAst = ShaderAst::Sanitize(shader); + ShaderAst::StatementPtr sanitizedAst; + if (!states.sanitized) + sanitizedAst = ShaderAst::Sanitize(shader); + + ShaderAst::StatementPtr& targetAst = (states.sanitized) ? shader : sanitizedAst; m_context.states = &states; @@ -399,7 +403,7 @@ namespace Nz // Register all extended instruction sets PreVisitor preVisitor(states, state.constantTypeCache, state.funcs); - sanitizedAst->Visit(preVisitor); + targetAst->Visit(preVisitor); m_currentState->preVisitor = &preVisitor; @@ -407,7 +411,7 @@ namespace Nz state.extensionInstructions[extInst] = AllocateResultId(); SpirvAstVisitor visitor(*this, state.instructions, state.funcs); - sanitizedAst->Visit(visitor); + targetAst->Visit(visitor); AppendHeader();