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(