Shader: Add support for compound operators
This commit is contained in:
parent
601ed047ba
commit
0442db1c53
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue