Shader: Many fixes

This commit is contained in:
Jérôme Leclercq 2022-03-04 18:23:01 +01:00
parent 1919bd3302
commit a2f4f3c802
13 changed files with 161 additions and 84 deletions

View File

@ -20,8 +20,13 @@ namespace Nz::ShaderAst
struct Module
{
struct Metadata
{
UInt32 shaderLangVersion;
};
std::shared_ptr<const Metadata> metadata;
MultiStatementPtr rootNode;
UInt32 shaderLangVersion;
};
}

View File

@ -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);

View File

@ -97,7 +97,7 @@ namespace Nz::ShaderBuilder
struct DeclareStruct
{
inline std::unique_ptr<ShaderAst::DeclareStructStatement> operator()(ShaderAst::StructDescription description) const;
inline std::unique_ptr<ShaderAst::DeclareStructStatement> operator()(ShaderAst::StructDescription description, ShaderAst::ExpressionValue<bool> isExported) const;
};
struct DeclareVariable

View File

@ -189,6 +189,7 @@ namespace Nz::ShaderBuilder
case ShaderAst::PrimitiveType::Float32: return ShaderBuilder::Constant(SafeCast<float>(value));
case ShaderAst::PrimitiveType::Int32: return ShaderBuilder::Constant(SafeCast<Int32>(value));
case ShaderAst::PrimitiveType::UInt32: return ShaderBuilder::Constant(SafeCast<UInt32>(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<ShaderAst::DeclareStructStatement> Impl::DeclareStruct::operator()(ShaderAst::StructDescription description) const
inline std::unique_ptr<ShaderAst::DeclareStructStatement> Impl::DeclareStruct::operator()(ShaderAst::StructDescription description, ShaderAst::ExpressionValue<bool> isExported) const
{
auto declareStructNode = std::make_unique<ShaderAst::DeclareStructStatement>();
declareStructNode->description = std::move(description);
declareStructNode->isExported = std::move(isExported);
return declareStructNode;
}

View File

@ -82,6 +82,7 @@ namespace Nz::ShaderLang
const Token& Peek(std::size_t advance = 0);
std::vector<ShaderAst::ExprValue> ParseAttributes();
void ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes);
void ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue<ShaderAst::ExpressionType>& type, ShaderAst::ExpressionPtr& initialValue);
// Statements
@ -93,7 +94,6 @@ namespace Nz::ShaderLang
std::vector<ShaderAst::StatementPtr> ParseFunctionBody();
ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector<ShaderAst::ExprValue> attributes = {});
ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter();
void ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes);
ShaderAst::StatementPtr ParseOptionDeclaration();
ShaderAst::StatementPtr ParseReturnStatement();
ShaderAst::StatementPtr ParseRootStatement(std::vector<ShaderAst::ExprValue> attributes = {});

View File

@ -9,6 +9,7 @@
#include <Nazara/OpenGLRenderer/Utils.hpp>
#include <Nazara/Shader/GlslWriter.hpp>
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <Nazara/Shader/Ast/Module.hpp>
#include <cassert>
#include <stdexcept>
#include <Nazara/OpenGLRenderer/Debug.hpp>
@ -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<ShaderAst::Module::Metadata> metadata = std::make_shared<ShaderAst::Module::Metadata>();
metadata->shaderLangVersion = 100;
dummyModule.metadata = std::move(metadata);
OpenGLShaderModule shaderModule(device, stage, dummyModule);
stageFlags |= shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping());

View File

@ -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<Module>();
m_stream >> module->shaderLangVersion;
std::shared_ptr<Module::Metadata> metadata = std::make_shared<Module::Metadata>();
m_stream >> metadata->shaderLangVersion;
module->metadata = std::move(metadata);
module->rootNode = ShaderBuilder::MultiStatement();
ShaderSerializerVisitor visitor(*this);

View File

@ -115,7 +115,7 @@ namespace Nz::ShaderAst
ModulePtr SanitizeVisitor::Sanitize(const Module& module, const Options& options, std::string* error)
{
ModulePtr clone = std::make_shared<Module>();
clone->shaderLangVersion = module.shaderLangVersion;
clone->metadata = module.metadata;
Context currentContext;
currentContext.options = options;

View File

@ -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);

View File

@ -75,14 +75,7 @@ namespace Nz
inline bool HasValue() const { return locationIndex.HasValue(); }
};
struct LangWriter::NzslAttribute
{
const ShaderAst::ExpressionValue<UInt32>& version;
inline bool HasValue() const { return version.HasValue(); }
};
struct LangWriter::SetAttribute
{
const ShaderAst::ExpressionValue<UInt32>& setIndex;
@ -100,6 +93,7 @@ namespace Nz
struct LangWriter::State
{
const States* states = nullptr;
ShaderAst::Module* module;
std::stringstream stream;
std::unordered_map<std::size_t, std::string> constantNames;
std::unordered_map<std::size_t, ShaderAst::StructDescription*> 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();
}
}

View File

@ -230,6 +230,78 @@ namespace Nz::ShaderLang
return attributes;
}
void Parser::ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes)
{
Expect(Advance(), TokenType::Module);
if (m_context->module)
throw DuplicateModule{ "you must set one module statement per file" };
std::optional<UInt32> 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<ShaderAst::ConstantValueExpression&>(*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<std::string>(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<ShaderAst::Module>();
m_context->module->rootNode = ShaderBuilder::MultiStatement();
std::shared_ptr<ShaderAst::Module::Metadata> moduleMetadata = std::make_shared<ShaderAst::Module::Metadata>();
moduleMetadata->shaderLangVersion = *moduleVersion;
m_context->module->metadata = std::move(moduleMetadata);
Expect(Advance(), TokenType::Semicolon);
}
void Parser::ParseVariableDeclaration(std::string& name, ShaderAst::ExpressionValue<ShaderAst::ExpressionType>& type, ShaderAst::ExpressionPtr& initialValue)
{
name = ParseIdentifierAsName();
@ -564,71 +636,13 @@ namespace Nz::ShaderLang
return { parameterName, std::move(parameterType) };
}
void Parser::ParseModuleStatement(std::vector<ShaderAst::ExprValue> attributes)
{
Expect(Advance(), TokenType::Module);
if (m_context->module)
throw DuplicateModule{ "you must set one module statement per file" };
std::optional<UInt32> 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<ShaderAst::ConstantValueExpression&>(*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<std::string>(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<ShaderAst::Module>();
m_context->module->rootNode = ShaderBuilder::MultiStatement();
m_context->module->shaderLangVersion = *moduleVersion;
Expect(Advance(), TokenType::Semicolon);
}

View File

@ -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]);

View File

@ -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");