Shader: Add support for compound operators

This commit is contained in:
Jérôme Leclercq 2021-09-24 15:39:03 +02:00
parent 601ed047ba
commit 0442db1c53
15 changed files with 350 additions and 234 deletions

View File

@ -48,10 +48,10 @@ fn main(input: FragIn) -> FragOut
let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize * 10.0;
let color = colorTexture.Sample(fragcoord).rgb;
color = color * (BrightMiddleGrey/BrightLuminance);
color = color * (vec3<f32>(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold)));
color = color - vec3<f32>(0.5, 0.5, 0.5);
color = color / (vec3<f32>(1.0, 1.0, 1.0) + color);
color *= BrightMiddleGrey / BrightLuminance;
color *= vec3<f32>(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold));
color -= vec3<f32>(0.5, 0.5, 0.5);
color /= vec3<f32>(1.0, 1.0, 1.0) + color;
let output: FragOut;
output.color = vec4<f32>(color, 1.0);

View File

@ -58,8 +58,7 @@ fn main(input: InputData) -> OutputData
{
let diffuseColor = settings.DiffuseColor;
const if (HasDiffuseTexture)
// TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv)
diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv);
diffuseColor *= MaterialDiffuseMap.Sample(input.uv);
const if (HasAlphaTexture)
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x

View File

@ -48,19 +48,19 @@ fn main(input: FragIn) -> FragOut
let filter = vec2<f32>(1.0, 0.0);
color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color += colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color += colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
color += colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
color += colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
filter = vec2<f32>(0.0, 1.0);
color = color + colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color = color + colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color += colorTexture.Sample(fragcoord + filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color += colorTexture.Sample(fragcoord - filter * 1.3846153846 * invTargetSize).rgb * 0.3162162162;
color = color + colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
color = color + colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
color += colorTexture.Sample(fragcoord + filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
color += colorTexture.Sample(fragcoord - filter * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
let output: FragOut;
output.color = vec4<f32>(color, 1.0);

View File

@ -16,7 +16,13 @@ namespace Nz
{
enum class AssignType
{
Simple //< =
Simple, //< a = b
CompoundAdd, //< a += b
CompoundDivide, //< a /= b
CompoundMultiply, //< a *= b
CompoundLogicalAnd, //< a &&= b
CompoundLogicalOr, //< a ||= b
CompoundSubtract, //< a -= b
};
enum class AttributeType

View File

@ -38,6 +38,7 @@ namespace Nz::ShaderAst
std::unordered_set<std::string> reservedIdentifiers;
std::unordered_map<std::size_t, ConstantValue> optionValues;
bool makeVariableNameUnique = false;
bool removeCompoundAssignments = false;
bool removeOptionDeclaration = true;
};
@ -76,9 +77,9 @@ namespace Nz::ShaderAst
const Identifier* FindIdentifier(const std::string_view& identifierName) const;
Expression& MandatoryExpr(ExpressionPtr& node);
Statement& MandatoryStatement(StatementPtr& node);
void TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right);
Expression& MandatoryExpr(const ExpressionPtr& node);
Statement& MandatoryStatement(const StatementPtr& node);
void TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right);
void TypeMustMatch(const ExpressionType& left, const ExpressionType& right);
void PushScope();
@ -111,6 +112,7 @@ namespace Nz::ShaderAst
void Validate(AccessIndexExpression& node);
void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration);
void Validate(IntrinsicExpression& node);
ExpressionType ValidateBinaryOp(BinaryType op, const ExpressionPtr& leftExpr, const ExpressionPtr& rightExpr);
struct FunctionData
{

View File

@ -22,6 +22,7 @@ NAZARA_SHADERLANG_TOKEN(Const)
NAZARA_SHADERLANG_TOKEN(ConstSelect)
NAZARA_SHADERLANG_TOKEN(Discard)
NAZARA_SHADERLANG_TOKEN(Divide)
NAZARA_SHADERLANG_TOKEN(DivideAssign)
NAZARA_SHADERLANG_TOKEN(Dot)
NAZARA_SHADERLANG_TOKEN(Equal)
NAZARA_SHADERLANG_TOKEN(Else)
@ -39,12 +40,17 @@ NAZARA_SHADERLANG_TOKEN(LessThan)
NAZARA_SHADERLANG_TOKEN(LessThanEqual)
NAZARA_SHADERLANG_TOKEN(Let)
NAZARA_SHADERLANG_TOKEN(LogicalAnd)
NAZARA_SHADERLANG_TOKEN(LogicalAndAssign)
NAZARA_SHADERLANG_TOKEN(LogicalOr)
NAZARA_SHADERLANG_TOKEN(LogicalOrAssign)
NAZARA_SHADERLANG_TOKEN(Multiply)
NAZARA_SHADERLANG_TOKEN(MultiplyAssign)
NAZARA_SHADERLANG_TOKEN(Minus)
NAZARA_SHADERLANG_TOKEN(MinusAssign)
NAZARA_SHADERLANG_TOKEN(Not)
NAZARA_SHADERLANG_TOKEN(NotEqual)
NAZARA_SHADERLANG_TOKEN(Plus)
NAZARA_SHADERLANG_TOKEN(PlusAssign)
NAZARA_SHADERLANG_TOKEN(OpenCurlyBracket)
NAZARA_SHADERLANG_TOKEN(OpenSquareBracket)
NAZARA_SHADERLANG_TOKEN(OpenParenthesis)

View File

@ -66,16 +66,13 @@ fn main(input: FragIn) -> FragOut
let diffuseColor = settings.DiffuseColor;
const if (HasUV)
//TODO: diffuseColor *= TextureOverlay.Sample(input.uv);
diffuseColor = diffuseColor * TextureOverlay.Sample(input.uv);
diffuseColor *= TextureOverlay.Sample(input.uv);
const if (HasVertexColor)
//TODO: diffuseColor *= input.color;
diffuseColor = diffuseColor * input.color;
diffuseColor *= input.color;
const if (HasDiffuseTexture)
// TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv)
diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv);
diffuseColor *= MaterialDiffuseMap.Sample(input.uv);
const if (HasAlphaTexture)
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x

View File

@ -54,16 +54,13 @@ fn main(input: FragIn)
let alpha = settings.DiffuseColor.a;
const if (HasUV)
//TODO: diffuseColor *= TextureOverlay.Sample(input.uv);
alpha = alpha * TextureOverlay.Sample(input.uv).a;
alpha *= TextureOverlay.Sample(input.uv).a;
const if (HasDiffuseTexture)
// TODO: alpha *= MaterialDiffuseMap.Sample(input.uv).a;
alpha = alpha * MaterialDiffuseMap.Sample(input.uv).a;
alpha *= MaterialDiffuseMap.Sample(input.uv).a;
const if (HasAlphaTexture)
// TODO: alpha *= MaterialAlphaMap.Sample(input.uv).x
alpha = alpha * MaterialAlphaMap.Sample(input.uv).x;
alpha *= MaterialAlphaMap.Sample(input.uv).x;
if (alpha < settings.AlphaThreshold)
discard;

View File

@ -253,8 +253,35 @@ namespace Nz::ShaderAst
auto clone = static_unique_pointer_cast<AssignExpression>(AstCloner::Clone(node));
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = GetExpressionType(*clone->right);
std::optional<BinaryType> binaryType;
switch (clone->op)
{
case AssignType::Simple:
TypeMustMatch(clone->left, clone->right);
break;
case AssignType::CompoundAdd: binaryType = BinaryType::Add; break;
case AssignType::CompoundDivide: binaryType = BinaryType::Divide; break;
case AssignType::CompoundMultiply: binaryType = BinaryType::Multiply; break;
case AssignType::CompoundLogicalAnd: binaryType = BinaryType::LogicalAnd; break;
case AssignType::CompoundLogicalOr: binaryType = BinaryType::LogicalOr; break;
case AssignType::CompoundSubtract: binaryType = BinaryType::Subtract; break;
}
if (binaryType)
{
ExpressionType expressionType = ValidateBinaryOp(*binaryType, clone->left, clone->right);
TypeMustMatch(GetExpressionType(*clone->left), expressionType);
if (m_context->options.removeCompoundAssignments)
{
clone->op = AssignType::Simple;
clone->right = ShaderBuilder::Binary(*binaryType, AstCloner::Clone(*clone->left), std::move(clone->right));
clone->right->cachedExpressionType = std::move(expressionType);
}
}
clone->cachedExpressionType = GetExpressionType(*clone->left);
return clone;
}
@ -262,191 +289,7 @@ namespace Nz::ShaderAst
ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node)
{
auto clone = static_unique_pointer_cast<BinaryExpression>(AstCloner::Clone(node));
const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(clone->left));
if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType))
throw AstError{ "left expression type does not support binary operation" };
const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(clone->right));
if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType))
throw AstError{ "right expression type does not support binary operation" };
if (IsPrimitiveType(leftExprType))
{
PrimitiveType leftType = std::get<PrimitiveType>(leftExprType);
switch (clone->op)
{
case BinaryType::CompGe:
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
if (leftType == PrimitiveType::Boolean)
throw AstError{ "this operation is not supported for booleans" };
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = PrimitiveType::Boolean;
break;
case BinaryType::Add:
case BinaryType::CompEq:
case BinaryType::CompNe:
case BinaryType::Subtract:
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = leftExprType;
break;
case BinaryType::Multiply:
case BinaryType::Divide:
{
switch (leftType)
{
case PrimitiveType::Float32:
case PrimitiveType::Int32:
case PrimitiveType::UInt32:
{
if (IsMatrixType(rightExprType))
{
TypeMustMatch(leftType, std::get<MatrixType>(rightExprType).type);
clone->cachedExpressionType = rightExprType;
}
else if (IsPrimitiveType(rightExprType))
{
TypeMustMatch(leftType, rightExprType);
clone->cachedExpressionType = leftExprType;
}
else if (IsVectorType(rightExprType))
{
TypeMustMatch(leftType, std::get<VectorType>(rightExprType).type);
clone->cachedExpressionType = rightExprType;
}
else
throw AstError{ "incompatible types" };
break;
}
case PrimitiveType::Boolean:
throw AstError{ "this operation is not supported for booleans" };
default:
throw AstError{ "incompatible types" };
}
break;
}
case BinaryType::LogicalAnd:
case BinaryType::LogicalOr:
if (leftType != PrimitiveType::Boolean)
throw AstError{ "logical and/or are only supported on booleans" };
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = PrimitiveType::Boolean;
break;
}
}
else if (IsMatrixType(leftExprType))
{
const MatrixType& leftType = std::get<MatrixType>(leftExprType);
switch (clone->op)
{
case BinaryType::CompGe:
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
case BinaryType::CompEq:
case BinaryType::CompNe:
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = PrimitiveType::Boolean;
break;
case BinaryType::Add:
case BinaryType::Subtract:
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = leftExprType;
break;
case BinaryType::Multiply:
case BinaryType::Divide:
{
if (IsMatrixType(rightExprType))
{
TypeMustMatch(leftExprType, rightExprType);
clone->cachedExpressionType = leftExprType; //< FIXME
}
else if (IsPrimitiveType(rightExprType))
{
TypeMustMatch(leftType.type, rightExprType);
clone->cachedExpressionType = leftExprType;
}
else if (IsVectorType(rightExprType))
{
const VectorType& rightType = std::get<VectorType>(rightExprType);
TypeMustMatch(leftType.type, rightType.type);
if (leftType.columnCount != rightType.componentCount)
throw AstError{ "incompatible types" };
clone->cachedExpressionType = rightExprType;
}
else
throw AstError{ "incompatible types" };
break;
}
case BinaryType::LogicalAnd:
case BinaryType::LogicalOr:
throw AstError{ "logical and/or are only supported on booleans" };
}
}
else if (IsVectorType(leftExprType))
{
const VectorType& leftType = std::get<VectorType>(leftExprType);
switch (clone->op)
{
case BinaryType::CompGe:
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
case BinaryType::CompEq:
case BinaryType::CompNe:
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = PrimitiveType::Boolean;
break;
case BinaryType::Add:
case BinaryType::Subtract:
TypeMustMatch(clone->left, clone->right);
clone->cachedExpressionType = leftExprType;
break;
case BinaryType::Multiply:
case BinaryType::Divide:
{
if (IsPrimitiveType(rightExprType))
{
TypeMustMatch(leftType.type, rightExprType);
clone->cachedExpressionType = leftExprType;
}
else if (IsVectorType(rightExprType))
{
TypeMustMatch(leftType, rightExprType);
clone->cachedExpressionType = rightExprType;
}
else
throw AstError{ "incompatible types" };
break;
}
case BinaryType::LogicalAnd:
case BinaryType::LogicalOr:
throw AstError{ "logical and/or are only supported on booleans" };
}
}
clone->cachedExpressionType = ValidateBinaryOp(clone->op, clone->left, clone->right);
return clone;
}
@ -1116,7 +959,7 @@ namespace Nz::ShaderAst
return &*it;
}
Expression& SanitizeVisitor::MandatoryExpr(ExpressionPtr& node)
Expression& SanitizeVisitor::MandatoryExpr(const ExpressionPtr& node)
{
if (!node)
throw AstError{ "Invalid expression" };
@ -1124,7 +967,7 @@ namespace Nz::ShaderAst
return *node;
}
Statement& SanitizeVisitor::MandatoryStatement(StatementPtr& node)
Statement& SanitizeVisitor::MandatoryStatement(const StatementPtr& node)
{
if (!node)
throw AstError{ "Invalid statement" };
@ -1640,7 +1483,189 @@ namespace Nz::ShaderAst
}
}
void SanitizeVisitor::TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right)
ExpressionType SanitizeVisitor::ValidateBinaryOp(BinaryType op, const ExpressionPtr& leftExpr, const ExpressionPtr& rightExpr)
{
const ExpressionType& leftExprType = GetExpressionType(MandatoryExpr(leftExpr));
const ExpressionType& rightExprType = GetExpressionType(MandatoryExpr(rightExpr));
if (!IsPrimitiveType(leftExprType) && !IsMatrixType(leftExprType) && !IsVectorType(leftExprType))
throw AstError{ "left expression type does not support binary operation" };
if (!IsPrimitiveType(rightExprType) && !IsMatrixType(rightExprType) && !IsVectorType(rightExprType))
throw AstError{ "right expression type does not support binary operation" };
if (IsPrimitiveType(leftExprType))
{
PrimitiveType leftType = std::get<PrimitiveType>(leftExprType);
switch (op)
{
case BinaryType::CompGe:
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
{
if (leftType == PrimitiveType::Boolean)
throw AstError{ "this operation is not supported for booleans" };
TypeMustMatch(leftExpr, rightExpr);
return PrimitiveType::Boolean;
}
case BinaryType::Add:
case BinaryType::CompEq:
case BinaryType::CompNe:
case BinaryType::Subtract:
TypeMustMatch(leftExpr, rightExpr);
return leftExprType;
case BinaryType::Multiply:
case BinaryType::Divide:
{
switch (leftType)
{
case PrimitiveType::Float32:
case PrimitiveType::Int32:
case PrimitiveType::UInt32:
{
if (IsMatrixType(rightExprType))
{
TypeMustMatch(leftType, std::get<MatrixType>(rightExprType).type);
return rightExprType;
}
else if (IsPrimitiveType(rightExprType))
{
TypeMustMatch(leftType, rightExprType);
return leftExprType;
}
else if (IsVectorType(rightExprType))
{
TypeMustMatch(leftType, std::get<VectorType>(rightExprType).type);
return rightExprType;
}
else
throw AstError{ "incompatible types" };
break;
}
case PrimitiveType::Boolean:
throw AstError{ "this operation is not supported for booleans" };
default:
throw AstError{ "incompatible types" };
}
}
case BinaryType::LogicalAnd:
case BinaryType::LogicalOr:
{
if (leftType != PrimitiveType::Boolean)
throw AstError{ "logical and/or are only supported on booleans" };
TypeMustMatch(leftExpr, rightExpr);
return PrimitiveType::Boolean;
}
}
}
else if (IsMatrixType(leftExprType))
{
const MatrixType& leftType = std::get<MatrixType>(leftExprType);
switch (op)
{
case BinaryType::CompGe:
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
case BinaryType::CompEq:
case BinaryType::CompNe:
TypeMustMatch(leftExpr, rightExpr);
return PrimitiveType::Boolean;
case BinaryType::Add:
case BinaryType::Subtract:
TypeMustMatch(leftExpr, rightExpr);
return leftExprType;
case BinaryType::Multiply:
case BinaryType::Divide:
{
if (IsMatrixType(rightExprType))
{
TypeMustMatch(leftExprType, rightExprType);
return leftExprType; //< FIXME
}
else if (IsPrimitiveType(rightExprType))
{
TypeMustMatch(leftType.type, rightExprType);
return leftExprType;
}
else if (IsVectorType(rightExprType))
{
const VectorType& rightType = std::get<VectorType>(rightExprType);
TypeMustMatch(leftType.type, rightType.type);
if (leftType.columnCount != rightType.componentCount)
throw AstError{ "incompatible types" };
return rightExprType;
}
else
throw AstError{ "incompatible types" };
}
case BinaryType::LogicalAnd:
case BinaryType::LogicalOr:
throw AstError{ "logical and/or are only supported on booleans" };
}
}
else if (IsVectorType(leftExprType))
{
const VectorType& leftType = std::get<VectorType>(leftExprType);
switch (op)
{
case BinaryType::CompGe:
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
case BinaryType::CompEq:
case BinaryType::CompNe:
TypeMustMatch(leftExpr, rightExpr);
return PrimitiveType::Boolean;
case BinaryType::Add:
case BinaryType::Subtract:
TypeMustMatch(leftExpr, rightExpr);
return leftExprType;
case BinaryType::Multiply:
case BinaryType::Divide:
{
if (IsPrimitiveType(rightExprType))
{
TypeMustMatch(leftType.type, rightExprType);
return leftExprType;
}
else if (IsVectorType(rightExprType))
{
TypeMustMatch(leftType, rightExprType);
return rightExprType;
}
else
throw AstError{ "incompatible types" };
break;
}
case BinaryType::LogicalAnd:
case BinaryType::LogicalOr:
throw AstError{ "logical and/or are only supported on booleans" };
}
}
throw AstError{ "internal error: unchecked operation" };
}
void SanitizeVisitor::TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right)
{
return TypeMustMatch(GetExpressionType(*left), GetExpressionType(*right));
}

View File

@ -207,6 +207,7 @@ namespace Nz
ShaderAst::SanitizeVisitor::Options options;
options.optionValues = std::move(optionValues);
options.makeVariableNameUnique = true;
options.removeCompoundAssignments = false;
options.reservedIdentifiers = {
// All reserved GLSL keywords as of GLSL ES 3.2
"active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly"
@ -725,9 +726,13 @@ namespace Nz
switch (node.op)
{
case ShaderAst::AssignType::Simple:
Append(" = ");
break;
case ShaderAst::AssignType::Simple: Append(" = "); break;
case ShaderAst::AssignType::CompoundAdd: Append(" += "); break;
case ShaderAst::AssignType::CompoundDivide: Append(" /= "); break;
case ShaderAst::AssignType::CompoundMultiply: Append(" *= "); break;
case ShaderAst::AssignType::CompoundLogicalAnd: Append(" &&= "); break;
case ShaderAst::AssignType::CompoundLogicalOr: Append(" ||= "); break;
case ShaderAst::AssignType::CompoundSubtract: Append(" -= "); break;
}
node.right->Visit(*this);

View File

@ -541,9 +541,13 @@ namespace Nz
switch (node.op)
{
case ShaderAst::AssignType::Simple:
Append(" = ");
break;
case ShaderAst::AssignType::Simple: Append(" = "); break;
case ShaderAst::AssignType::CompoundAdd: Append(" += "); break;
case ShaderAst::AssignType::CompoundDivide: Append(" /= "); break;
case ShaderAst::AssignType::CompoundMultiply: Append(" *= "); break;
case ShaderAst::AssignType::CompoundLogicalAnd: Append(" &&= "); break;
case ShaderAst::AssignType::CompoundLogicalOr: Append(" ||= "); break;
case ShaderAst::AssignType::CompoundSubtract: Append(" -= "); break;
}
node.right->Visit(*this);

View File

@ -106,14 +106,21 @@ namespace Nz::ShaderLang
case '-':
{
if (Peek() == '>')
char next = Peek();
if (next == '>')
{
currentPos++;
tokenType = TokenType::FunctionReturn;
break;
}
else if (next == '=')
{
currentPos++;
tokenType = TokenType::MinusAssign;
}
else
tokenType = TokenType::Minus;
tokenType = TokenType::Minus;
break;
}
@ -155,6 +162,11 @@ namespace Nz::ShaderLang
}
while (next != -1);
}
else if (next == '=')
{
currentPos++;
tokenType = TokenType::DivideAssign;
}
else
tokenType = TokenType::Divide;
@ -253,7 +265,14 @@ namespace Nz::ShaderLang
if (next == '|')
{
currentPos++;
tokenType = TokenType::LogicalOr;
next = Peek();
if (next == '=')
{
currentPos++;
tokenType = TokenType::LogicalOrAssign;
}
else
tokenType = TokenType::LogicalOr;
}
else
throw UnrecognizedToken{}; //< TODO: Add BOR (a | b)
@ -267,7 +286,14 @@ namespace Nz::ShaderLang
if (next == '&')
{
currentPos++;
tokenType = TokenType::LogicalAnd;
next = Peek();
if (next == '=')
{
currentPos++;
tokenType = TokenType::LogicalAndAssign;
}
else
tokenType = TokenType::LogicalAnd;
}
else
throw UnrecognizedToken{}; //< TODO: Add BAND (a & b)
@ -317,9 +343,34 @@ namespace Nz::ShaderLang
break;
}
case '+':
{
char next = Peek();
if (next == '=')
{
currentPos++;
tokenType = TokenType::PlusAssign;
}
else
tokenType = TokenType::Plus;
break;
}
case '*':
{
char next = Peek();
if (next == '=')
{
currentPos++;
tokenType = TokenType::MultiplyAssign;
}
else
tokenType = TokenType::Multiply;
break;
}
case '+': tokenType = TokenType::Plus; break;
case '*': tokenType = TokenType::Multiply; break;
case ':': tokenType = TokenType::Colon; break;
case ';': tokenType = TokenType::Semicolon; break;
case '.': tokenType = TokenType::Dot; break;

View File

@ -860,12 +860,32 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr Parser::ParseVariableAssignation()
{
// Variable expression
ShaderAst::ExpressionPtr left = ParseExpression();
Expect(Advance(), TokenType::Assign);
// Assignation type
ShaderAst::AssignType assignType;
switch (Peek().type)
{
case TokenType::Assign: assignType = ShaderAst::AssignType::Simple; break;
case TokenType::DivideAssign: assignType = ShaderAst::AssignType::CompoundDivide; break;
case TokenType::LogicalAndAssign: assignType = ShaderAst::AssignType::CompoundLogicalAnd; break;
case TokenType::LogicalOrAssign: assignType = ShaderAst::AssignType::CompoundLogicalOr; break;
case TokenType::MultiplyAssign: assignType = ShaderAst::AssignType::CompoundMultiply; break;
case TokenType::MinusAssign: assignType = ShaderAst::AssignType::CompoundSubtract; break;
case TokenType::PlusAssign: assignType = ShaderAst::AssignType::CompoundAdd; break;
default:
throw UnexpectedToken{};
}
Consume();
// Value expression
ShaderAst::ExpressionPtr right = ParseExpression();
return ShaderBuilder::Assign(ShaderAst::AssignType::Simple, std::move(left), std::move(right));
return ShaderBuilder::Assign(assignType, std::move(left), std::move(right));
}
ShaderAst::StatementPtr Parser::ParseVariableDeclaration()

View File

@ -51,6 +51,9 @@ namespace Nz
void SpirvAstVisitor::Visit(ShaderAst::AssignExpression& node)
{
if (node.op != ShaderAst::AssignType::Simple)
throw std::runtime_error("unexpected assign expression (should have been removed by sanitization)");
UInt32 resultId = EvaluateExpression(node.right);
SpirvExpressionStore storeVisitor(m_writer, *this, *m_currentBlock);

View File

@ -464,6 +464,7 @@ namespace Nz
{
ShaderAst::SanitizeVisitor::Options options;
options.optionValues = states.optionValues;
options.removeCompoundAssignments = true;
sanitizedAst = ShaderAst::Sanitize(shader, options);
targetAst = sanitizedAst.get();