mesa/src/util/drirc_gen.py
Lionel Landwerlin 61267c69db util/drirc_gen: enable validation for a specific driver
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@intel.com>
Reviewed-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41664>
2026-05-22 06:32:39 +00:00

245 lines
8.3 KiB
Python

#!/usr/bin/env python3
# Copyright (C) 2026 Valve Corporation
# SPDX-License-Identifier: MIT
import argparse
import os
import re
import sys
import xml.etree.ElementTree as ET
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
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):
dtype = DrircOptionType.STRING if value is not None else DrircOptionType.STRING_NODEF
super().__init__(dtype, name, description, c_name)
self.value = value
if value is not None:
self.c_args = [f'"{value}"', f'"{self.description}"']
else:
self.c_args = [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:
% if option.c_name is not None:
${type_to_ctype(option.dtype)} ${option.c_name};
% endif
% 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:
% if option.c_name is not None:
drirc->${section.c_name}.${option.c_name} = ${type_to_queryfn(option.dtype)}(&drirc->options, "${option.name}");
% endif
% endfor
% endfor
}
"""
def drirc_validate(conf_paths, sections, driver=None):
declared = {opt.name for section in sections for opt in section.options}
conf_names = set()
for conf_path in conf_paths:
tree = ET.parse(conf_path)
if driver is None:
for option in tree.iter('option'):
name = option.get('name')
if name:
conf_names.add(name)
else:
for device in tree.iter('device'):
if device.get('driver') != driver:
continue
for option in device.iter('option'):
name = option.get('name')
if name:
conf_names.add(name)
missing = conf_names - declared
if missing:
print('ERROR: options used in conf but not declared:', file=sys.stderr)
for name in sorted(missing):
print(f' {name}', file=sys.stderr)
sys.exit(1)
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)