diff --git a/src/gallium/drivers/lima/genxml/common.xml b/src/gallium/drivers/lima/genxml/common.xml
new file mode 100644
index 00000000000..80c809c273b
--- /dev/null
+++ b/src/gallium/drivers/lima/genxml/common.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/gallium/drivers/lima/genxml/gen_pack.py b/src/gallium/drivers/lima/genxml/gen_pack.py
new file mode 100644
index 00000000000..992e1ff1c03
--- /dev/null
+++ b/src/gallium/drivers/lima/genxml/gen_pack.py
@@ -0,0 +1,668 @@
+#encoding=utf-8
+
+# Copyright 2016 Intel Corporation
+# Copyright 2016 Broadcom
+# Copyright 2020 Collabora, Ltd.
+# Copyright 2025 Lima Project
+# SPDX-License-Identifier: MIT
+
+import xml.parsers.expat
+import sys
+import operator
+import math
+import platform
+from functools import reduce
+
+global_prefix = "lima"
+
+def to_alphanum(name):
+ substitutions = {
+ ' ': '_',
+ '/': '_',
+ '[': '',
+ ']': '',
+ '(': '',
+ ')': '',
+ '-': '_',
+ ':': '',
+ '.': '',
+ ',': '',
+ '=': '',
+ '>': '',
+ '#': '',
+ '&': '',
+ '*': '',
+ '"': '',
+ '+': '',
+ '\'': '',
+ '?': '',
+ }
+
+ for i, j in substitutions.items():
+ name = name.replace(i, j)
+
+ return name
+
+def safe_name(name):
+ name = to_alphanum(name)
+ if not name[0].isalpha():
+ name = '_' + name
+
+ return name
+
+def prefixed_upper_name(prefix, name):
+ if prefix:
+ name = prefix + "_" + name
+ return safe_name(name).upper()
+
+def enum_name(name):
+ return f"{global_prefix}_{safe_name(name)}".lower()
+
+MODIFIERS = ["shr", "minus", "align", "log2", "groups"]
+
+def parse_modifier(modifier):
+ if modifier is None:
+ return None
+
+ for mod in MODIFIERS:
+ if modifier[0:len(mod)] == mod:
+ if mod == "log2":
+ assert(len(mod) == len(modifier))
+ return [mod]
+
+ if modifier[len(mod)] == '(' and modifier[-1] == ')':
+ ret = [mod, int(modifier[(len(mod) + 1):-1])]
+ if ret[0] == 'align':
+ align = ret[1]
+ # Make sure the alignment is a power of 2
+ assert(align > 0 and not(align & (align - 1)));
+
+ return ret
+
+ print("Invalid modifier")
+ assert(False)
+
+class Field(object):
+ def __init__(self, parser, attrs):
+ self.parser = parser
+ if "name" in attrs:
+ self.name = safe_name(attrs["name"]).lower()
+ self.human_name = attrs["name"]
+
+ if ":" in str(attrs["start"]):
+ (word, bit) = attrs["start"].split(":")
+ self.start = (int(word) * 32) + int(bit)
+ else:
+ self.start = int(attrs["start"])
+
+ self.end = self.start + int(attrs["size"]) - 1
+ self.type = attrs["type"]
+
+ if self.type == 'bool' and self.start != self.end:
+ print(f"#error Field {self.name} has bool type but more than one bit of size");
+
+ if "prefix" in attrs:
+ self.prefix = safe_name(attrs["prefix"]).upper()
+ else:
+ self.prefix = None
+
+ self.modifier = parse_modifier(attrs.get("modifier"))
+ self.exact = attrs.get("exact")
+ self.default = None
+
+ if self.exact is not None:
+ self.default = self.exact
+ elif self.modifier is not None:
+ # Set the default value to encode to zero
+ mod = self.modifier
+ if mod[0] == 'log2':
+ self.default = 1
+ elif mod[0] == 'minus':
+ self.default = mod[1]
+ elif mod[0] == 'groups':
+ # The zero encoding means "all"
+ self.default = (1 << int(attrs["size"])) * mod[1]
+ elif mod[0] in ['shr', 'align']:
+ # Zero encodes to zero
+ pass
+ else:
+ assert(0)
+
+ # Map enum values
+ if self.type in self.parser.enums and self.default is not None:
+ self.default = safe_name(f'{global_prefix}_{self.type}_{self.default}').upper()
+
+
+ def emit_template_struct(self, dim):
+ if self.type == 'address':
+ type = 'uint64_t'
+ elif self.type == 'bool':
+ type = 'bool'
+ elif self.type in ['float', 'half', 'unorm16', 'ulod', 'slod']:
+ type = 'float'
+ elif self.type in ['uint', 'hex'] and self.end - self.start > 32:
+ type = 'uint64_t'
+ elif self.type == 'int':
+ type = 'int32_t'
+ elif self.type in ['uint', 'hex']:
+ type = 'uint32_t'
+ elif self.type in self.parser.structs:
+ type = 'struct ' + self.parser.gen_prefix(safe_name(self.type.upper()))
+ elif self.type in self.parser.enums:
+ type = 'enum ' + enum_name(self.type)
+ else:
+ print(f"#error unhandled type: {self.type}")
+ type = "uint32_t"
+
+ print(" %-36s %s%s;" % (type, self.name, dim))
+
+ for value in self.values:
+ name = prefixed_upper_name(self.prefix, value.name)
+ print("#define %-40s %d" % (name, value.value))
+
+ 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, label):
+ self.parser = parser
+ self.parent = parent
+ self.start = start
+ self.count = count
+ self.label = label
+ self.size = 0
+ self.length = 0
+ self.fields = []
+
+ def get_length(self):
+ # Determine number of bytes in this group.
+ calculated = max(field.end // 8 for field in self.fields) + 1 if len(self.fields) > 0 else 0
+ if self.length > 0:
+ assert(self.length >= calculated)
+ else:
+ self.length = calculated
+ return self.length
+
+
+ def emit_template_struct(self, dim):
+ if self.count == 0:
+ print(" /* variable length fields follow */")
+ else:
+ if self.count > 1:
+ dim = "%s[%d]" % (dim, self.count)
+
+ any_fields = False
+ for field in self.fields:
+ if not field.exact:
+ field.emit_template_struct(dim)
+ any_fields = True
+
+ if not any_fields:
+ print(" int dummy;")
+
+ class Word:
+ def __init__(self):
+ self.size = 32
+ self.contributors = []
+
+ class FieldRef:
+ def __init__(self, field, path, start, end):
+ self.field = field
+ self.path = path
+ self.start = start
+ self.end = end
+
+ def collect_fields(self, fields, offset, path, all_fields):
+ for field in fields:
+ field_path = f'{path}{field.name}'
+ field_offset = offset + field.start
+
+ if field.type in self.parser.structs:
+ sub_struct = self.parser.structs[field.type]
+ self.collect_fields(sub_struct.fields, field_offset, field_path + '.', all_fields)
+ continue
+
+ start = field_offset
+ end = offset + field.end
+ all_fields.append(self.FieldRef(field, field_path, start, end))
+
+ def collect_words(self, fields, offset, path, words):
+ for field in fields:
+ field_path = f'{path}{field.name}'
+ start = offset + field.start
+
+ if field.type in self.parser.structs:
+ sub_fields = self.parser.structs[field.type].fields
+ self.collect_words(sub_fields, start, field_path + '.', words)
+ continue
+
+ end = offset + field.end
+ contributor = self.FieldRef(field, field_path, start, end)
+ first_word = contributor.start // 32
+ last_word = contributor.end // 32
+ for b in range(first_word, last_word + 1):
+ if not b in words:
+ words[b] = self.Word()
+ words[b].contributors.append(contributor)
+
+ def emit_pack_function(self):
+ self.get_length()
+
+ words = {}
+ self.collect_words(self.fields, 0, '', words)
+
+ # Validate the modifier is lossless
+ for field in self.fields:
+ if field.modifier is None:
+ continue
+
+ if field.modifier[0] == "shr":
+ shift = field.modifier[1]
+ mask = hex((1 << shift) - 1)
+ print(f" assert((values->{field.name} & {mask}) == 0);")
+ elif field.modifier[0] == "minus":
+ print(f" assert(values->{field.name} >= {field.modifier[1]});")
+ elif field.modifier[0] == "log2":
+ print(f" assert(IS_POT_NONZERO(values->{field.name}));")
+
+ for index in range(math.ceil(self.length / 4)):
+ # Handle MBZ words
+ if not index in words:
+ print(" cl[%2d] = 0;" % index)
+ continue
+
+ word = words[index]
+
+ word_start = index * 32
+
+ v = None
+ prefix = " cl[%2d] =" % index
+
+ lines = []
+
+ for contributor in word.contributors:
+ field = contributor.field
+ name = field.name
+ start = contributor.start
+ end = contributor.end
+ contrib_word_start = (start // 32) * 32
+ start -= contrib_word_start
+ end -= contrib_word_start
+
+ value = f"values->{contributor.path}"
+ if field.exact:
+ value = field.default
+
+ # These types all use util_bitpack_uint
+ pack_as_uint = field.type in ["uint", "hex", "address", "bool"]
+ pack_as_uint |= field.type in self.parser.enums
+ start_adjusted = start
+ value_unshifted = None
+
+ if field.modifier is not None:
+ if field.modifier[0] == "shr":
+ if pack_as_uint and start >= field.modifier[1]:
+ # For uint, we fast path. If we do `(a >> 2) << 2`,
+ # clang will generate a mask in release builds, even
+ # though we know we're aligned. So don't generate
+ # that to avoid the masking.
+ start_adjusted = start - field.modifier[1]
+ else:
+ value = f"{value} >> {field.modifier[1]}"
+ elif field.modifier[0] == "minus":
+ value = f"{value} - {field.modifier[1]}"
+ elif field.modifier[0] == "align":
+ value = f"ALIGN_POT({value}, {field.modifier[1]})"
+ elif field.modifier[0] == "log2":
+ value = f"util_logbase2({value})"
+ elif field.modifier[0] == "groups":
+ value = "__gen_to_groups({}, {}, {})".format(value,
+ field.modifier[1], end - start + 1)
+
+ if pack_as_uint:
+ bits = (end - start_adjusted + 1)
+ if bits < 64 and not field.exact:
+ # Add some nicer error checking
+ label = f"{self.label}::{name}"
+ bound = hex(1 << bits)
+ print(f" lima_genxml_validate_bounds(\"{label}\", {value}, {bound}ull);")
+
+ s = f"util_bitpack_uint({value}, {start_adjusted}, {end})"
+ elif field.type == "int":
+ s = "util_bitpack_sint(%s, %d, %d)" % \
+ (value, start, end)
+ elif field.type == "float":
+ assert(start == 0 and end == 31)
+ s = f"util_bitpack_float({value})"
+ elif field.type == "half":
+ assert(start == 0 and end == 15)
+ s = f"_mesa_float_to_half({value})"
+ elif field.type == "unorm16":
+ assert(end - start + 1 == 16)
+ s = "__gen_pack_unorm16(%s, %d, %d)" % (value, start, end)
+ elif field.type == "ulod":
+ s = "util_bitpack_ufixed_clamp({}, {}, {}, 4)".format(value,
+ start,
+ end)
+ elif field.type == "slod":
+ s = "util_bitpack_sfixed_clamp({}, {}, {}, 4)".format(value,
+ start,
+ end)
+ else:
+ s = f"#error unhandled field {contributor.path}, type {field.type}"
+
+ if not s == None:
+ shift = word_start - contrib_word_start
+ if shift:
+ s = "%s >> %d" % (s, shift)
+
+ if contributor == word.contributors[-1]:
+ lines.append(f"{prefix} {s};")
+ else:
+ lines.append(f"{prefix} {s} |")
+ prefix = " "
+
+ for ln in lines:
+ print(ln)
+
+ continue
+
+ # Given a field (start, end) contained in word `index`, generate the 32-bit
+ # mask of present bits relative to the word
+ def mask_for_word(self, index, start, end):
+ field_word_start = index * 32
+ start -= field_word_start
+ end -= field_word_start
+ # Cap multiword at one word
+ start = max(start, 0)
+ end = min(end, 32 - 1)
+ count = (end - start + 1)
+ return (((1 << count) - 1) << start)
+
+ def emit_unpack_function(self):
+ # First, verify there is no garbage in unused bits
+ words = {}
+ self.collect_words(self.fields, 0, '', words)
+ validation = []
+
+ for index in range(self.length // 4):
+ base = index * 32
+ word = words.get(index, self.Word())
+ masks = [self.mask_for_word(index, c.start, c.end) for c in word.contributors]
+ mask = reduce(lambda x,y: x | y, masks, 0)
+
+ ALL_ONES = 0xffffffff
+
+ if mask != ALL_ONES:
+ bad_mask = hex(mask ^ ALL_ONES)
+ validation.append(f'lima_genxml_validate_mask(fp, \"{self.label}\", cl, {index}, {bad_mask})')
+
+ fieldrefs = []
+ self.collect_fields(self.fields, 0, '', fieldrefs)
+ for fieldref in fieldrefs:
+ field = fieldref.field
+ convert = None
+
+ args = []
+ args.append('(CONSTANT_ uint32_t *) cl')
+ args.append(str(fieldref.start))
+ args.append(str(fieldref.end))
+
+ if field.type in set(["uint", "address", "hex"]) | self.parser.enums:
+ convert = "__gen_unpack_uint"
+ elif field.type == "int":
+ convert = "__gen_unpack_sint"
+ elif field.type == "bool":
+ convert = "__gen_unpack_uint"
+ elif field.type == "float":
+ convert = "__gen_unpack_float"
+ elif field.type == "half":
+ convert = "__gen_unpack_half"
+ elif field.type == "unorm16":
+ convert = "__gen_unpack_unorm16"
+ elif field.type == "ulod":
+ convert = "__gen_unpack_ulod"
+ elif field.type == "slod":
+ convert = "__gen_unpack_slod"
+ else:
+ s = f"/* unhandled field {field.name}, type {field.type} */\n"
+
+ suffix = ""
+ prefix = ""
+ if field.modifier:
+ if field.modifier[0] == "minus":
+ suffix = f" + {field.modifier[1]}"
+ elif field.modifier[0] == "shr":
+ suffix = f" << {field.modifier[1]}"
+ if field.modifier[0] == "log2":
+ prefix = "1 << "
+ elif field.modifier[0] == "groups":
+ prefix = "__gen_from_groups("
+ suffix = ", {}, {})".format(field.modifier[1],
+ fieldref.end - fieldref.start + 1)
+
+ if field.type in self.parser.enums and not field.exact:
+ prefix = f"(enum {enum_name(field.type)}) {prefix}"
+
+ decoded = f"{prefix}{convert}({', '.join(args)}){suffix}"
+
+ if field.exact:
+ name = self.label
+ validation.append(f'lima_genxml_validate_exact(fp, \"{name}\", {decoded}, {field.default})')
+ else:
+ print(f' values->{fieldref.path} = {decoded};')
+
+ if field.modifier and field.modifier[0] == "align":
+ assert(not field.exact)
+ mask = hex(field.modifier[1] - 1)
+ print(f' assert(!(values->{fieldref.path} & {mask}));')
+
+ if len(validation) > 1:
+ print(' bool valid = true;')
+ for v in validation:
+ print(f' valid &= {v};')
+ print(" return valid;")
+ elif len(validation) == 1:
+ print(f" return {validation[0]};")
+ else:
+ print(" return true;")
+
+ def emit_print_function(self):
+ for field in self.fields:
+ convert = None
+ name, val = field.human_name, f'values->{field.name}'
+
+ if field.exact:
+ continue
+
+ if field.type in self.parser.structs:
+ pack_name = self.parser.gen_prefix(safe_name(field.type)).upper()
+ print(f' fprintf(fp, "%*s{field.human_name}:\\n", indent, "");')
+ print(f" {pack_name}_print(fp, &values->{field.name}, indent + 2);")
+ elif field.type == "address":
+ # TODO resolve to name
+ print(f' fprintf(fp, "%*s{name}: 0x%" PRIx64 "\\n", indent, "", {val});')
+ elif field.type in self.parser.enums:
+ print(f' if ({enum_name(field.type)}_as_str({val}))')
+ print(f' fprintf(fp, "%*s{name}: %s\\n", indent, "", {enum_name(field.type)}_as_str({val}));')
+ print(f' else')
+ print(f' fprintf(fp, "%*s{name}: unknown %X (XXX)\\n", indent, "", {val});')
+ elif field.type == "int":
+ print(f' fprintf(fp, "%*s{name}: %d\\n", indent, "", {val});')
+ elif field.type == "bool":
+ print(f' fprintf(fp, "%*s{name}: %s\\n", indent, "", {val} ? "true" : "false");')
+ elif field.type in ["float", "unorm16", "ulod", "slod", "half"]:
+ print(f' fprintf(fp, "%*s{name}: %f\\n", indent, "", {val});')
+ elif field.type in ["uint", "hex"] and (field.end - field.start) >= 32:
+ print(f' fprintf(fp, "%*s{name}: 0x%" PRIx64 "\\n", indent, "", {val});')
+ elif field.type == "hex":
+ print(f' fprintf(fp, "%*s{name}: 0x%" PRIx32 "\\n", indent, "", {val});')
+ else:
+ print(f' fprintf(fp, "%*s{name}: %u\\n", indent, "", {val});')
+
+class Value(object):
+ def __init__(self, attrs):
+ self.name = attrs["name"]
+ self.value = int(attrs["value"], 0)
+
+class Parser(object):
+ def __init__(self):
+ self.parser = xml.parsers.expat.ParserCreate()
+ self.parser.StartElementHandler = self.start_element
+ self.parser.EndElementHandler = self.end_element
+ self.os = platform.system().lower()
+
+ self.struct = None
+ self.structs = {}
+ # Set of enum names we've seen.
+ self.enums = set()
+
+ def gen_prefix(self, name):
+ return f'{global_prefix.upper()}_{name}'
+
+ def start_element(self, name, attrs):
+ if "os" in attrs and attrs["os"] != self.os:
+ return
+
+ if name == "genxml":
+ print(pack_header)
+ elif name == "struct":
+ name = attrs["name"]
+ object_name = self.gen_prefix(safe_name(name.upper()))
+ self.struct = object_name
+
+ self.group = Group(self, None, 0, 1, name)
+ if "size" in attrs:
+ self.group.length = int(attrs["size"])
+ self.group.align = int(attrs["align"]) if "align" in attrs else None
+ self.structs[attrs["name"]] = self.group
+ elif name == "field" and self.group is not None:
+ self.group.fields.append(Field(self, attrs))
+ self.values = []
+ elif name == "enum":
+ self.values = []
+ self.enum = safe_name(attrs["name"])
+ self.enums.add(attrs["name"])
+ if "prefix" in attrs:
+ self.prefix = attrs["prefix"]
+ else:
+ self.prefix= None
+ elif name == "value":
+ self.values.append(Value(attrs))
+
+ def end_element(self, name):
+ if name == "struct":
+ if self.struct is not None:
+ self.emit_struct()
+ self.struct = None
+
+ self.group = None
+ elif name == "field" and self.group is not None:
+ self.group.fields[-1].values = self.values
+ elif name == "enum":
+ self.emit_enum()
+ self.enum = None
+
+ def emit_header(self, name):
+ default_fields = []
+ for field in self.group.fields:
+ if not type(field) is Field or field.exact:
+ continue
+ if field.default is not None:
+ default_fields.append(f" .{field.name} = {field.default}")
+ elif field.type in self.structs:
+ default_fields.append(f" .{field.name} = {{ {self.gen_prefix(safe_name(field.type.upper()))}_header }}")
+
+ if default_fields:
+ print('#define %-40s\\' % (name + '_header'))
+ print(", \\\n".join(default_fields))
+ else:
+ print(f'#define {name}_header 0')
+ print('')
+
+ def emit_template_struct(self, name, group):
+ print("struct %s {" % name)
+ group.emit_template_struct("")
+ print("};\n")
+
+ def emit_pack_function(self, name, group):
+ print("static inline void\n%s_pack(GLOBAL_ uint32_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
+ (name, ' ' * (len(name) + 6), name))
+
+ group.emit_pack_function()
+
+ print("}\n")
+
+ print(f"#define {name + '_LENGTH'} {self.group.length}")
+ if self.group.align != None:
+ print(f"#define {name + '_ALIGN'} {self.group.align}")
+
+ # round up to handle 6 half-word USC structures
+ words = (self.group.length + 4 - 1) // 4
+ print(f'struct {name.lower()}_packed {{ uint32_t opaque[{words}];}};')
+
+ def emit_unpack_function(self, name, group):
+ print("static inline bool")
+ print("%s_unpack(FILE_TYPE *fp, CONSTANT_ uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %
+ (name.upper(), ' ' * (len(name) + 8), name))
+
+ group.emit_unpack_function()
+
+ print("}\n")
+
+ def emit_print_function(self, name, group):
+ print("static inline void")
+ print(f"{name.upper()}_print(FILE *fp, const struct {name} * values, unsigned indent)\n{{")
+
+ group.emit_print_function()
+
+ print("}")
+
+ def emit_struct(self):
+ name = self.struct
+
+ self.emit_template_struct(self.struct, self.group)
+ self.emit_header(name)
+ self.emit_pack_function(self.struct, self.group)
+ self.emit_unpack_function(self.struct, self.group)
+ self.emit_print_function(self.struct, self.group)
+
+ def enum_prefix(self, name):
+ return
+
+ def emit_enum(self):
+ e_name = enum_name(self.enum)
+ prefix = e_name if self.enum != 'Format' else global_prefix
+ print(f'enum {e_name} {{')
+
+ for value in self.values:
+ name = f'{prefix}_{value.name}'
+ name = safe_name(name).upper()
+ print(f' {name} = {value.value},')
+ print('};\n')
+
+ print("static inline const char *")
+ print(f"{e_name.lower()}_as_str(enum {e_name} imm)\n{{")
+ print(" switch (imm) {")
+ for value in self.values:
+ name = f'{prefix}_{value.name}'
+ name = safe_name(name).upper()
+ print(f' case {name}: return "{value.name}";')
+ print(' default: return NULL;')
+ print(" }")
+ print("}")
+
+ def parse(self, filename):
+ file = open(filename, "rb")
+ self.parser.ParseFile(file)
+ file.close()
+
+if len(sys.argv) < 3:
+ print("Missing input files file specified")
+ sys.exit(1)
+
+input_file = sys.argv[1]
+pack_header = open(sys.argv[2]).read()
+
+p = Parser()
+p.parse(input_file)
diff --git a/src/gallium/drivers/lima/genxml/lima_pack_header.h b/src/gallium/drivers/lima/genxml/lima_pack_header.h
new file mode 100644
index 00000000000..86ef081f50e
--- /dev/null
+++ b/src/gallium/drivers/lima/genxml/lima_pack_header.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2016 Intel Corporation
+ * Copyright 2016 Broadcom
+ * Copyright 2020 Collabora, Ltd.
+ * Copyright 2024 Alyssa Rosenzweig
+ * Copyright 2025 Lima Project
+ * SPDX-License-Identifier: MIT
+ */
+
+#pragma once
+
+#include
+#include
+#include "util/bitpack_helpers.h"
+#include "util/half_float.h"
+#define FILE_TYPE FILE
+#define CONSTANT_ const
+#define GLOBAL_
+
+#define __gen_unpack_float(x, y, z) uif(__gen_unpack_uint(x, y, z))
+#define __gen_unpack_half(x, y, z) \
+ _mesa_half_to_float(__gen_unpack_uint(x, y, z))
+
+static inline uint64_t
+__gen_unpack_uint(CONSTANT_ uint32_t *restrict cl, uint32_t start, uint32_t end)
+{
+ uint64_t val = 0;
+ const int width = end - start + 1;
+ const uint64_t mask =
+ (width == 64) ? ~((uint64_t)0) : ((uint64_t)1 << width) - 1;
+
+ for (unsigned word = start / 32; word < (end / 32) + 1; word++) {
+ val |= ((uint64_t)cl[word]) << ((word - start / 32) * 32);
+ }
+
+ return (val >> (start % 32)) & mask;
+}
+
+static inline uint64_t
+__gen_pack_unorm16(float f, uint32_t start, uint32_t end)
+{
+ return util_bitpack_uint(float_to_ushort(f), start, end);
+}
+
+static inline float
+__gen_unpack_unorm16(CONSTANT_ uint32_t *restrict cl, uint32_t start, uint32_t end)
+{
+ return ushort_to_float(__gen_unpack_uint(cl, start, end));
+}
+
+static inline uint64_t
+__gen_unpack_sint(CONSTANT_ uint32_t *restrict cl, uint32_t start, uint32_t end)
+{
+ int size = end - start + 1;
+ int64_t val = __gen_unpack_uint(cl, start, end);
+
+ return util_sign_extend(val, size);
+}
+
+static inline float
+__gen_unpack_ulod(const uint32_t *restrict cl, uint32_t start, uint32_t end)
+{
+ uint32_t u = __gen_unpack_uint(cl, start, end);
+
+ return ((float)u) / 16.0;
+}
+
+static inline float
+__gen_unpack_slod(const uint32_t *restrict cl, uint32_t start, uint32_t end)
+{
+ int32_t u = __gen_unpack_sint(cl, start, end);
+
+ return ((float)u) / 16.0;
+}
+
+static inline uint64_t
+__gen_to_groups(uint32_t value, uint32_t group_size, uint32_t length)
+{
+ /* Zero is not representable, clamp to minimum */
+ if (value == 0)
+ return 1;
+
+ /* Round up to the nearest number of groups */
+ uint32_t groups = DIV_ROUND_UP(value, group_size);
+
+ /* The 0 encoding means "all" */
+ if (groups == ((uint64_t)1) << length)
+ return 0;
+
+ /* Otherwise it's encoded as the identity */
+ assert(groups < (1u << length) && "out of bounds");
+ assert(groups >= 1 && "exhaustive");
+ return groups;
+}
+
+static inline uint64_t
+__gen_from_groups(uint32_t value, uint32_t group_size, uint32_t length)
+{
+ return group_size * (value ? value : (1 << length));
+}
+
+#define lima_pack(dst, T, name) \
+ for (struct LIMA_##T name = {LIMA_##T##_header}, \
+ *_loop_count = (GLOBAL_ void *)((uintptr_t)0); \
+ (uintptr_t)_loop_count < 1; ( \
+ { \
+ LIMA_##T##_pack((GLOBAL_ uint32_t *)(dst), &name); \
+ _loop_count = (GLOBAL_ void *)(((uintptr_t)_loop_count) + 1); \
+ }))
+
+#define lima_unpack(fp, src, T, name) \
+ struct LIMA_##T name; \
+ LIMA_##T##_unpack(fp, (CONSTANT_ uint8_t *)(src), &name)
+
+#define lima_print(fp, T, var, indent) LIMA_##T##_print(fp, &(var), indent)
+
+static inline void
+lima_merge_helper(uint32_t *dst, const uint32_t *src, size_t bytes)
+{
+ assert((bytes & 3) == 0);
+
+ for (unsigned i = 0; i < (bytes / 4); ++i)
+ dst[i] |= src[i];
+}
+
+#define lima_merge(packed1, packed2, type) \
+ lima_merge_helper((packed1).opaque, (packed2).opaque, LIMA_##type##_LENGTH)
+
+#if defined(NDEBUG)
+#define lima_genxml_validate_bounds(a, b, c)
+#define lima_genxml_validate_mask(a, b, c, d, e) true
+#define lima_genxml_validate_exact(a, b, c, d) true
+#else
+static inline void
+lima_genxml_validate_bounds(const char *name, uint64_t value, uint64_t bound)
+{
+ if (unlikely(value >= bound)) {
+ fprintf(stderr, "%s out-of-bounds, got 0x%" PRIx64 ", max %" PRIx64 "\n",
+ name, value, bound);
+
+ unreachable("Out-of-bounds pack");
+ }
+}
+
+static inline bool
+lima_genxml_validate_mask(FILE *fp, const char *name, const void *cl_,
+ uint32_t index, uint32_t bad_mask)
+{
+ const uint32_t *cl = (const uint32_t *)cl_;
+ uint32_t bad = cl[index] & bad_mask;
+
+ if (bad && fp != NULL) {
+ fprintf(
+ fp,
+ "XXX: Unknown field of %s unpacked at word %u got %X, bad mask %X\n",
+ name, index, cl[index], bad);
+ }
+
+ return bad == 0;
+}
+
+static bool
+lima_genxml_validate_exact(FILE *fp, const char *name, uint64_t value,
+ uint64_t exact)
+{
+ if (value != exact && fp != NULL) {
+ fprintf(fp, "XXX: Expected %s to equal %" PRIx64 " but got %" PRIx64 "\n",
+ name, value, exact);
+ }
+
+ return value == exact;
+}
+
+#endif
+
+/* Everything after this is autogenerated from XML. Do not hand edit. */
diff --git a/src/gallium/drivers/lima/genxml/meson.build b/src/gallium/drivers/lima/genxml/meson.build
new file mode 100644
index 00000000000..797ee42381a
--- /dev/null
+++ b/src/gallium/drivers/lima/genxml/meson.build
@@ -0,0 +1,19 @@
+# Copyright 2017 Intel Corporation
+# Copyright 2025 Lima Project
+# SPDX-License-Identifier: MIT
+
+lima_pack = custom_target(
+ 'lima_pack.h',
+ input : ['gen_pack.py', 'common.xml', 'lima_pack_header.h'],
+ output : 'lima_pack.h',
+ command : [prog_python, '@INPUT@'],
+ capture : true,
+)
+
+idep_lima_pack = declare_dependency(
+ sources : [lima_pack],
+ dependencies : dep_valgrind,
+ include_directories : include_directories('.'),
+)
+
+
diff --git a/src/gallium/drivers/lima/lima_blit.c b/src/gallium/drivers/lima/lima_blit.c
index a0901d2afac..a90a570ea5a 100644
--- a/src/gallium/drivers/lima/lima_blit.c
+++ b/src/gallium/drivers/lima/lima_blit.c
@@ -100,22 +100,22 @@ lima_pack_blit_cmd(struct lima_job *job,
memcpy(cpu + lima_blit_render_state_offset, &reload_render_state,
sizeof(reload_render_state));
- lima_tex_desc *td = cpu + lima_blit_tex_desc_offset;
- memset(td, 0, lima_min_tex_desc_size);
- lima_texture_desc_set_res(ctx, td, psurf->texture, level, level,
- first_layer, mrt_idx);
- td->format = lima_format_get_texel_reload(psurf->format);
- td->unnorm_coords = 1;
- td->sampler_dim = LIMA_SAMPLER_DIM_2D;
- td->min_img_filter_nearest = 1;
- td->mag_img_filter_nearest = 1;
- td->wrap_s = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
- td->wrap_t = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
- td->wrap_r = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
+ lima_pack(cpu + lima_blit_tex_desc_offset, TEXTURE_DESCRIPTOR, desc) {
+ lima_texture_desc_set_res(ctx, &desc, psurf->texture, level, level,
+ first_layer, mrt_idx);
+ desc.texel_format = lima_format_get_texel_reload(psurf->format);
+ desc.unnorm_coords = true;
+ desc.sampler_dim = LIMA_SAMPLER_DIMENSION_2D;
+ desc.min_img_filter_nearest = true;
+ desc.mag_img_filter_nearest = true;
+ desc.wrap_s = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
+ desc.wrap_t = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
+ desc.wrap_r = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
- if (filter != PIPE_TEX_FILTER_NEAREST) {
- td->min_img_filter_nearest = 0;
- td->mag_img_filter_nearest = 0;
+ if (filter != PIPE_TEX_FILTER_NEAREST) {
+ desc.min_img_filter_nearest = false;
+ desc.mag_img_filter_nearest = false;
+ }
}
uint32_t *ta = cpu + lima_blit_tex_array_offset;
diff --git a/src/gallium/drivers/lima/lima_format.c b/src/gallium/drivers/lima/lima_format.c
index 3f07ea7419a..ff09ab3b8b2 100644
--- a/src/gallium/drivers/lima/lima_format.c
+++ b/src/gallium/drivers/lima/lima_format.c
@@ -30,30 +30,7 @@
#include
#include "lima_format.h"
-
-#define LIMA_TEXEL_FORMAT_L8 0x09
-#define LIMA_TEXEL_FORMAT_A8 0x0a
-#define LIMA_TEXEL_FORMAT_I8 0x0b
-#define LIMA_TEXEL_FORMAT_BGR_565 0x0e
-#define LIMA_TEXEL_FORMAT_BGRA_5551 0x0f
-#define LIMA_TEXEL_FORMAT_BGRA_4444 0x10
-#define LIMA_TEXEL_FORMAT_L8A8 0x11
-#define LIMA_TEXEL_FORMAT_L16 0x12
-#define LIMA_TEXEL_FORMAT_A16 0x13
-#define LIMA_TEXEL_FORMAT_I16 0x14
-#define LIMA_TEXEL_FORMAT_RGB_888 0x15
-#define LIMA_TEXEL_FORMAT_RGBA_8888 0x16
-#define LIMA_TEXEL_FORMAT_RGBX_8888 0x17
-#define LIMA_TEXEL_FORMAT_ETC1_RGB8 0x20
-#define LIMA_TEXEL_FORMAT_L16_FLOAT 0x22
-#define LIMA_TEXEL_FORMAT_A16_FLOAT 0x23
-#define LIMA_TEXEL_FORMAT_I16_FLOAT 0x24
-#define LIMA_TEXEL_FORMAT_L16A16_FLOAT 0x25
-#define LIMA_TEXEL_FORMAT_R16G16B16A16_FLOAT 0x26
-#define LIMA_TEXEL_FORMAT_R16G16B16_FLOAT 0x2f
-#define LIMA_TEXEL_FORMAT_Z24X8 0x2c
-/* This format is only used for depth/stencil reload */
-#define LIMA_TEXEL_FORMAT_Z24S8_RLD 0x32
+#include "genxml/lima_pack.h"
#define LIMA_PIXEL_FORMAT_B5G6R5 0x00
#define LIMA_PIXEL_FORMAT_B5G5R5A1 0x01
diff --git a/src/gallium/drivers/lima/lima_parser.c b/src/gallium/drivers/lima/lima_parser.c
index da8379975da..d13b7e8dc5a 100644
--- a/src/gallium/drivers/lima/lima_parser.c
+++ b/src/gallium/drivers/lima/lima_parser.c
@@ -730,112 +730,11 @@ lima_parse_render_state(FILE *fp, uint32_t *data, int size, uint32_t start)
fprintf(fp, "/* ============ RSW END =========================== */\n");
}
-static void
-parse_texture(FILE *fp, uint32_t *data, uint32_t start, uint32_t offset)
-{
- uint32_t i = 0;
- offset /= 4;
- lima_tex_desc *desc = (lima_tex_desc *)&data[offset];
-
- /* Word 0 */
- fprintf(fp, "/* 0x%08x (0x%08x) */\t0x%08x\n",
- start + i * 4, i * 4, *(&data[i + offset]));
- i++;
- fprintf(fp, "\t format: 0x%x (%d)\n", desc->format, desc->format);
- fprintf(fp, "\t flag1: 0x%x (%d)\n", desc->flag1, desc->flag1);
- fprintf(fp, "\t swap_r_b: 0x%x (%d)\n", desc->swap_r_b, desc->swap_r_b);
- fprintf(fp, "\t unknown_0_1: 0x%x (%d)\n", desc->unknown_0_1, desc->unknown_0_1);
- fprintf(fp, "\t stride: 0x%x (%d)\n", desc->stride, desc->stride);
- fprintf(fp, "\t unknown_0_2: 0x%x (%d)\n", desc->unknown_0_2, desc->unknown_0_2);
-
- /* Word 1 - 5 */
- fprintf(fp, "/* 0x%08x (0x%08x) */\t0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
- start + i * 4, i * 4, *(&data[i + offset]), *(&data[i + 1 + offset]),
- *(&data[i + 2 + offset]), *(&data[i + 3 + offset]), *(&data[i + 4 + offset]));
- i += 5;
- fprintf(fp, "\t unknown_1_1: 0x%x (%d)\n", desc->unknown_1_1, desc->unknown_1_1);
- fprintf(fp, "\t unnorm_coords: 0x%x (%d)\n", desc->unnorm_coords, desc->unnorm_coords);
- fprintf(fp, "\t unknown_1_2: 0x%x (%d)\n", desc->unknown_1_2, desc->unknown_1_2);
- fprintf(fp, "\t cube_map: 0x%x (%d)\n", desc->cube_map, desc->cube_map);
- fprintf(fp, "\t sampler_dim: 0x%x (%d)\n", desc->sampler_dim, desc->sampler_dim);
- fprintf(fp, "\t min_lod: 0x%x (%d) (%f)\n", desc->min_lod, desc->min_lod, lima_fixed8_to_float(desc->min_lod));
- fprintf(fp, "\t max_lod: 0x%x (%d) (%f)\n", desc->max_lod, desc->max_lod, lima_fixed8_to_float(desc->max_lod));
- fprintf(fp, "\t lod_bias: 0x%x (%d) (%f)\n", desc->lod_bias, desc->lod_bias, lima_fixed8_to_float(desc->lod_bias));
- fprintf(fp, "\t unknown_2_1: 0x%x (%d)\n", desc->unknown_2_1, desc->unknown_2_1);
- fprintf(fp, "\t has_stride: 0x%x (%d)\n", desc->has_stride, desc->has_stride);
- fprintf(fp, "\t min_mipfilter_2: 0x%x (%d)\n", desc->min_mipfilter_2, desc->min_mipfilter_2);
- fprintf(fp, "\t min_img_filter_nearest: 0x%x (%d)\n", desc->min_img_filter_nearest, desc->min_img_filter_nearest);
- fprintf(fp, "\t mag_img_filter_nearest: 0x%x (%d)\n", desc->mag_img_filter_nearest, desc->mag_img_filter_nearest);
- fprintf(fp, "\t wrap_s: %d (%s)\n", desc->wrap_s,
- lima_get_wrap_mode_string(desc->wrap_s));
- fprintf(fp, "\t wrap_t: %d (%s)\n", desc->wrap_t,
- lima_get_wrap_mode_string(desc->wrap_t));
- fprintf(fp, "\t wrap_r: %d (%s)\n", desc->wrap_r,
- lima_get_wrap_mode_string(desc->wrap_r));
- fprintf(fp, "\t width: 0x%x (%d)\n", desc->width, desc->width);
- fprintf(fp, "\t height: 0x%x (%d)\n", desc->height, desc->height);
- fprintf(fp, "\t depth: 0x%x (%d)\n", desc->depth, desc->depth);
- fprintf(fp, "\t border_red: 0x%x (%d)\n", desc->border_red, desc->border_red);
- fprintf(fp, "\t border_green: 0x%x (%d)\n", desc->border_green, desc->border_green);
- fprintf(fp, "\t border_blue: 0x%x (%d)\n", desc->border_blue, desc->border_blue);
- fprintf(fp, "\t border_alpha: 0x%x (%d)\n", desc->border_alpha, desc->border_alpha);
- fprintf(fp, "\t unknown_5_1: 0x%x (%d)\n", desc->unknown_5_1, desc->unknown_5_1);
-
- /* Word 6 - */
- fprintf(fp, "/* 0x%08x (0x%08x) */",
- start + i * 4, i * 4);
- fprintf(fp, "\t");
-
- int miplevels = (int)lima_fixed8_to_float(desc->max_lod);
- for (int k = 0; k < ((((miplevels + 1) * 26) + 64) / 32); k++)
- fprintf(fp, "0x%08x ", *(&data[i + offset + k]));
- fprintf(fp, "\n");
-
- i++;
- fprintf(fp, "\t unknown_6_1: 0x%x (%d)\n", desc->va_s.unknown_6_1, desc->va_s.unknown_6_1);
- fprintf(fp, "\t layout: 0x%x (%d)\n", desc->va_s.layout, desc->va_s.layout);
- fprintf(fp, "\t unknown_6_2: 0x%x (%d)\n", desc->va_s.unknown_6_2, desc->va_s.unknown_6_2);
- fprintf(fp, "\t unknown_6_3: 0x%x (%d)\n", desc->va_s.unknown_6_3, desc->va_s.unknown_6_3);
-
- /* first level */
- fprintf(fp, "\t va_0: 0x%x \n", desc->va_s.va_0 << 6);
-
- /* second level up to desc->miplevels */
- int j;
- unsigned va_bit_idx;
- unsigned va_idx;
- uint32_t va;
- uint32_t va_1;
- uint32_t va_2;
- for (j = 1; j <= miplevels; j++) {
- va = 0;
- va_1 = 0;
- va_2 = 0;
-
- va_bit_idx = VA_BIT_OFFSET + (VA_BIT_SIZE * j);
- va_idx = va_bit_idx / 32;
- va_bit_idx %= 32;
-
- /* the first (32 - va_bit_idx) bits */
- va_1 |= (*(&data[i + offset + va_idx - 1]) >> va_bit_idx);
-
- /* do we need some bits from the following word? */
- if (va_bit_idx > 6) {
- /* shift left and right again to erase the unneeded bits, keep space for va1 */
- va_2 |= (*(&data[i + offset + va_idx]) << (2 * 32 - VA_BIT_SIZE - va_bit_idx));
- va_2 >>= ((2 * 32 - VA_BIT_SIZE - va_bit_idx) - (32 - va_bit_idx));
- va |= va_2;
- }
- va |= va_1;
- va <<= 6;
- fprintf(fp, "\t va_%d: 0x%x \n", j, va);
- }
-}
-
void
lima_parse_texture_descriptor(FILE *fp, uint32_t *data, int size, uint32_t start, uint32_t offset)
{
fprintf(fp, "/* ============ TEXTURE BEGIN ===================== */\n");
- parse_texture(fp, data, start, offset);
+ lima_unpack(fp, data + offset / sizeof(uint32_t), TEXTURE_DESCRIPTOR, temp);
+ lima_print(fp, TEXTURE_DESCRIPTOR, temp, 8);
fprintf(fp, "/* ============ TEXTURE END ======================= */\n");
}
diff --git a/src/gallium/drivers/lima/lima_texture.c b/src/gallium/drivers/lima/lima_texture.c
index 90413eb22ec..ecb33c9275c 100644
--- a/src/gallium/drivers/lima/lima_texture.c
+++ b/src/gallium/drivers/lima/lima_texture.c
@@ -32,6 +32,7 @@
#include "lima_bo.h"
#include "lima_context.h"
+#include "lima_pack.h"
#include "lima_screen.h"
#include "lima_texture.h"
#include "lima_resource.h"
@@ -44,78 +45,56 @@
#define lima_tex_list_size 64
-static_assert(offsetof(lima_tex_desc, va) == 24, "lima_tex_desc->va offset isn't 24");
-
-
-static void
-lima_texture_desc_set_va(lima_tex_desc *desc,
- int idx,
- uint32_t va)
-{
- unsigned va_bit_idx = VA_BIT_OFFSET + (VA_BIT_SIZE * idx);
- unsigned va_idx = va_bit_idx / 32;
- va_bit_idx %= 32;
-
- va >>= 6;
-
- desc->va[va_idx] |= va << va_bit_idx;
- if (va_bit_idx <= 6)
- return;
- desc->va[va_idx + 1] |= va >> (32 - va_bit_idx);
-}
-
/*
* Note: this function is used by both draw and flush code path,
* make sure no lima_job_get() is called inside this.
*/
void
-lima_texture_desc_set_res(struct lima_context *ctx, lima_tex_desc *desc,
+lima_texture_desc_set_res(struct lima_context *ctx, struct LIMA_TEXTURE_DESCRIPTOR *desc,
struct pipe_resource *prsc,
unsigned first_level, unsigned last_level,
unsigned first_layer, unsigned mrt_idx)
{
- unsigned width, height, depth, layout, i;
struct lima_resource *lima_res = lima_resource(prsc);
- width = prsc->width0;
- height = prsc->height0;
- depth = prsc->depth0;
+ desc->width = prsc->width0;
+ desc->height = prsc->height0;
+ desc->depth = prsc->depth0;
if (first_level != 0) {
- width = u_minify(width, first_level);
- height = u_minify(height, first_level);
- depth = u_minify(depth, first_level);
+ desc->width = u_minify(desc->width, first_level);
+ desc->height = u_minify(desc->height, first_level);
+ desc->depth = u_minify(desc->depth, first_level);
}
- desc->format = lima_format_get_texel(prsc->format);
- desc->swap_r_b = lima_format_get_texel_swap_rb(prsc->format);
- desc->width = width;
- desc->height = height;
- desc->depth = depth;
+ desc->texel_format = lima_format_get_texel(prsc->format);
+ desc->swap_rb = lima_format_get_texel_swap_rb(prsc->format);
if (lima_res->tiled)
- layout = 3;
+ desc->layout = LIMA_TEXTURE_LAYOUT_TILED;
else {
desc->stride = lima_res->levels[first_level].stride;
- desc->has_stride = 1;
- layout = 0;
+ desc->has_stride = true;
+ desc->layout = LIMA_TEXTURE_LAYOUT_LINEAR;
}
uint32_t base_va = lima_res->bo->va;
- /* attach first level */
- uint32_t first_va = base_va + lima_res->levels[first_level].offset +
- first_layer * lima_res->levels[first_level].layer_stride +
- mrt_idx * lima_res->mrt_pitch;
- desc->va_s.va_0 = first_va >> 6;
- desc->va_s.layout = layout;
+ uint32_t *mips[] = {&desc->mip_0, &desc->mip_1,
+ &desc->mip_2, &desc->mip_3,
+ &desc->mip_4, &desc->mip_5,
+ &desc->mip_6, &desc->mip_7,
+ &desc->mip_8, &desc->mip_9,
+ &desc->mip_10};
- /* Attach remaining levels.
- * Each subsequent mipmap address is specified using the 26 msbs.
- * These addresses are then packed continuously in memory */
- for (i = 1; i <= (last_level - first_level); i++) {
- uint32_t address = base_va + lima_res->levels[first_level + i].offset;
- lima_texture_desc_set_va(desc, i, address);
+
+ int max_mips = MIN2(last_level - first_level, sizeof(mips) / sizeof(mips[0]));
+
+ for (int i = 0; i <= max_mips; i++) {
+ *mips[i] = base_va + lima_res->levels[first_level + i].offset;
}
+
+ *mips[0] += first_layer * lima_res->levels[first_level].layer_stride +
+ mrt_idx * lima_res->mrt_pitch;
}
static unsigned
@@ -154,133 +133,118 @@ lima_update_tex_desc(struct lima_context *ctx, struct lima_sampler_state *sample
struct lima_sampler_view *texture, void *pdesc,
unsigned desc_size)
{
- /* unit is 1/16 since lod_bias is in fixed format */
- int lod_bias_delta = 0;
- lima_tex_desc *desc = pdesc;
- unsigned first_level;
- unsigned last_level;
- unsigned first_layer;
- float max_lod;
-
- memset(desc, 0, desc_size);
-
- if (!texture)
+ if (!texture) {
+ memset(pdesc, 0, desc_size);
return;
-
- switch (texture->base.target) {
- case PIPE_TEXTURE_1D:
- desc->sampler_dim = LIMA_SAMPLER_DIM_1D;
- break;
- case PIPE_TEXTURE_2D:
- case PIPE_TEXTURE_RECT:
- desc->sampler_dim = LIMA_SAMPLER_DIM_2D;
- break;
- case PIPE_TEXTURE_CUBE:
- desc->cube_map = 1;
- FALLTHROUGH;
- case PIPE_TEXTURE_3D:
- desc->sampler_dim = LIMA_SAMPLER_DIM_3D;
- break;
- default:
- break;
}
- if (sampler->base.unnormalized_coords)
- desc->unnorm_coords = 1;
+ lima_pack(pdesc, TEXTURE_DESCRIPTOR, desc)
+ {
+ float lod_bias_delta = 0.0;
+ unsigned first_level;
+ unsigned last_level;
+ unsigned first_layer;
+ float max_lod;
- first_level = texture->base.u.tex.first_level;
- last_level = texture->base.u.tex.last_level;
- first_layer = texture->base.u.tex.first_layer;
- if (last_level - first_level >= LIMA_MAX_MIP_LEVELS)
- last_level = first_level + LIMA_MAX_MIP_LEVELS - 1;
-
- desc->min_lod = lima_float_to_fixed8(sampler->base.min_lod);
- max_lod = MIN2(sampler->base.max_lod, sampler->base.min_lod +
- (last_level - first_level));
- desc->max_lod = lima_float_to_fixed8(max_lod);
- desc->lod_bias = lima_float_to_fixed8(sampler->base.lod_bias);
-
- switch (sampler->base.min_mip_filter) {
- case PIPE_TEX_MIPFILTER_LINEAR:
- desc->min_mipfilter_2 = 3;
+ switch (texture->base.target) {
+ case PIPE_TEXTURE_1D:
+ desc.sampler_dim = LIMA_SAMPLER_DIMENSION_1D;
break;
- case PIPE_TEX_MIPFILTER_NEAREST:
- desc->min_mipfilter_2 = 0;
+ case PIPE_TEXTURE_2D:
+ case PIPE_TEXTURE_RECT:
+ desc.sampler_dim = LIMA_SAMPLER_DIMENSION_2D;
break;
- case PIPE_TEX_MIPFILTER_NONE:
- desc->max_lod = desc->min_lod;
+ case PIPE_TEXTURE_CUBE:
+ desc.cube_map = true;
+ FALLTHROUGH;
+ case PIPE_TEXTURE_3D:
+ desc.sampler_dim = LIMA_SAMPLER_DIMENSION_3D;
break;
default:
break;
+ }
+
+ if (sampler->base.unnormalized_coords)
+ desc.unnorm_coords = true;
+
+ first_level = texture->base.u.tex.first_level;
+ last_level = texture->base.u.tex.last_level;
+ first_layer = texture->base.u.tex.first_layer;
+ if (last_level - first_level >= LIMA_MAX_MIP_LEVELS)
+ last_level = first_level + LIMA_MAX_MIP_LEVELS - 1;
+
+ desc.min_lod = sampler->base.min_lod;
+ max_lod = MIN2(sampler->base.max_lod, sampler->base.min_lod +
+ (last_level - first_level));
+ desc.max_lod = max_lod;
+ desc.lod_bias = sampler->base.lod_bias;
+
+ switch (sampler->base.min_mip_filter) {
+ case PIPE_TEX_MIPFILTER_LINEAR:
+ desc.mipfilter = LIMA_MIPFILTER_LINEAR;
+ break;
+ case PIPE_TEX_MIPFILTER_NEAREST:
+ desc.mipfilter = LIMA_MIPFILTER_NEAREST;
+ break;
+ case PIPE_TEX_MIPFILTER_NONE:
+ desc.max_lod = desc.min_lod;
+ break;
+ default:
+ break;
+ }
+
+ switch (sampler->base.mag_img_filter) {
+ case PIPE_TEX_FILTER_LINEAR:
+ desc.mag_img_filter_nearest = false;
+ break;
+ case PIPE_TEX_FILTER_NEAREST:
+ default:
+ desc.mag_img_filter_nearest = true;
+ break;
+ }
+
+ switch (sampler->base.min_img_filter) {
+ break;
+ case PIPE_TEX_FILTER_LINEAR:
+ desc.min_img_filter_nearest = false;
+ break;
+ case PIPE_TEX_FILTER_NEAREST:
+ default:
+ lod_bias_delta = 0.5;
+ desc.min_img_filter_nearest = true;
+ break;
+ }
+
+ /* Panfrost mentions that GL_CLAMP is broken for NEAREST filter on Midgard,
+ * looks like it also broken on Utgard, since it fails in piglit
+ */
+ bool using_nearest = sampler->base.min_img_filter == PIPE_TEX_FILTER_NEAREST;
+
+ desc.wrap_s = pipe_wrap_to_lima(sampler->base.wrap_s, using_nearest);
+ desc.wrap_t = pipe_wrap_to_lima(sampler->base.wrap_t, using_nearest);
+ desc.wrap_r = pipe_wrap_to_lima(sampler->base.wrap_r, using_nearest);
+
+ desc.border_red = sampler->base.border_color.f[0];
+ desc.border_green = sampler->base.border_color.f[1];
+ desc.border_blue = sampler->base.border_color.f[2];
+ desc.border_alpha = sampler->base.border_color.f[3];
+
+ if (desc.min_img_filter_nearest && desc.mag_img_filter_nearest &&
+ desc.mipfilter == 0 &&
+ (desc.min_lod != desc.max_lod))
+ lod_bias_delta = -1.0/16.0;
+
+ desc.lod_bias += lod_bias_delta;
+
+ lima_texture_desc_set_res(ctx, &desc, texture->base.texture,
+ first_level, last_level, first_layer, 0);
}
-
- switch (sampler->base.mag_img_filter) {
- case PIPE_TEX_FILTER_LINEAR:
- desc->mag_img_filter_nearest = 0;
- break;
- case PIPE_TEX_FILTER_NEAREST:
- default:
- desc->mag_img_filter_nearest = 1;
- break;
- }
-
- switch (sampler->base.min_img_filter) {
- break;
- case PIPE_TEX_FILTER_LINEAR:
- desc->min_img_filter_nearest = 0;
- break;
- case PIPE_TEX_FILTER_NEAREST:
- default:
- lod_bias_delta = 8;
- desc->min_img_filter_nearest = 1;
- break;
- }
-
- /* Panfrost mentions that GL_CLAMP is broken for NEAREST filter on Midgard,
- * looks like it also broken on Utgard, since it fails in piglit
- */
- bool using_nearest = sampler->base.min_img_filter == PIPE_TEX_FILTER_NEAREST;
-
- desc->wrap_s = pipe_wrap_to_lima(sampler->base.wrap_s, using_nearest);
- desc->wrap_t = pipe_wrap_to_lima(sampler->base.wrap_t, using_nearest);
- desc->wrap_r = pipe_wrap_to_lima(sampler->base.wrap_r, using_nearest);
-
- desc->border_red = float_to_ushort(sampler->base.border_color.f[0]);
- desc->border_green = float_to_ushort(sampler->base.border_color.f[1]);
- desc->border_blue = float_to_ushort(sampler->base.border_color.f[2]);
- desc->border_alpha = float_to_ushort(sampler->base.border_color.f[3]);
-
- if (desc->min_img_filter_nearest && desc->mag_img_filter_nearest &&
- desc->min_mipfilter_2 == 0 &&
- (desc->min_lod != desc->max_lod))
- lod_bias_delta = -1;
-
- desc->lod_bias += lod_bias_delta;
-
- lima_texture_desc_set_res(ctx, desc, texture->base.texture,
- first_level, last_level, first_layer, 0);
}
static unsigned
lima_calc_tex_desc_size(struct lima_sampler_view *texture)
{
- unsigned size = offsetof(lima_tex_desc, va);
- unsigned va_bit_size;
-
- if (!texture)
- return lima_min_tex_desc_size;
-
- unsigned first_level = texture->base.u.tex.first_level;
- unsigned last_level = texture->base.u.tex.last_level;
-
- if (last_level - first_level >= LIMA_MAX_MIP_LEVELS)
- last_level = first_level + LIMA_MAX_MIP_LEVELS - 1;
-
- va_bit_size = VA_BIT_OFFSET + VA_BIT_SIZE * (last_level - first_level + 1);
- size += (va_bit_size + 7) >> 3;
- size = align(size, lima_min_tex_desc_size);
-
- return size;
+ return sizeof(struct lima_texture_descriptor_packed);
}
void
diff --git a/src/gallium/drivers/lima/lima_texture.h b/src/gallium/drivers/lima/lima_texture.h
index 18cc9c7050a..e6a0fb2f117 100644
--- a/src/gallium/drivers/lima/lima_texture.h
+++ b/src/gallium/drivers/lima/lima_texture.h
@@ -22,104 +22,15 @@
*
*/
+#include "genxml/lima_pack.h"
+
#ifndef H_LIMA_TEXTURE
#define H_LIMA_TEXTURE
-#define lima_min_tex_desc_size 64
-
-#define LIMA_SAMPLER_DIM_1D 0
-#define LIMA_SAMPLER_DIM_2D 1
-#define LIMA_SAMPLER_DIM_3D 2
-
-#define LIMA_TEX_WRAP_REPEAT 0
-#define LIMA_TEX_WRAP_CLAMP_TO_EDGE 1
-#define LIMA_TEX_WRAP_CLAMP 2
-#define LIMA_TEX_WRAP_CLAMP_TO_BORDER 3
-#define LIMA_TEX_WRAP_MIRROR_REPEAT 4
-#define LIMA_TEX_WRAP_MIRROR_CLAMP_TO_EDGE 5
-#define LIMA_TEX_WRAP_MIRROR_CLAMP 6
-#define LIMA_TEX_WRAP_MIRROR_CLAMP_TO_BORDER 7
-
-typedef struct __attribute__((__packed__)) {
- /* Word 0 */
- uint32_t format : 6;
- uint32_t flag1: 1;
- uint32_t swap_r_b: 1;
- uint32_t unknown_0_1: 8;
- uint32_t stride: 15;
- uint32_t unknown_0_2: 1;
-
- /* Word 1-3 */
- uint32_t unknown_1_1: 7;
- uint32_t unnorm_coords: 1;
- uint32_t unknown_1_2: 1;
- uint32_t cube_map: 1;
- uint32_t sampler_dim: 2;
- uint32_t min_lod: 8; /* Fixed point, 4.4, unsigned */
- uint32_t max_lod: 8; /* Fixed point, 4.4, unsigned */
- uint32_t lod_bias: 9; /* Fixed point, signed, 1.4.4 */
- uint32_t unknown_2_1: 3;
- uint32_t has_stride: 1;
- uint32_t min_mipfilter_2: 2; /* 0x3 for linear, 0x0 for nearest */
- uint32_t min_img_filter_nearest: 1;
- uint32_t mag_img_filter_nearest: 1;
- uint32_t wrap_s: 3;
- uint32_t wrap_t: 3;
- uint32_t wrap_r: 3;
- uint32_t width: 13;
- uint32_t height: 13;
- uint32_t depth: 13;
-
- uint32_t border_red: 16;
- uint32_t border_green: 16;
- uint32_t border_blue: 16;
- uint32_t border_alpha: 16;
-
- /* Word 5 (last 3 bits) */
- uint32_t unknown_5_1: 3;
-
- /* Word 6-15 */
- /* layout is in va[0] bit 13-14 */
- /* VAs start in va[0] at bit 30, each VA is 26 bits (only MSBs are stored), stored
- * linearly in memory */
- union {
- uint32_t va[0];
- struct __attribute__((__packed__)) {
- uint32_t unknown_6_1: 13;
- uint32_t layout: 2;
- uint32_t unknown_6_2: 9;
- uint32_t unknown_6_3: 6;
-#define VA_BIT_OFFSET 30
-#define VA_BIT_SIZE 26
- uint32_t va_0: VA_BIT_SIZE;
- uint32_t va_0_1: 8;
- uint32_t va_1_x[0];
- } va_s;
- };
-} lima_tex_desc;
-
-void lima_texture_desc_set_res(struct lima_context *ctx, lima_tex_desc *desc,
+void lima_texture_desc_set_res(struct lima_context *ctx, struct LIMA_TEXTURE_DESCRIPTOR *desc,
struct pipe_resource *prsc,
unsigned first_level, unsigned last_level,
unsigned first_layer, unsigned mrt_idx);
void lima_update_textures(struct lima_context *ctx);
-
-static inline int16_t lima_float_to_fixed8(float f)
-{
- return (int)(f * 16.0);
-}
-
-static inline float lima_fixed8_to_float(int16_t i)
-{
- float sign = 1.0;
-
- if (i > 0xff) {
- i = 0x200 - i;
- sign = -1;
- }
-
- return sign * (float)(i / 16.0);
-}
-
#endif
diff --git a/src/gallium/drivers/lima/meson.build b/src/gallium/drivers/lima/meson.build
index 60c52530732..f6149b0b1b1 100644
--- a/src/gallium/drivers/lima/meson.build
+++ b/src/gallium/drivers/lima/meson.build
@@ -82,6 +82,8 @@ lima_nir_algebraic_c = custom_target(
depend_files : nir_algebraic_depends,
)
+subdir('genxml')
+
liblima = static_library(
'lima',
files_lima, lima_nir_algebraic_c,
@@ -89,7 +91,7 @@ liblima = static_library(
inc_src, inc_include, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
inc_panfrost
],
- dependencies : [dep_libdrm, idep_nir_headers, idep_mesautil],
+ dependencies : [dep_libdrm, idep_nir_headers, idep_mesautil, idep_lima_pack],
)
driver_lima = declare_dependency(