Shader: Add support for max/min intrinsic

This commit is contained in:
Jérôme Leclercq 2021-05-19 20:31:26 +02:00
parent 0339ea346f
commit a7235ab02d
7 changed files with 84 additions and 0 deletions

View File

@ -57,6 +57,8 @@ namespace Nz::ShaderAst
CrossProduct = 0,
DotProduct = 1,
Length = 3,
Max = 4,
Min = 5,
SampleTexture = 2,
};

View File

@ -448,6 +448,8 @@ namespace Nz::ShaderAst
{
case IntrinsicType::CrossProduct:
case IntrinsicType::DotProduct:
case IntrinsicType::Max:
case IntrinsicType::Min:
{
if (clone->parameters.size() != 2)
throw AstError { "Expected two parameters" };
@ -523,6 +525,21 @@ namespace Nz::ShaderAst
break;
}
case IntrinsicType::Max:
case IntrinsicType::Min:
{
const ExpressionType& type = GetExpressionType(*clone->parameters.front());
if (!IsPrimitiveType(type) && !IsVectorType(type))
throw AstError{ "max and min only work with primitive and vector types" };
if ((IsPrimitiveType(type) && std::get<PrimitiveType>(type) == PrimitiveType::Boolean) ||
(IsVectorType(type) && std::get<VectorType>(type).type == PrimitiveType::Boolean))
throw AstError{ "max and min do not work with booleans" };
clone->cachedExpressionType = type;
break;
}
case IntrinsicType::SampleTexture:
{
clone->cachedExpressionType = VectorType{ 4, std::get<SamplerType>(GetExpressionType(*clone->parameters.front())).sampledType };

View File

@ -822,6 +822,14 @@ namespace Nz
Append("length");
break;
case ShaderAst::IntrinsicType::Max:
Append("max");
break;
case ShaderAst::IntrinsicType::Min:
Append("min");
break;
case ShaderAst::IntrinsicType::SampleTexture:
Append("texture");
break;

View File

@ -658,6 +658,14 @@ namespace Nz
Append("length");
break;
case ShaderAst::IntrinsicType::Max:
Append("max");
break;
case ShaderAst::IntrinsicType::Min:
Append("min");
break;
case ShaderAst::IntrinsicType::SampleTexture:
Append("texture");
break;

View File

@ -22,6 +22,8 @@ namespace Nz::ShaderLang
std::unordered_map<std::string, ShaderAst::IntrinsicType> s_identifierToIntrinsic = {
{ "cross", ShaderAst::IntrinsicType::CrossProduct },
{ "dot", ShaderAst::IntrinsicType::DotProduct },
{ "max", ShaderAst::IntrinsicType::Max },
{ "min", ShaderAst::IntrinsicType::Min },
{ "length", ShaderAst::IntrinsicType::Length },
};

View File

@ -710,6 +710,51 @@ namespace Nz
break;
}
case ShaderAst::IntrinsicType::Max:
case ShaderAst::IntrinsicType::Min:
{
UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450");
const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]);
assert(IsPrimitiveType(parameterType) || IsVectorType(parameterType));
UInt32 typeId = m_writer.GetTypeId(parameterType);
ShaderAst::PrimitiveType basicType;
if (IsPrimitiveType(parameterType))
basicType = std::get<ShaderAst::PrimitiveType>(parameterType);
else if (IsVectorType(parameterType))
basicType = std::get<ShaderAst::VectorType>(parameterType).type;
else
throw std::runtime_error("unexpected expression type");
GLSLstd450 op;
switch (basicType)
{
case ShaderAst::PrimitiveType::Boolean:
throw std::runtime_error("unexpected boolean for max/min intrinsic");
case ShaderAst::PrimitiveType::Float32:
op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450FMax : GLSLstd450FMin;
break;
case ShaderAst::PrimitiveType::Int32:
op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450SMax : GLSLstd450SMin;
break;
case ShaderAst::PrimitiveType::UInt32:
op = (node.intrinsic == ShaderAst::IntrinsicType::Max) ? GLSLstd450UMax : GLSLstd450UMin;
break;
}
UInt32 firstParam = EvaluateExpression(node.parameters[0]);
UInt32 secondParam = EvaluateExpression(node.parameters[1]);
UInt32 resultId = m_writer.AllocateResultId();
m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, op, firstParam, secondParam);
PushResultId(resultId);
break;
}
case ShaderAst::IntrinsicType::SampleTexture:
{
UInt32 typeId = m_writer.GetTypeId(ShaderAst::VectorType{4, ShaderAst::PrimitiveType::Float32});

View File

@ -283,6 +283,8 @@ namespace Nz
// Require GLSL.std.450
case ShaderAst::IntrinsicType::CrossProduct:
case ShaderAst::IntrinsicType::Length:
case ShaderAst::IntrinsicType::Max:
case ShaderAst::IntrinsicType::Min:
extInsts.emplace("GLSL.std.450");
break;