From 8967d38bc578f1653c1dde01dce49a8f7b0c912e Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 4 Apr 2021 12:35:00 +0300 Subject: [PATCH] Add visitors to calculate offsets of struct members It's not used yet, but will be required for creating SPIR-V modules. --- source/glsl/finalize.cpp | 51 ++++++++++++++++++++++++++++++++ source/glsl/finalize.h | 16 ++++++++++ source/glsl/reflect.cpp | 64 ++++++++++++++++++++++++++++++++++++++++ source/glsl/reflect.h | 25 ++++++++++++++++ 4 files changed, 156 insertions(+) diff --git a/source/glsl/finalize.cpp b/source/glsl/finalize.cpp index 2d1a46fb..6e9a4780 100644 --- a/source/glsl/finalize.cpp +++ b/source/glsl/finalize.cpp @@ -12,6 +12,57 @@ namespace Msp { namespace GL { namespace SL { +StructOrganizer::StructOrganizer(): + offset(-1) +{ } + +void StructOrganizer::visit(StructDeclaration &strct) +{ + SetForScope set_offset(offset, 0); + TraversingVisitor::visit(strct); +} + +void StructOrganizer::visit(VariableDeclaration &var) +{ + if(offset>=0) + { + int *layout_offset = 0; + if(var.layout) + { + vector &qualifiers = var.layout->qualifiers; + for(vector::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::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) diff --git a/source/glsl/finalize.h b/source/glsl/finalize.h index 0638026d..fd29737a 100644 --- a/source/glsl/finalize.h +++ b/source/glsl/finalize.h @@ -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 diff --git a/source/glsl/reflect.cpp b/source/glsl/reflect.cpp index 688c99bf..151735ab 100644 --- a/source/glsl/reflect.cpp +++ b/source/glsl/reflect.cpp @@ -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::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 qualifiers = var.layout->qualifiers; + for(vector::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(var.array_size.get())) + if(literal->value.check_type()) + r_size += r_alignment*(literal->value.value()-1); +} + + set DependencyCollector::apply(FunctionDeclaration &func) { func.visit(*this); diff --git a/source/glsl/reflect.h b/source/glsl/reflect.h index 72a50c3e..162ed9c0 100644 --- a/source/glsl/reflect.h +++ b/source/glsl/reflect.h @@ -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 -- 2.45.2