From 51ecff291287d39a7db9b5e46f6269f4d07d60e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 14 May 2021 02:02:12 +0200 Subject: [PATCH] ShaderLang: Add support for length intrinsic --- include/Nazara/Shader/Ast/Enums.hpp | 7 ++++--- include/Nazara/Shader/SpirvWriter.hpp | 1 + src/Nazara/Shader/Ast/SanitizeVisitor.cpp | 18 ++++++++++++++++++ src/Nazara/Shader/GlslWriter.cpp | 4 ++++ src/Nazara/Shader/LangWriter.cpp | 4 ++++ src/Nazara/Shader/ShaderLangParser.cpp | 1 + src/Nazara/Shader/SpirvAstVisitor.cpp | 22 +++++++++++++++++++++- src/Nazara/Shader/SpirvWriter.cpp | 15 ++++++++++++--- 8 files changed, 65 insertions(+), 7 deletions(-) diff --git a/include/Nazara/Shader/Ast/Enums.hpp b/include/Nazara/Shader/Ast/Enums.hpp index 90d229000..b4a7597a6 100644 --- a/include/Nazara/Shader/Ast/Enums.hpp +++ b/include/Nazara/Shader/Ast/Enums.hpp @@ -54,9 +54,10 @@ namespace Nz::ShaderAst enum class IntrinsicType { - CrossProduct, - DotProduct, - SampleTexture + CrossProduct = 0, + DotProduct = 1, + Length = 3, + SampleTexture = 2, }; enum class MemoryLayout diff --git a/include/Nazara/Shader/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp index 52695d2c2..89f737afe 100644 --- a/include/Nazara/Shader/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -57,6 +57,7 @@ namespace Nz SpirvConstantCache::TypePtr BuildFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode); UInt32 GetConstantId(const ShaderAst::ConstantValue& value) const; + UInt32 GetExtendedInstructionSet(const std::string& instructionSetName) const; UInt32 GetExtVarPointerId(std::size_t varIndex) const; UInt32 GetFunctionTypeId(const ShaderAst::DeclareFunctionStatement& functionNode); UInt32 GetPointerTypeId(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const; diff --git a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp index 24dced757..50f86f59e 100644 --- a/src/Nazara/Shader/Ast/SanitizeVisitor.cpp +++ b/src/Nazara/Shader/Ast/SanitizeVisitor.cpp @@ -466,6 +466,21 @@ namespace Nz::ShaderAst break; } + case IntrinsicType::Length: + { + if (clone->parameters.size() != 1) + throw AstError{ "Expected only one parameters" }; + + for (auto& param : clone->parameters) + MandatoryExpr(param); + + const ExpressionType& type = GetExpressionType(*clone->parameters.front()); + if (!IsVectorType(type)) + throw AstError{ "Expected a vector" }; + + break; + } + case IntrinsicType::SampleTexture: { if (clone->parameters.size() != 2) @@ -479,6 +494,8 @@ namespace Nz::ShaderAst if (!IsVectorType(GetExpressionType(*clone->parameters[1]))) throw AstError{ "Second parameter must be a vector" }; + + break; } } @@ -496,6 +513,7 @@ namespace Nz::ShaderAst } case IntrinsicType::DotProduct: + case IntrinsicType::Length: { ExpressionType type = GetExpressionType(*clone->parameters.front()); if (!IsVectorType(type)) diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index 98ebb2b0f..3d355f4a6 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -806,6 +806,10 @@ namespace Nz Append("dot"); break; + case ShaderAst::IntrinsicType::Length: + Append("length"); + break; + case ShaderAst::IntrinsicType::SampleTexture: Append("texture"); break; diff --git a/src/Nazara/Shader/LangWriter.cpp b/src/Nazara/Shader/LangWriter.cpp index 8746b5e94..d836214de 100644 --- a/src/Nazara/Shader/LangWriter.cpp +++ b/src/Nazara/Shader/LangWriter.cpp @@ -654,6 +654,10 @@ namespace Nz Append("dot"); break; + case ShaderAst::IntrinsicType::Length: + Append("length"); + break; + case ShaderAst::IntrinsicType::SampleTexture: Append("texture"); break; diff --git a/src/Nazara/Shader/ShaderLangParser.cpp b/src/Nazara/Shader/ShaderLangParser.cpp index 6ace15958..8ce1e1a50 100644 --- a/src/Nazara/Shader/ShaderLangParser.cpp +++ b/src/Nazara/Shader/ShaderLangParser.cpp @@ -22,6 +22,7 @@ namespace Nz::ShaderLang std::unordered_map s_identifierToIntrinsic = { { "cross", ShaderAst::IntrinsicType::CrossProduct }, { "dot", ShaderAst::IntrinsicType::DotProduct }, + { "length", ShaderAst::IntrinsicType::Length }, }; std::unordered_map s_identifierToAttributeType = { diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index 6fd5cc4f8..286048923 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace Nz @@ -600,7 +601,7 @@ namespace Nz m_instructions.Append(SpirvOp::OpFunctionEnd); } - void SpirvAstVisitor::Visit(ShaderAst::DeclareOptionStatement& node) + void SpirvAstVisitor::Visit(ShaderAst::DeclareOptionStatement& /*node*/) { /* nothing to do */ } @@ -666,6 +667,25 @@ namespace Nz break; } + case ShaderAst::IntrinsicType::Length: + { + UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450"); + + const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]); + assert(IsVectorType(vecExprType)); + + const ShaderAst::VectorType& vecType = std::get(vecExprType); + UInt32 typeId = m_writer.GetTypeId(vecType.type); + + UInt32 vec = EvaluateExpression(node.parameters[0]); + + UInt32 resultId = m_writer.AllocateResultId(); + + m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Length, vec); + PushResultId(resultId); + break; + } + case ShaderAst::IntrinsicType::SampleTexture: { UInt32 typeId = m_writer.GetTypeId(ShaderAst::VectorType{4, ShaderAst::PrimitiveType::Float32}); diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 515c9aebd..30e9c9b43 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -274,6 +274,7 @@ namespace Nz { // Require GLSL.std.450 case ShaderAst::IntrinsicType::CrossProduct: + case ShaderAst::IntrinsicType::Length: extInsts.emplace("GLSL.std.450"); break; @@ -363,7 +364,7 @@ namespace Nz UInt32 id; }; - std::unordered_map extensionInstructions; + std::unordered_map extensionInstructionSet; std::unordered_map varToResult; std::vector funcs; std::vector resultIds; @@ -408,7 +409,7 @@ namespace Nz m_currentState->preVisitor = &preVisitor; for (const std::string& extInst : preVisitor.extInsts) - state.extensionInstructions[extInst] = AllocateResultId(); + state.extensionInstructionSet[extInst] = AllocateResultId(); SpirvAstVisitor visitor(*this, state.instructions, state.funcs); targetAst->Visit(visitor); @@ -465,7 +466,7 @@ namespace Nz m_currentState->header.Append(SpirvOp::OpCapability, SpirvCapability::Shader); - for (const auto& [extInst, resultId] : m_currentState->extensionInstructions) + for (const auto& [extInst, resultId] : m_currentState->extensionInstructionSet) m_currentState->header.Append(SpirvOp::OpExtInstImport, resultId, extInst); m_currentState->header.Append(SpirvOp::OpMemoryModel, SpirvAddressingModel::Logical, SpirvMemoryModel::GLSL450); @@ -534,6 +535,14 @@ namespace Nz return m_currentState->constantTypeCache.GetId(*m_currentState->constantTypeCache.BuildConstant(value)); } + UInt32 SpirvWriter::GetExtendedInstructionSet(const std::string& instructionSetName) const + { + auto it = m_currentState->extensionInstructionSet.find(instructionSetName); + assert(it != m_currentState->extensionInstructionSet.end()); + + return it->second; + } + UInt32 SpirvWriter::GetExtVarPointerId(std::size_t extVarIndex) const { auto it = m_currentState->preVisitor->extVars.find(extVarIndex);