panfrost: gen_pack: Add the aggregate concept
Panfrost descriptors are big and are usually built from a combination of
sub-descriptors. On top of that, layout of sub-descriptors might vary
depending on the architecture version. Since unions are not really an
option (too complex), here is a thin abstraction layer allowing us to
manipulate aggregates in their packed format. Each aggregate is formed
of one or more sections that are meant to be packed/unpacked/printed
separately. Section overlapping is allowed to facilitate handling of
descriptor variants.
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6797>
diff --git a/src/panfrost/lib/gen_pack.py b/src/panfrost/lib/gen_pack.py
index 1877f27..c17b42c 100644
--- a/src/panfrost/lib/gen_pack.py
+++ b/src/panfrost/lib/gen_pack.py
@@ -145,6 +145,23 @@
#define pan_print(fp, T, var, indent) \\
MALI_ ## T ## _print(fp, &(var), indent)
+#define pan_section_ptr(base, A, S) \\
+ ((void *)((uint8_t *)(base) + MALI_ ## A ## _SECTION_ ## S ## _OFFSET))
+
+#define pan_section_pack(dst, A, S, name) \\
+ for (MALI_ ## A ## _SECTION_ ## S ## _TYPE name = { MALI_ ## A ## _SECTION_ ## S ## _header }, \\
+ *_loop_terminate = (void *) (dst); \\
+ __builtin_expect(_loop_terminate != NULL, 1); \\
+ ({ MALI_ ## A ## _SECTION_ ## S ## _pack(pan_section_ptr(dst, A, S), &name); \\
+ _loop_terminate = NULL; }))
+
+#define pan_section_unpack(src, A, S, name) \\
+ MALI_ ## A ## _SECTION_ ## S ## _TYPE name; \\
+ MALI_ ## A ## _SECTION_ ## S ## _unpack(pan_section_ptr(src, A, S), &name)
+
+#define pan_section_print(fp, A, S, var, indent) \\
+ MALI_ ## A ## _SECTION_ ## S ## _print(fp, &(var), indent)
+
"""
def to_alphanum(name):
@@ -209,6 +226,43 @@
print("Invalid modifier")
assert(False)
+class Aggregate(object):
+ def __init__(self, parser, name, attrs):
+ self.parser = parser
+ self.sections = []
+ self.name = name
+ self.explicit_size = int(attrs["size"]) if "size" in attrs else 0
+ self.size = 0
+
+ class Section:
+ def __init__(self, name):
+ self.name = name
+
+ def get_size(self):
+ if self.size > 0:
+ return self.size
+
+ size = 0
+ for section in self.sections:
+ size = max(size, section.offset + section.type.get_length())
+
+ if self.explicit_size > 0:
+ assert(self.explicit_size >= size)
+ self.size = self.explicit_size
+ else:
+ self.size = size
+ return self.size
+
+ def add_section(self, type_name, attrs):
+ assert("name" in attrs)
+ section = self.Section(safe_name(attrs["name"]).lower())
+ section.human_name = attrs["name"]
+ section.offset = int(attrs["offset"])
+ assert(section.offset % 4 == 0)
+ section.type = self.parser.structs[attrs["type"]]
+ section.type_name = type_name
+ self.sections.append(section)
+
class Field(object):
def __init__(self, parser, attrs):
self.parser = parser
@@ -279,7 +333,6 @@
def overlaps(self, field):
return self != field and max(self.start, field.start) <= min(self.end, field.end)
-
class Group(object):
def __init__(self, parser, parent, start, count):
self.parser = parser
@@ -537,6 +590,8 @@
self.structs = {}
# Set of enum names we've seen.
self.enums = set()
+ self.aggregate = None
+ self.aggregates = {}
def gen_prefix(self, name):
return '{}_{}'.format(global_prefix.upper(), name)
@@ -568,6 +623,13 @@
self.prefix= None
elif name == "value":
self.values.append(Value(attrs))
+ elif name == "aggregate":
+ aggregate_name = self.gen_prefix(safe_name(attrs["name"].upper()))
+ self.aggregate = Aggregate(self, aggregate_name, attrs)
+ self.aggregates[attrs['name']] = self.aggregate
+ elif name == "section":
+ type_name = self.gen_prefix(safe_name(attrs["type"].upper()))
+ self.aggregate.add_section(type_name, attrs)
def end_element(self, name):
if name == "struct":
@@ -579,6 +641,9 @@
elif name == "enum":
self.emit_enum()
self.enum = None
+ elif name == "aggregate":
+ self.emit_aggregate()
+ self.aggregate = None
elif name == "panxml":
# Include at the end so it can depend on us but not the converse
print('#include "panfrost-job.h"')
@@ -610,6 +675,21 @@
# Just so it isn't left undefined
print('#define %-40s 0' % (name + '_OPAQUE_header'))
+ def emit_aggregate(self):
+ aggregate = self.aggregate
+ print("struct %s_packed {" % aggregate.name.lower())
+ print(" uint32_t opaque[{}];".format(aggregate.get_size() // 4))
+ print("};\n")
+ print('#define {}_LENGTH {}'.format(aggregate.name.upper(), aggregate.size))
+ for section in aggregate.sections:
+ print('#define {}_SECTION_{}_TYPE struct {}'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
+ print('#define {}_SECTION_{}_header {}_header'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
+ print('#define {}_SECTION_{}_pack {}_pack'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
+ print('#define {}_SECTION_{}_unpack {}_unpack'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
+ print('#define {}_SECTION_{}_print {}_print'.format(aggregate.name.upper(), section.name.upper(), section.type_name))
+ print('#define {}_SECTION_{}_OFFSET {}'.format(aggregate.name.upper(), section.name.upper(), section.offset))
+ print("")
+
def emit_pack_function(self, name, group, with_opaque):
print("static inline void\n%s_pack(uint32_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
(name, ' ' * (len(name) + 6), name))