]> git.tdb.fi Git - libs/gl.git/commitdiff
Add visitors to calculate offsets of struct members
authorMikko Rasa <tdb@tdb.fi>
Sun, 4 Apr 2021 09:35:00 +0000 (12:35 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 4 Apr 2021 09:35:00 +0000 (12:35 +0300)
It's not used yet, but will be required for creating SPIR-V modules.

source/glsl/finalize.cpp
source/glsl/finalize.h
source/glsl/reflect.cpp
source/glsl/reflect.h

index 2d1a46fb0862639457a1137a2de94036c6a1f7da..6e9a478012e0dad898065da952868d8bf03eff46 100644 (file)
@@ -12,6 +12,57 @@ namespace Msp {
 namespace GL {
 namespace SL {
 
+StructOrganizer::StructOrganizer():
+       offset(-1)
+{ }
+
+void StructOrganizer::visit(StructDeclaration &strct)
+{
+       SetForScope<int> set_offset(offset, 0);
+       TraversingVisitor::visit(strct);
+}
+
+void StructOrganizer::visit(VariableDeclaration &var)
+{
+       if(offset>=0)
+       {
+               int *layout_offset = 0;
+               if(var.layout)
+               {
+                       vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
+                       for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
+                               if(i->name=="offset" && i->has_value)
+                               {
+                                       layout_offset = &i->value;
+                                       if(i->value>=offset)
+                                               offset = i->value;
+                                       break;
+                               }
+               }
+
+               MemoryRequirementsCalculator::Result mem_reqs = MemoryRequirementsCalculator().apply(var);
+               offset += mem_reqs.alignment-1;
+               offset -= offset%mem_reqs.alignment;
+
+               if(layout_offset)
+                       *layout_offset = offset;
+               else
+               {
+                       if(!var.layout)
+                               var.layout = new Layout;
+
+                       Layout::Qualifier qual;
+                       qual.name = "offset";
+                       qual.has_value = true;
+                       qual.value = offset;
+                       var.layout->qualifiers.push_back(qual);
+               }
+
+               offset += mem_reqs.size;
+       }
+}
+
+
 void LocationAllocator::apply(Module &module, const Features &features)
 {
        for(list<Stage>::iterator i=module.stages.begin(); i!=module.stages.end(); ++i)
index 0638026dba207f2e7d48a209d2a2f3d6ea49c11c..fd29737a713b3ed331e9ba4b0bddb2e13b9f72a6 100644 (file)
@@ -8,6 +8,22 @@ namespace Msp {
 namespace GL {
 namespace SL {
 
+/** Assigns offset layout qualifiers to struct members. */
+class StructOrganizer: private TraversingVisitor
+{
+private:
+       int offset;
+
+public:
+       StructOrganizer();
+
+       void apply(Stage &s) { s.content.visit(*this); }
+
+private:
+       virtual void visit(StructDeclaration &);
+       virtual void visit(VariableDeclaration &);
+};
+
 /** Assigns location and binding layout qualifiers to interface variables and
 blocks. */
 class LocationAllocator: private TraversingVisitor
index 688c99bf81b951ae288a23c9d5409e94fd7903c8..151735ab18f3790d51b94bbf61da68726ce56a39 100644 (file)
@@ -44,6 +44,70 @@ void LocationCounter::visit(VariableDeclaration &var)
 }
 
 
+void MemoryRequirementsCalculator::visit(BasicTypeDeclaration &basic)
+{
+       if(basic.kind==BasicTypeDeclaration::BOOL)
+       {
+               r_size = 1;
+               r_alignment = 1;
+       }
+       else if(basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
+       {
+               r_size = basic.size/8;
+               r_alignment = r_size;
+       }
+       else if(basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX)
+       {
+               basic.base_type->visit(*this);
+               unsigned n_elem = basic.size&0xFFFF;
+               r_size *= n_elem;
+               if(basic.kind==BasicTypeDeclaration::VECTOR)
+                       r_alignment *= (n_elem==3 ? 4 : n_elem);
+       }
+       else if(basic.kind==BasicTypeDeclaration::ARRAY)
+               basic.base_type->visit(*this);
+}
+
+void MemoryRequirementsCalculator::visit(StructDeclaration &strct)
+{
+       unsigned total = 0;
+       unsigned max_align = 1;
+       for(NodeList<Statement>::iterator i=strct.members.body.begin(); i!=strct.members.body.end(); ++i)
+       {
+               r_size = 0;
+               r_alignment = 1;
+               r_offset = -1;
+               (*i)->visit(*this);
+               if(r_offset)
+                       total = r_offset;
+               total += r_alignment-1;
+               total -= total%r_alignment;
+               total += r_size;
+               max_align = max(max_align, r_alignment);
+       }
+       r_size = total;
+       r_alignment = max_align;
+}
+
+void MemoryRequirementsCalculator::visit(VariableDeclaration &var)
+{
+       if(var.layout)
+       {
+               const vector<Layout::Qualifier> qualifiers = var.layout->qualifiers;
+               for(vector<Layout::Qualifier>::const_iterator i=qualifiers.begin(); (r_offset<0 && i!=qualifiers.end()); ++i)
+                       if(i->name=="offset")
+                               r_offset = i->value;
+       }
+
+       if(var.type_declaration)
+               var.type_declaration->visit(*this);
+       if(var.array)
+               if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
+                       if(literal->value.check_type<int>())
+                               r_size += r_alignment*(literal->value.value<int>()-1);
+}
+
+
 set<Node *> DependencyCollector::apply(FunctionDeclaration &func)
 {
        func.visit(*this);
index 72a50c3eb6368b303ba5bd6e2fad8f7095e0189b..162ed9c0b8bcf4ddb01daf17724e4308138decd0 100644 (file)
@@ -25,6 +25,31 @@ private:
        virtual void visit(VariableDeclaration &);
 };
 
+/** Determines the size and alignment of a variable, in bytes. */
+class MemoryRequirementsCalculator: private NodeVisitor
+{
+public:
+       struct Result
+       {
+               unsigned size;
+               unsigned alignment;
+
+               Result(unsigned s, unsigned a): size(s), alignment(a) { }
+       };
+private:
+       unsigned r_size;
+       unsigned r_alignment;
+       int r_offset;
+
+public:
+       Result apply(VariableDeclaration &v) { v.visit(*this); return Result(r_size, r_alignment); }
+
+private:
+       virtual void visit(BasicTypeDeclaration &);
+       virtual void visit(StructDeclaration &);
+       virtual void visit(VariableDeclaration &);
+};
+
 /** Collects dependencies of a function.  This includes global variables,
 interface blocks, other functions and types. */
 class DependencyCollector: private TraversingVisitor