ShaderLang: Add support for length intrinsic

This commit is contained in:
Jérôme Leclercq 2021-05-14 02:02:12 +02:00
parent 24f7b75654
commit 51ecff2912
8 changed files with 65 additions and 7 deletions

View File

@ -54,9 +54,10 @@ namespace Nz::ShaderAst
enum class IntrinsicType
{
CrossProduct,
DotProduct,
SampleTexture
CrossProduct = 0,
DotProduct = 1,
Length = 3,
SampleTexture = 2,
};
enum class MemoryLayout

View File

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

View File

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

View File

@ -806,6 +806,10 @@ namespace Nz
Append("dot");
break;
case ShaderAst::IntrinsicType::Length:
Append("length");
break;
case ShaderAst::IntrinsicType::SampleTexture:
Append("texture");
break;

View File

@ -654,6 +654,10 @@ namespace Nz
Append("dot");
break;
case ShaderAst::IntrinsicType::Length:
Append("length");
break;
case ShaderAst::IntrinsicType::SampleTexture:
Append("texture");
break;

View File

@ -22,6 +22,7 @@ namespace Nz::ShaderLang
std::unordered_map<std::string, ShaderAst::IntrinsicType> s_identifierToIntrinsic = {
{ "cross", ShaderAst::IntrinsicType::CrossProduct },
{ "dot", ShaderAst::IntrinsicType::DotProduct },
{ "length", ShaderAst::IntrinsicType::Length },
};
std::unordered_map<std::string, ShaderAst::AttributeType> s_identifierToAttributeType = {

View File

@ -9,6 +9,7 @@
#include <Nazara/Shader/SpirvExpressionLoad.hpp>
#include <Nazara/Shader/SpirvExpressionStore.hpp>
#include <Nazara/Shader/SpirvWriter.hpp>
#include <SpirV/GLSL.std.450.h>
#include <Nazara/Shader/Debug.hpp>
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<ShaderAst::VectorType>(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});

View File

@ -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<std::string, UInt32> extensionInstructions;
std::unordered_map<std::string, UInt32> extensionInstructionSet;
std::unordered_map<std::string, UInt32> varToResult;
std::vector<SpirvAstVisitor::FuncData> funcs;
std::vector<UInt32> 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);