nouveau/headers: Add Rust bindings for texture headers

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27397>
This commit is contained in:
Faith Ekstrand 2024-04-05 16:55:17 -05:00 committed by Marge Bot
parent 56aefac615
commit 640d14969e
2 changed files with 159 additions and 0 deletions

View File

@ -77,6 +77,16 @@ if with_nouveau_vk
'--out-rs', '@OUTPUT0@'],
depend_files: nvk_cl_header_depend_files,
)
if cl.endswith('97')
cl_rs_generated += custom_target(
'nvh_' + cl + 'tex.rs',
input : ['struct_parser.py', 'nvidia/classes/'+cl+'tex.h'],
output : ['nvh_'+cl+'_tex.rs'],
command : [prog_python, '@INPUT0@', '--in-h', '@INPUT1@',
'--out-rs', '@OUTPUT0@']
)
endif
endforeach
_nvidia_headers_lib_rs = custom_target(

View File

@ -0,0 +1,149 @@
#! /usr/bin/env python3
#
# Copyright © 2024 Collabora Ltd. and Red Hat Inc.
# SPDX-License-Identifier: MIT
import argparse
import os.path
import re
import sys
from collections import namedtuple
from mako.template import Template
TEMPLATE_RS = Template("""\
// Copyright © 2024 Collabora Ltd. and Red Hat Inc.
// SPDX-License-Identifier: MIT
// This file is generated by struct_parser.py. DO NOT EDIT!
use std::ops::Range;
% for s in structs:
% for f in s.fields:
pub const ${s.name}_${f.name}: Range<usize> = ${f.lo}..${f.hi + 1};
% for e in f.enums:
pub const ${s.name}_${f.name}_${e.name}: u32 = ${e.value};
% endfor
% endfor
% endfor
""")
STRUCTS = [
'TEXHEADV2',
'TEXHEADV3',
'TEXHEAD_BL',
'TEXHEAD_1D',
'TEXHEAD_PITCH',
# This one goes last because it's a substring of the others
'TEXHEAD',
'TEXSAMP',
]
Enum = namedtuple('Enum', ['name', 'value'])
class Field(object):
def __init__(self, name, lo, hi):
self.name = name
self.lo = lo
self.hi = hi
self.enums = []
def add_enum(self, name, value):
self.enums.append(Enum(name, value))
class Struct(object):
def __init__(self, name):
self.name = name
self.fields = []
def add_field(self, name, lo, hi):
self.fields.append(Field(name, lo, hi))
DRF_RE = re.compile(r'(?P<hi>[0-9]+):(?P<lo>[0-9]+)')
FIELD_NAME_RE = re.compile(r'_?(?P<dw>[0-9]+)?_?(?P<name>.*)')
MW_RE = re.compile(r'MW\((?P<hi>[0-9]+):(?P<lo>[0-9]+)\)')
def parse_header(nvcl, file):
structs = {}
for line in file:
line = line.strip().split()
if not line:
continue
if line[0] != '#define':
continue
if not line[1].startswith(nvcl):
continue
name = line[1][(len(nvcl)+1):]
struct = None
for s in STRUCTS:
if name.startswith(s):
if s not in structs:
structs[s] = Struct(s)
struct = structs[s]
name = name[len(s):]
break
if struct is None:
continue
name_m = FIELD_NAME_RE.match(name)
name = name_m.group('name')
drf = DRF_RE.match(line[2])
mw = MW_RE.match(line[2])
if drf:
dw = int(name_m.group('dw'))
lo = int(drf.group('lo')) + dw * 32
hi = int(drf.group('hi')) + dw * 32
struct.add_field(name, lo, hi)
elif mw:
lo = int(mw.group('lo'))
hi = int(mw.group('hi'))
struct.add_field(name, lo, hi)
else:
for f in struct.fields:
if name.startswith(f.name + '_'):
name = name[(len(f.name)+1):]
f.add_enum(name, line[2])
return list(structs.values())
NVCL_RE = re.compile(r'cl(?P<clsver>[0-9a-f]{4}).*')
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--out-rs', required=True, help='Output Rust file.')
parser.add_argument('--in-h',
help='Input class header file.',
required=True)
args = parser.parse_args()
clheader = os.path.basename(args.in_h)
nvcl = NVCL_RE.match(clheader).group('clsver')
nvcl = nvcl.upper()
nvcl = "NV" + nvcl
with open(args.in_h, 'r', encoding='utf-8') as f:
structs = parse_header(nvcl, f)
try:
with open(args.out_rs, 'w', encoding='utf-8') as f:
f.write(TEMPLATE_RS.render(structs=structs))
except Exception:
# In the event there's an error, this imports some helpers from mako
# to print a useful stack trace and prints it, then exits with
# status 1, if python is run with debug; otherwise it just raises
# the exception
import sys
from mako import exceptions
print(exceptions.text_error_template().render(), file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()