]> git.tdb.fi Git - libs/gl.git/commitdiff
Recognize swizzles in GLSL
authorMikko Rasa <tdb@tdb.fi>
Mon, 8 Mar 2021 14:59:12 +0000 (16:59 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 9 Mar 2021 08:15:11 +0000 (10:15 +0200)
15 files changed:
source/glsl/debug.cpp
source/glsl/debug.h
source/glsl/generate.cpp
source/glsl/generate.h
source/glsl/optimize.cpp
source/glsl/optimize.h
source/glsl/output.cpp
source/glsl/output.h
source/glsl/syntax.cpp
source/glsl/syntax.h
source/glsl/validate.cpp
source/glsl/validate.h
source/glsl/visitor.cpp
source/glsl/visitor.h
tests/glsl/invalid_swizzle.glsl [new file with mode: 0644]

index ee50bf46e2ccb3af903f44249187cc70a5eb9fb4..fd1fd667257b788f86f4b523575d8af730afbd9d 100644 (file)
@@ -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<swizzle.count; ++i)
+               text += components[swizzle.components[i]];
+       text += format(" -> %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));
index d873ea379a9019241385b8106196fd1c503c6a1e..3837c569bb18e13aacf3d02a9d1d58eadecd5cb0 100644 (file)
@@ -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 &);
index 53676c26784cf7d32709639fea843459e3cf4269..3e53c1526daa88c43766dbfc4a019d267c317157 100644 (file)
@@ -1,3 +1,4 @@
+#include <algorithm>
 #include <msp/core/hash.h>
 #include <msp/core/raii.h>
 #include <msp/strings/lexicalcast.h>
@@ -367,11 +368,43 @@ void VariableResolver::visit(MemberAccess &memacc)
                if(i!=strct->members.variables.end())
                        declaration = i->second;
        }
+       else if(BasicTypeDeclaration *basic = dynamic_cast<BasicTypeDeclaration *>(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 && i<memacc.member.size()); ++i)
+                               ok = ((components[i] = (find(component_names, component_names+12, memacc.member[i])-component_names)/3) < 4);
+
+                       if(ok)
+                       {
+                               Swizzle *swizzle = new Swizzle;
+                               swizzle->source = 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<BasicTypeDeclaration *>(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);
index 427f4de2360d977819d02ba9373b5beb7dfee7fe..c0d1ef8d62b7cdea8e4e7d41d402745b62ceb943 100644 (file)
@@ -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 &);
index c1431f2b6e9d9e33ed522cd853bcd326bbb3414a..414cf38754191a85d8b6643811c3dc5c4764f4b4 100644 (file)
@@ -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<Expression>::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);
index 551e2d56976155a0d5b8b1e5c56e848fe95281e1..67d064c5328574bafe6f5bffdba2b1be081d9a94 100644 (file)
@@ -90,6 +90,7 @@ private:
        virtual void visit(BinaryExpression &);
        virtual void visit(Assignment &a) { visit(static_cast<BinaryExpression &>(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 &);
index 52371d1bfdd79f9f7de91ff457d10001952f6c62..b277ba8ee09fef2b2c38c4152dc136982c16d68f 100644 (file)
@@ -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)
index f720606eadbda1eeef757a39a7bb75bfbd4696d1..61c02caada72aed11f5e7361c55b639ccde449b9 100644 (file)
@@ -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 &);
index cb77419763645be5987842b9bd7d654eb30e13c5..85d805d1b67aeea72ee41bcec1855222732dc5ef 100644 (file)
@@ -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);
index 30acca42b957bd42b547b642173032160fcdd0df..c3eeb6a14c7c244cea696bab9508f0d0bdc50012 100644 (file)
@@ -6,6 +6,7 @@
 #include <set>
 #include <string>
 #include <vector>
+#include <msp/core/inttypes.h>
 #include <msp/core/refptr.h>
 #include <msp/core/variant.h>
 #include "features.h"
@@ -197,6 +198,19 @@ struct MemberAccess: Expression
        virtual void visit(NodeVisitor &);
 };
 
+struct Swizzle: Expression
+{
+       NodePtr<Expression> 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> expression;
index b0c6e3d67acb29cb178bbdeb1e7d2812ea16f5be..c4e0a9bda8aa6b21d80fca7e92a5b393217d4a53 100644 (file)
@@ -1,3 +1,4 @@
+#include <algorithm>
 #include <cstring>
 #include <msp/core/raii.h>
 #include <msp/strings/format.h>
@@ -227,6 +228,44 @@ void ReferenceValidator::visit(FunctionDeclaration &func)
 }
 
 
+void ExpressionValidator::visit(Swizzle &swizzle)
+{
+       unsigned size = 0;
+       if(BasicTypeDeclaration *basic = dynamic_cast<BasicTypeDeclaration *>(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<swizzle.count; ++i)
+               {
+                       unsigned component_flavour = (find(component_names, component_names+12, swizzle.component_group[i])-component_names)/4;
+                       if(flavour==-1)
+                               flavour = component_flavour;
+                       else if(flavour>=0 && component_flavour!=static_cast<unsigned>(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)
index e5b8ed4ebfa9397bea0220540b6f3719acf6a0b0..2efb5199660e149740693a04180d1ba643619d19 100644 (file)
@@ -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 &);
index ebcedb71242cc883bd2ef7b7c58ac6783867a19a..dfe2d8d46523a00d83b024f1e13dc261db36703d 100644 (file)
@@ -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);
index 30b9b484aa9a86948a9a0ae9604ace91c7ea5d1b..30ab25444f2aabe89636309b29d8a9dc56ed519d 100644 (file)
@@ -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 (file)
index 0000000..4094ce5
--- /dev/null
@@ -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:
+<test>:6: Access to component 'z' which is not present in 'vec2'
+<test>:7: Flavour of swizzle component 'b' is inconsistent with 'x'
+<test>:8: Use of undeclared member 'xyzwx'
+*/