From: Mikko Rasa Date: Mon, 8 Mar 2021 14:59:12 +0000 (+0200) Subject: Recognize swizzles in GLSL X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=f526938b407e061c7424adedc34af4d1ff687f90 Recognize swizzles in GLSL --- diff --git a/source/glsl/debug.cpp b/source/glsl/debug.cpp index ee50bf46..fd1fd667 100644 --- a/source/glsl/debug.cpp +++ b/source/glsl/debug.cpp @@ -178,6 +178,16 @@ void DumpTree::visit(MemberAccess &memacc) annotated_branch(text, *memacc.left); } +void DumpTree::visit(Swizzle &swizzle) +{ + static const char components[4] = { 'x', 'y', 'z', 'w' }; + string text = "Swizzle: ."; + for(unsigned i=0; i %s", format_type(swizzle.type)); + annotated_branch(text, *swizzle.left); +} + void DumpTree::visit(UnaryExpression &unary) { string text = format("Unary: %s, %sfix -> %s", unary.oper->token, (unary.oper->type==Operator::PREFIX ? "pre" : "post"), format_type(unary.type)); diff --git a/source/glsl/debug.h b/source/glsl/debug.h index d873ea37..3837c569 100644 --- a/source/glsl/debug.h +++ b/source/glsl/debug.h @@ -58,6 +58,7 @@ private: virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 53676c26..3e53c152 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -367,11 +368,43 @@ void VariableResolver::visit(MemberAccess &memacc) if(i!=strct->members.variables.end()) declaration = i->second; } + else if(BasicTypeDeclaration *basic = dynamic_cast(memacc.left->type)) + { + bool scalar_swizzle = ((basic->kind==BasicTypeDeclaration::INT || basic->kind==BasicTypeDeclaration::FLOAT) && memacc.member.size()==1); + bool vector_swizzle = (basic->kind==BasicTypeDeclaration::VECTOR && memacc.member.size()<=4); + if(scalar_swizzle || vector_swizzle) + { + static const char component_names[] = { 'x', 'r', 's', 'y', 'g', 't', 'z', 'b', 'p', 'w', 'a', 'q' }; + + bool ok = true; + UInt8 components[4] = { }; + for(unsigned i=0; (ok && isource = memacc.source; + swizzle->line = memacc.line; + swizzle->oper = memacc.oper; + swizzle->left = memacc.left; + swizzle->component_group = memacc.member; + swizzle->count = memacc.member.size(); + copy(components, components+memacc.member.size(), swizzle->components); + r_replacement_expr = swizzle; + } + } + } r_any_resolved |= (declaration!=memacc.declaration); memacc.declaration = declaration; } +void VariableResolver::visit(Swizzle &swizzle) +{ + visit_and_replace(swizzle.left); +} + void VariableResolver::visit(UnaryExpression &unary) { visit_and_replace(unary.expression); @@ -589,6 +622,20 @@ void ExpressionResolver::visit(MemberAccess &memacc) resolve(memacc, memacc.declaration->type_declaration, memacc.left->lvalue); } +void ExpressionResolver::visit(Swizzle &swizzle) +{ + TraversingVisitor::visit(swizzle); + + if(BasicTypeDeclaration *left_basic = dynamic_cast(swizzle.left->type)) + { + BasicTypeDeclaration *left_elem = get_element_type(*left_basic); + if(swizzle.count==1) + resolve(swizzle, left_elem, swizzle.left->lvalue); + else if(left_basic->kind==BasicTypeDeclaration::VECTOR && left_elem) + resolve(swizzle, find_type(*left_elem, left_basic->kind, swizzle.count), swizzle.left->lvalue); + } +} + void ExpressionResolver::visit(UnaryExpression &unary) { TraversingVisitor::visit(unary); diff --git a/source/glsl/generate.h b/source/glsl/generate.h index 427f4de2..c0d1ef8d 100644 --- a/source/glsl/generate.h +++ b/source/glsl/generate.h @@ -111,6 +111,7 @@ private: virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); @@ -157,6 +158,7 @@ private: virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); void visit(BinaryExpression &, bool); virtual void visit(BinaryExpression &); diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index c1431f2b..414cf387 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -232,6 +232,11 @@ void FunctionInliner::visit(MemberAccess &memacc) visit_and_inline(memacc.left); } +void FunctionInliner::visit(Swizzle &swizzle) +{ + visit_and_inline(swizzle.left); +} + void FunctionInliner::visit(FunctionCall &call) { for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) @@ -439,6 +444,13 @@ void ExpressionInliner::visit(MemberAccess &memacc) r_trivial = false; } +void ExpressionInliner::visit(Swizzle &swizzle) +{ + visit_and_record(swizzle.left, swizzle.oper, false); + r_oper = swizzle.oper; + r_trivial = false; +} + void ExpressionInliner::visit(UnaryExpression &unary) { SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-'); @@ -752,6 +764,13 @@ void UnusedVariableRemover::visit(MemberAccess &memacc) unused_nodes.erase(memacc.declaration); } +void UnusedVariableRemover::visit(Swizzle &swizzle) +{ + if(assignment_target) + r_assign_to_subfield = true; + TraversingVisitor::visit(swizzle); +} + void UnusedVariableRemover::visit(UnaryExpression &unary) { TraversingVisitor::visit(unary); diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h index 551e2d56..67d064c5 100644 --- a/source/glsl/optimize.h +++ b/source/glsl/optimize.h @@ -90,6 +90,7 @@ private: virtual void visit(BinaryExpression &); virtual void visit(Assignment &a) { visit(static_cast(a)); } virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(FunctionCall &); virtual void visit(ExpressionStatement &); virtual void visit(VariableDeclaration &); @@ -139,6 +140,7 @@ private: virtual void visit(Block &); virtual void visit(VariableReference &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); @@ -223,6 +225,7 @@ private: virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); diff --git a/source/glsl/output.cpp b/source/glsl/output.cpp index 52371d1b..b277ba8e 100644 --- a/source/glsl/output.cpp +++ b/source/glsl/output.cpp @@ -136,6 +136,12 @@ void Formatter::visit(MemberAccess &memacc) append(format(".%s", memacc.member)); } +void Formatter::visit(Swizzle &swizzle) +{ + swizzle.left->visit(*this); + append(format(".%s", swizzle.component_group)); +} + void Formatter::visit(UnaryExpression &unary) { if(unary.oper->type==Operator::PREFIX) diff --git a/source/glsl/output.h b/source/glsl/output.h index f720606e..61c02caa 100644 --- a/source/glsl/output.h +++ b/source/glsl/output.h @@ -38,6 +38,7 @@ private: virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp index cb774197..85d805d1 100644 --- a/source/glsl/syntax.cpp +++ b/source/glsl/syntax.cpp @@ -161,6 +161,18 @@ void MemberAccess::visit(NodeVisitor &visitor) } +Swizzle::Swizzle(): + count(0) +{ + fill(components, components+4, 0); +} + +void Swizzle::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + void UnaryExpression::visit(NodeVisitor &visitor) { visitor.visit(*this); diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index 30acca42..c3eeb6a1 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "features.h" @@ -197,6 +198,19 @@ struct MemberAccess: Expression virtual void visit(NodeVisitor &); }; +struct Swizzle: Expression +{ + NodePtr left; + std::string component_group; + unsigned count; + UInt8 components[4]; + + Swizzle(); + + virtual Swizzle *clone() const { return new Swizzle(*this); } + virtual void visit(NodeVisitor &); +}; + struct UnaryExpression: Expression { NodePtr expression; diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index b0c6e3d6..c4e0a9bd 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -227,6 +228,44 @@ void ReferenceValidator::visit(FunctionDeclaration &func) } +void ExpressionValidator::visit(Swizzle &swizzle) +{ + unsigned size = 0; + if(BasicTypeDeclaration *basic = dynamic_cast(swizzle.left->type)) + { + if(basic->kind==BasicTypeDeclaration::INT || basic->kind==BasicTypeDeclaration::FLOAT) + size = 1; + else if(basic->kind==BasicTypeDeclaration::VECTOR) + size = basic->size; + } + + if(size) + { + static const char component_names[] = { 'x', 'y', 'z', 'w', 'r', 'g', 'b', 'a', 's', 't', 'p', 'q' }; + int flavour = -1; + for(unsigned i=0; i=0 && component_flavour!=static_cast(flavour)) + { + error(swizzle, format("Flavour of swizzle component '%c' is inconsistent with '%c'", + swizzle.component_group[i], swizzle.component_group[0])); + flavour = -2; + } + + if(swizzle.components[i]>=size) + error(swizzle, format("Access to component '%c' which is not present in '%s'", + swizzle.component_group[i], swizzle.left->type->name)); + } + } + else if(swizzle.left->type) + error(swizzle, format("Swizzle applied to '%s' which is neither a scalar nor a vector", swizzle.left->type->name)); + + TraversingVisitor::visit(swizzle); +} + void ExpressionValidator::visit(UnaryExpression &unary) { if(unary.expression->type) diff --git a/source/glsl/validate.h b/source/glsl/validate.h index e5b8ed4e..2efb5199 100644 --- a/source/glsl/validate.h +++ b/source/glsl/validate.h @@ -88,6 +88,7 @@ public: void apply(Stage &s) { stage = &s; s.content.visit(*this); } private: + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); diff --git a/source/glsl/visitor.cpp b/source/glsl/visitor.cpp index ebcedb71..dfe2d8d4 100644 --- a/source/glsl/visitor.cpp +++ b/source/glsl/visitor.cpp @@ -26,6 +26,11 @@ void TraversingVisitor::visit(MemberAccess &memacc) memacc.left->visit(*this); } +void TraversingVisitor::visit(Swizzle &swizzle) +{ + swizzle.left->visit(*this); +} + void TraversingVisitor::visit(UnaryExpression &unary) { unary.expression->visit(*this); diff --git a/source/glsl/visitor.h b/source/glsl/visitor.h index 30b9b484..30ab2544 100644 --- a/source/glsl/visitor.h +++ b/source/glsl/visitor.h @@ -23,6 +23,7 @@ public: virtual void visit(VariableReference &) { } virtual void visit(InterfaceBlockReference &) { } virtual void visit(MemberAccess &) { } + virtual void visit(Swizzle &) { } virtual void visit(UnaryExpression &) { } virtual void visit(BinaryExpression &) { } virtual void visit(Assignment &) { } @@ -58,6 +59,7 @@ public: virtual void visit(Block &); virtual void visit(ParenthesizedExpression &); virtual void visit(MemberAccess &); + virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); diff --git a/tests/glsl/invalid_swizzle.glsl b/tests/glsl/invalid_swizzle.glsl new file mode 100644 index 00000000..4094ce51 --- /dev/null +++ b/tests/glsl/invalid_swizzle.glsl @@ -0,0 +1,15 @@ +#pragma MSP stage(vertex) +layout(location=0) in vec4 position; +layout(location=1) in vec2 texcoord; +void main() +{ + vec2 bad_component = texcoord.xz; + vec4 mixed = position.xyba; + gl_Position = position.xyzwx.xyzw; +} + +/* Expected error: +:6: Access to component 'z' which is not present in 'vec2' +:7: Flavour of swizzle component 'b' is inconsistent with 'x' +:8: Use of undeclared member 'xyzwx' +*/