diff --git a/src/util/drirc_gen.py b/src/util/drirc_gen.py new file mode 100644 index 00000000000..1f891fc1fdf --- /dev/null +++ b/src/util/drirc_gen.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +# Copyright (C) 2026 Valve Corporation +# SPDX-License-Identifier: MIT + +import argparse +import os +import re +import sys + +from enum import Enum +from mako.template import Template + +class DrircOptionType(Enum): + BOOL = 0, + INT = 1, + UINT64 = 2, + FLOAT = 3, + STRING = 4, + STRING_NODEF = 5, + ENUM = 6, + +type_to_ctype: dict[DrircOptionType, str] = { + DrircOptionType.BOOL: "bool", + DrircOptionType.INT: "int", + DrircOptionType.UINT64: "uint64_t", + DrircOptionType.FLOAT: "float", + DrircOptionType.STRING: "char *", + DrircOptionType.STRING_NODEF: "char *", + DrircOptionType.ENUM: "int", +} + +type_to_macro: dict[DrircOptionType, str] = { + DrircOptionType.BOOL: "DRI_CONF_OPT_B", + DrircOptionType.INT: "DRI_CONF_OPT_I", + DrircOptionType.UINT64: "DRI_CONF_OPT_U64", + DrircOptionType.FLOAT: "DRI_CONF_OPT_F", + DrircOptionType.STRING: "DRI_CONF_OPT_S", + DrircOptionType.STRING_NODEF: "DRI_CONF_OPT_S_NODEF", + DrircOptionType.ENUM: "DRI_CONF_OPT_E", +} + +type_to_queryfn: dict[DrircOptionType, str] = { + DrircOptionType.BOOL: "driQueryOptionb", + DrircOptionType.INT: "driQueryOptioni", + DrircOptionType.UINT64: "driQueryOptionu64", + DrircOptionType.FLOAT: "driQueryOptionf", + DrircOptionType.STRING: "driQueryOptionstr", + DrircOptionType.STRING_NODEF: "driQueryOptionstr", + DrircOptionType.ENUM: "driQueryOptioni", +} + +class DrircOption(object): + def __init__(self, dtype, name, description, c_name): + self.dtype = dtype + self.name = name + self.description = description + self.c_name = c_name if c_name is not None else name.lower() + self.c_args = [] + +class DrircBool(DrircOption): + def __init__(self, name, value, description="", c_name=None): + super().__init__(DrircOptionType.BOOL, name, description, c_name) + self.value = value + self.c_args = ["true" if value else "false", f"\"{self.description}\""] + +class DrircInt(DrircOption): + def __init__(self, name, value, min_value, max_value, description="", c_name=None): + super().__init__(DrircOptionType.INT, name, description, c_name) + self.value = value + self.min_value = min_value + self.max_value = max_value + self.c_args = [f"{value}", f"{min_value}", f"{max_value}", f"\"{self.description}\""] + +class DrircUint64(DrircOption): + def __init__(self, name, value, min_value, max_value, description="", c_name=None): + super().__init__(DrircOptionType.UINT64, name, description, c_name) + self.value = value + self.min_value = min_value + self.max_value = max_value + self.c_args = [f"{value}", f"{min_value}", f"{max_value}", f"\"{self.description}\""] + +class DrircFloat(DrircOption): + def __init__(self, name, value, min_value, max_value, description="", c_name=None): + super().__init__(DrircOptionType.FLOAT, name, description, c_name) + self.value = value + self.min_value = min_value + self.max_value = max_value + self.c_args = [f"{value}", f"{min_value}", f"{max_value}", f"\"{self.description}\""] + +class DrircString(DrircOption): + def __init__(self, name, value=None, description="", c_name=None): + super().__init__(DrircOptionType.STRING if value is not None else DrircOptionType.STRING_NODEF, + "char *", name, description, c_name) + self.value = value + self.c_args = [f"{value}", f"\"{self.description}\""] + +class DrircEnumValue(object): + def __init__(self, value, description=""): + self.value = value + self.description = description + +class DrircEnum(DrircOption): + def __init__(self, name, value, min_value, max_value, values, description="", c_name=None): + super().__init__(DrircOptionType.ENUM, name, description, c_name) + self.values = values + self.value = value + self.min_value = min_value + self.max_value = max_value + self.c_args = [f"{value}", f"{min_value}", f"{min_value}", f"\"{self.description}\""] + vals = [] + for v in values: + vals.append(f"DRI_CONF_ENUM({v.value}, \"{v.description}\")") + self.c_args.append(''.join(vals)) + +class DrircSection(object): + """Class that represents a DRIRC section + """ + def __init__(self, name, options=[], c_name=None): + """Parameters: + + - options: list of DrircOption + """ + self.name = name + self.options = options + self.c_name = c_name if c_name is not None else name.lower() + + +TEMPLATE_H = """\ +/* This file is autogenerated. Do not edit. */ + +#ifndef ${driver_prefix.upper()}_DRIRC_H +#define ${driver_prefix.upper()}_DRIRC_H + +#include "util/driconf.h" + +struct ${driver_prefix}_drirc { + struct driOptionCache options; + struct driOptionCache available_options; + +% for section in sections: + struct { +% for option in section.options: + ${type_to_ctype(option.dtype)} ${option.c_name}; +% endfor + } ${section.c_name}; +% endfor +}; + +void ${driver_prefix}_parse_dri_options(struct ${driver_prefix}_drirc *drirc, + const driConfigFileParseParams *params); + +#endif /* ${driver_prefix.upper()}_DRIRC_H */ +""" + +TEMPLATE_C = """\ +/* This file is autogenerated. Do not edit. */ + +#include "${include_file}" + +static const driOptionDescription dri_options[] = { +% for section in sections: +DRI_CONF_SECTION("${section.name}") +% for option in section.options: + ${type_to_macro(option.dtype)}(${option.name} +% for arg in option.c_args: + , ${arg} +% endfor + ) +% endfor +DRI_CONF_SECTION_END +% endfor +}; + +void +${driver_prefix}_parse_dri_options(struct ${driver_prefix}_drirc *drirc, + const driConfigFileParseParams *params) +{ + driParseOptionInfo(&drirc->available_options, dri_options, ARRAY_SIZE(dri_options)); + driParseConfigFiles(&drirc->options, &drirc->available_options, params); + +% for section in sections: +% for option in section.options: + drirc->${section.c_name}.${option.c_name} = ${type_to_queryfn(option.dtype)}(&drirc->options, "${option.name}"); +% endfor +% endfor +} +""" + +def drirc_generate(cpath, hpath, driver_prefix, sections): + environment = { + 'driver_prefix': driver_prefix, + 'sections': sections, + 'type_to_ctype': lambda dtype: type_to_ctype[dtype], + 'type_to_macro': lambda dtype: type_to_macro[dtype], + 'type_to_queryfn': lambda dtype: type_to_queryfn[dtype], + 'include_file': os.path.basename(hpath), + } + + with open(cpath, 'w', encoding='utf-8') as f: + try: + result = f.write(Template(TEMPLATE_C).render(**environment)) + except Exception: + from mako import exceptions + print(exceptions.text_error_template().render(), file=sys.stderr) + sys.exit(1) + with open(hpath, 'w', encoding='utf-8') as f: + try: + result = f.write(Template(TEMPLATE_H).render(**environment)) + except Exception: + from mako import exceptions + print(exceptions.text_error_template().render(), file=sys.stderr) + sys.exit(1) diff --git a/src/util/meson.build b/src/util/meson.build index 30cf227b13d..b69ed73a2b4 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -217,6 +217,8 @@ if with_amd_vk files_drirc += files('00-radv-defaults.conf') endif +drirc_gen = files('drirc_gen.py') + if with_tests prog_xmllint = find_program('xmllint', required : false, native : true) if prog_xmllint.found()