diff --git a/include/Nazara/Shader/Ast/Module.hpp b/include/Nazara/Shader/Ast/Module.hpp index a2860bca5..c77c1dde6 100644 --- a/include/Nazara/Shader/Ast/Module.hpp +++ b/include/Nazara/Shader/Ast/Module.hpp @@ -20,8 +20,13 @@ namespace Nz::ShaderAst struct Module { + struct Metadata + { + UInt32 shaderLangVersion; + }; + + std::shared_ptr metadata; MultiStatementPtr rootNode; - UInt32 shaderLangVersion; }; } diff --git a/include/Nazara/Shader/LangWriter.hpp b/include/Nazara/Shader/LangWriter.hpp index 0bcccfab9..50caae0d4 100644 --- a/include/Nazara/Shader/LangWriter.hpp +++ b/include/Nazara/Shader/LangWriter.hpp @@ -45,7 +45,6 @@ namespace Nz struct EntryAttribute; struct LayoutAttribute; struct LocationAttribute; - struct NzslAttribute; struct SetAttribute; struct UnrollAttribute; @@ -76,7 +75,6 @@ namespace Nz void AppendAttribute(EntryAttribute entry); void AppendAttribute(LayoutAttribute layout); void AppendAttribute(LocationAttribute location); - void AppendAttribute(NzslAttribute nzslVersion); void AppendAttribute(SetAttribute set); void AppendAttribute(UnrollAttribute unroll); void AppendCommentSection(const std::string& section); diff --git a/include/Nazara/Shader/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp index 3ac22688b..a37389269 100644 --- a/include/Nazara/Shader/ShaderBuilder.hpp +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -97,7 +97,7 @@ namespace Nz::ShaderBuilder struct DeclareStruct { - inline std::unique_ptr operator()(ShaderAst::StructDescription description) const; + inline std::unique_ptr operator()(ShaderAst::StructDescription description, ShaderAst::ExpressionValue isExported) const; }; struct DeclareVariable diff --git a/include/Nazara/Shader/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl index fa3ca0457..482e624ff 100644 --- a/include/Nazara/Shader/ShaderBuilder.inl +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -189,6 +189,7 @@ namespace Nz::ShaderBuilder case ShaderAst::PrimitiveType::Float32: return ShaderBuilder::Constant(SafeCast(value)); case ShaderAst::PrimitiveType::Int32: return ShaderBuilder::Constant(SafeCast(value)); case ShaderAst::PrimitiveType::UInt32: return ShaderBuilder::Constant(SafeCast(value)); + case ShaderAst::PrimitiveType::String: return ShaderBuilder::Constant(value); } throw std::runtime_error("unexpected primitive type"); @@ -269,10 +270,11 @@ namespace Nz::ShaderBuilder return declareOptionNode; } - inline std::unique_ptr Impl::DeclareStruct::operator()(ShaderAst::StructDescription description) const + inline std::unique_ptr Impl::DeclareStruct::operator()(ShaderAst::StructDescription description, ShaderAst::ExpressionValue isExported) const { auto declareStructNode = std::make_unique(); declareStructNode->description = std::move(description); + declareStructNode->isExported = std::move(isExported); return declareStructNode; } diff --git a/include/Nazara/Shader/ShaderLangParser.hpp b/include/Nazara/Shader/ShaderLangParser.hpp index b24c4184a..81360e7b0 100644 --- a/include/Nazara/Shader/ShaderLangParser.hpp +++ b/include/Nazara/Shader/ShaderLangParser.hpp @@ -82,6 +82,7 @@ namespace Nz::ShaderLang const Token& Peek(std::size_t advance = 0); std::vector ParseAttributes(); + void ParseModuleStatement(std::vector attributes); void ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue& type, ShaderAst::ExpressionPtr& initialValue); // Statements @@ -93,7 +94,6 @@ namespace Nz::ShaderLang std::vector ParseFunctionBody(); ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector attributes = {}); ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter(); - void ParseModuleStatement(std::vector attributes); ShaderAst::StatementPtr ParseOptionDeclaration(); ShaderAst::StatementPtr ParseReturnStatement(); ShaderAst::StatementPtr ParseRootStatement(std::vector attributes = {}); diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp index e60b644be..6df6b9c9b 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderPipeline.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,11 @@ namespace Nz ShaderAst::Module dummyModule; dummyModule.rootNode = ShaderBuilder::MultiStatement(); dummyModule.rootNode->statements.push_back(ShaderBuilder::DeclareFunction(stage, "main", {}, {})); - dummyModule.shaderLangVersion = 100; + + std::shared_ptr metadata = std::make_shared(); + metadata->shaderLangVersion = 100; + + dummyModule.metadata = std::move(metadata); OpenGLShaderModule shaderModule(device, stage, dummyModule); stageFlags |= shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping()); diff --git a/src/Nazara/Shader/Ast/AstSerializer.cpp b/src/Nazara/Shader/Ast/AstSerializer.cpp index 9092f4e11..70464714f 100644 --- a/src/Nazara/Shader/Ast/AstSerializer.cpp +++ b/src/Nazara/Shader/Ast/AstSerializer.cpp @@ -333,7 +333,7 @@ namespace Nz::ShaderAst { m_stream << s_magicNumber << s_currentVersion; - m_stream << module.shaderLangVersion; + m_stream << module.metadata->shaderLangVersion; Serialize(*module.rootNode); m_stream.FlushBits(); @@ -531,7 +531,10 @@ namespace Nz::ShaderAst ModulePtr module = std::make_shared(); - m_stream >> module->shaderLangVersion; + std::shared_ptr metadata = std::make_shared(); + m_stream >> metadata->shaderLangVersion; + + module->metadata = std::move(metadata); module->rootNode = ShaderBuilder::MultiStatement(); ShaderSerializerVisitor visitor(*this); diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index a469b9b33..b2582ee69 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -115,7 +115,7 @@ namespace Nz::ShaderAst ModulePtr SanitizeVisitor::Sanitize(const Module& module, const Options& options, std::string* error) { ModulePtr clone = std::make_shared(); - clone->shaderLangVersion = module.shaderLangVersion; + clone->metadata = module.metadata; Context currentContext; currentContext.options = options; diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index bab6822da..820aa0f7f 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -298,7 +298,7 @@ namespace Nz } } - void GlslWriter::Append(const ShaderAst::MethodType& methodType) + void GlslWriter::Append(const ShaderAst::MethodType& /*methodType*/) { throw std::runtime_error("unexpected method type"); } @@ -311,6 +311,7 @@ namespace Nz case ShaderAst::PrimitiveType::Float32: return Append("float"); case ShaderAst::PrimitiveType::Int32: return Append("int"); case ShaderAst::PrimitiveType::UInt32: return Append("uint"); + case ShaderAst::PrimitiveType::String: throw std::runtime_error("unexpected string constant"); } } @@ -324,6 +325,8 @@ namespace Nz case ShaderAst::PrimitiveType::Int32: Append("i"); break; case ShaderAst::PrimitiveType::UInt32: Append("u"); break; + + case ShaderAst::PrimitiveType::String: throw std::runtime_error("unexpected string type"); } Append("sampler"); @@ -363,6 +366,7 @@ namespace Nz case ShaderAst::PrimitiveType::Float32: break; case ShaderAst::PrimitiveType::Int32: Append("i"); break; case ShaderAst::PrimitiveType::UInt32: Append("u"); break; + case ShaderAst::PrimitiveType::String: throw std::runtime_error("unexpected string type"); } Append("vec"); @@ -1201,6 +1205,11 @@ namespace Nz Append(";"); } + void GlslWriter::Visit(ShaderAst::ImportStatement& /*node*/) + { + /* nothing to do */ + } + void GlslWriter::Visit(ShaderAst::MultiStatement& node) { AppendStatementList(node.statements); diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp index 10ee07690..a935b1097 100644 --- a/src/Nazara/Shader/LangWriter.cpp +++ b/src/Nazara/Shader/LangWriter.cpp @@ -75,14 +75,7 @@ namespace Nz inline bool HasValue() const { return locationIndex.HasValue(); } }; - - struct LangWriter::NzslAttribute - { - const ShaderAst::ExpressionValue& version; - - inline bool HasValue() const { return version.HasValue(); } - }; - + struct LangWriter::SetAttribute { const ShaderAst::ExpressionValue& setIndex; @@ -100,6 +93,7 @@ namespace Nz struct LangWriter::State { const States* states = nullptr; + ShaderAst::Module* module; std::stringstream stream; std::unordered_map constantNames; std::unordered_map structs; @@ -118,6 +112,7 @@ namespace Nz }); ShaderAst::ModulePtr sanitizedModule = ShaderAst::Sanitize(module); + state.module = sanitizedModule.get(); AppendHeader(); @@ -195,6 +190,7 @@ namespace Nz case ShaderAst::PrimitiveType::Float32: return Append("f32"); case ShaderAst::PrimitiveType::Int32: return Append("i32"); case ShaderAst::PrimitiveType::UInt32: return Append("u32"); + case ShaderAst::PrimitiveType::String: return Append("string"); } } @@ -459,11 +455,7 @@ namespace Nz Append(")"); } - - void LangWriter::AppendAttribute(NzslAttribute nzslVersion) - { - } - + void LangWriter::AppendAttribute(SetAttribute set) { if (!set.HasValue()) @@ -1101,6 +1093,23 @@ namespace Nz void LangWriter::AppendHeader() { - // Nothing yet + UInt32 shaderLangVersion = m_currentState->module->metadata->shaderLangVersion; + UInt32 majorVersion = shaderLangVersion / 100; + shaderLangVersion -= majorVersion * 100; + + UInt32 minorVersion = shaderLangVersion / 10; + shaderLangVersion -= minorVersion * 100; + + UInt32 patchVersion = shaderLangVersion; + + // nzsl_version + Append("[nzsl_version(\"", majorVersion, ".", minorVersion); + if (patchVersion != 0) + Append(".", patchVersion); + + AppendLine("\")]"); + + AppendLine("module;"); + AppendLine(); } } diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index ca5e498e8..8def0b884 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -230,6 +230,78 @@ namespace Nz::ShaderLang return attributes; } + void Parser::ParseModuleStatement(std::vector attributes) + { + Expect(Advance(), TokenType::Module); + + if (m_context->module) + throw DuplicateModule{ "you must set one module statement per file" }; + + std::optional moduleVersion; + + for (auto&& [attributeType, arg] : attributes) + { + switch (attributeType) + { + case ShaderAst::AttributeType::LangVersion: + { + // Version parsing + if (moduleVersion.has_value()) + throw AttributeError{ "attribute " + std::string("nzsl_version") + " must be present once" }; + + if (!arg) + throw AttributeError{ "attribute " + std::string("nzsl_version") + " requires a parameter"}; + + const ShaderAst::ExpressionPtr& expr = *arg; + if (expr->GetType() != ShaderAst::NodeType::ConstantValueExpression) + throw AttributeError{ "attribute " + std::string("nzsl_version") + " expect a single string parameter" }; + + auto& constantValue = SafeCast(*expr); + if (ShaderAst::GetExpressionType(constantValue.value) != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::String }) + throw AttributeError{ "attribute " + std::string("nzsl_version") + " expect a single string parameter" }; + + const std::string& versionStr = std::get(constantValue.value); + + std::regex versionRegex(R"(^(\d+)(\.(\d+)(\.(\d+))?)?$)", std::regex::ECMAScript); + + std::smatch versionMatch; + if (!std::regex_match(versionStr, versionMatch, versionRegex)) + throw AttributeError("invalid version for attribute nzsl"); + + assert(versionMatch.size() == 6); + + std::uint32_t version = 0; + version += std::stoi(versionMatch[1]) * 100; + + if (versionMatch.length(3) > 0) + version += std::stoi(versionMatch[3]) * 10; + + if (versionMatch.length(5) > 0) + version += std::stoi(versionMatch[5]) * 1; + + moduleVersion = version; + break; + } + + default: + throw AttributeError{ "unhandled attribute for module" }; + } + } + + if (!moduleVersion.has_value()) + throw AttributeError{ "missing module version" }; + + m_context->module = std::make_shared(); + m_context->module->rootNode = ShaderBuilder::MultiStatement(); + + std::shared_ptr moduleMetadata = std::make_shared(); + moduleMetadata->shaderLangVersion = *moduleVersion; + + m_context->module->metadata = std::move(moduleMetadata); + + Expect(Advance(), TokenType::Semicolon); + } + void Parser::ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue& type, ShaderAst::ExpressionPtr& initialValue) { name = ParseIdentifierAsName(); @@ -564,71 +636,13 @@ namespace Nz::ShaderLang return { parameterName, std::move(parameterType) }; } - void Parser::ParseModuleStatement(std::vector attributes) { - Expect(Advance(), TokenType::Module); - if (m_context->module) - throw DuplicateModule{ "you must set one module statement per file" }; - std::optional moduleVersion; - - for (auto&& [attributeType, arg] : attributes) { - switch (attributeType) - { - case ShaderAst::AttributeType::LangVersion: - { - // Version parsing - if (moduleVersion.has_value()) - throw AttributeError{ "attribute " + std::string("nzsl_version") + " must be present once" }; - if (!arg) - throw AttributeError{ "attribute " + std::string("nzsl_version") + " requires a parameter"}; - - const ShaderAst::ExpressionPtr& expr = *arg; - if (expr->GetType() != ShaderAst::NodeType::ConstantValueExpression) - throw AttributeError{ "attribute " + std::string("nzsl_version") + " expect a single string parameter" }; - - auto& constantValue = SafeCast(*expr); - if (ShaderAst::GetExpressionType(constantValue.value) != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::String }) - throw AttributeError{ "attribute " + std::string("nzsl_version") + " expect a single string parameter" }; - - const std::string& versionStr = std::get(constantValue.value); - - std::regex versionRegex(R"(^(\d+)(\.(\d+)(\.(\d+))?)?$)", std::regex::ECMAScript); - - std::smatch versionMatch; - if (!std::regex_match(versionStr, versionMatch, versionRegex)) - throw AttributeError("invalid version for attribute nzsl"); - - assert(versionMatch.size() == 6); - - std::uint32_t version = 0; - version += std::stoi(versionMatch[1]) * 100; - - if (versionMatch.length(3) > 0) - version += std::stoi(versionMatch[3]) * 10; - - if (versionMatch.length(5) > 0) - version += std::stoi(versionMatch[5]) * 1; - - moduleVersion = version; - break; - } - - default: - throw AttributeError{ "unhandled attribute for module" }; - } } - if (!moduleVersion.has_value()) - throw AttributeError{ "missing module version" }; - - m_context->module = std::make_shared(); - m_context->module->rootNode = ShaderBuilder::MultiStatement(); - m_context->module->shaderLangVersion = *moduleVersion; - Expect(Advance(), TokenType::Semicolon); } diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index c3bbb2a00..b908c422d 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -106,6 +106,7 @@ namespace Nz return SpirvOp::OpIAdd; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -124,6 +125,7 @@ namespace Nz return SpirvOp::OpISub; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -144,6 +146,7 @@ namespace Nz return SpirvOp::OpUDiv; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -197,7 +200,8 @@ namespace Nz case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpIMul; - default: + case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -217,6 +221,9 @@ namespace Nz case ShaderAst::PrimitiveType::Int32: case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpIEqual; + + case ShaderAst::PrimitiveType::String: + break; } break; @@ -236,6 +243,7 @@ namespace Nz return SpirvOp::OpUGreaterThan; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -256,6 +264,7 @@ namespace Nz return SpirvOp::OpUGreaterThanEqual; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -276,6 +285,7 @@ namespace Nz return SpirvOp::OpULessThanEqual; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -296,6 +306,7 @@ namespace Nz return SpirvOp::OpULessThan; case ShaderAst::PrimitiveType::Boolean: + case ShaderAst::PrimitiveType::String: break; } @@ -315,6 +326,9 @@ namespace Nz case ShaderAst::PrimitiveType::Int32: case ShaderAst::PrimitiveType::UInt32: return SpirvOp::OpINotEqual; + + case ShaderAst::PrimitiveType::String: + break; } break; @@ -482,6 +496,9 @@ namespace Nz case ShaderAst::PrimitiveType::UInt32: castOp = SpirvOp::OpConvertUToF; break; + + case ShaderAst::PrimitiveType::String: + throw std::runtime_error("unexpected string type"); } break; } @@ -503,6 +520,9 @@ namespace Nz case ShaderAst::PrimitiveType::UInt32: castOp = SpirvOp::OpSConvert; break; + + case ShaderAst::PrimitiveType::String: + throw std::runtime_error("unexpected string type"); } break; } @@ -524,9 +544,15 @@ namespace Nz case ShaderAst::PrimitiveType::UInt32: break; //< Already handled + + case ShaderAst::PrimitiveType::String: + throw std::runtime_error("unexpected string type"); } break; } + + case ShaderAst::PrimitiveType::String: + throw std::runtime_error("unexpected string type"); } assert(castOp); @@ -809,6 +835,9 @@ namespace Nz case ShaderAst::PrimitiveType::UInt32: op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450UMax : GLSLstd450UMin; break; + + case ShaderAst::PrimitiveType::String: + throw std::runtime_error("unexpected string type"); } UInt32 firstParam = EvaluateExpression(node.parameters[0]); diff --git a/src/Nazara/Shader/SpirvConstantCache.cpp b/src/Nazara/Shader/SpirvConstantCache.cpp index 289632a6f..9ba2796f2 100644 --- a/src/Nazara/Shader/SpirvConstantCache.cpp +++ b/src/Nazara/Shader/SpirvConstantCache.cpp @@ -725,6 +725,9 @@ namespace Nz case ShaderAst::PrimitiveType::UInt32: return Integer{ 32, false }; + + case ShaderAst::PrimitiveType::String: + break; } throw std::runtime_error("unexpected type");