xref: /aosp_15_r20/external/mesa3d/src/vulkan/registry/update-aliases.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*61046927SAndroid Build Coastguard Worker"""
3*61046927SAndroid Build Coastguard WorkerCheck for and replace aliases with their new names from vk.xml
4*61046927SAndroid Build Coastguard Worker"""
5*61046927SAndroid Build Coastguard Worker
6*61046927SAndroid Build Coastguard Workerimport argparse
7*61046927SAndroid Build Coastguard Workerimport pathlib
8*61046927SAndroid Build Coastguard Workerimport subprocess
9*61046927SAndroid Build Coastguard Workerimport sys
10*61046927SAndroid Build Coastguard Workerimport xml.etree.ElementTree as et
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard WorkerTHIS_FILE = pathlib.Path(__file__)
13*61046927SAndroid Build Coastguard WorkerCWD = pathlib.Path.cwd()
14*61046927SAndroid Build Coastguard Worker
15*61046927SAndroid Build Coastguard WorkerVK_XML = THIS_FILE.parent / 'vk.xml'
16*61046927SAndroid Build Coastguard WorkerEXCLUDE_PATHS = [
17*61046927SAndroid Build Coastguard Worker    VK_XML.relative_to(CWD).as_posix(),
18*61046927SAndroid Build Coastguard Worker
19*61046927SAndroid Build Coastguard Worker    # These files come from other repos, there's no point checking and
20*61046927SAndroid Build Coastguard Worker    # fixing them here as that would be overwritten in the next sync.
21*61046927SAndroid Build Coastguard Worker    'src/amd/vulkan/radix_sort/',
22*61046927SAndroid Build Coastguard Worker    'src/virtio/venus-protocol/',
23*61046927SAndroid Build Coastguard Worker]
24*61046927SAndroid Build Coastguard Worker
25*61046927SAndroid Build Coastguard Worker
26*61046927SAndroid Build Coastguard Workerdef get_aliases(xml_file: pathlib.Path):
27*61046927SAndroid Build Coastguard Worker    """
28*61046927SAndroid Build Coastguard Worker    Get all the aliases defined in vk.xml
29*61046927SAndroid Build Coastguard Worker    """
30*61046927SAndroid Build Coastguard Worker    xml = et.parse(xml_file)
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Worker    for node in ([]
33*61046927SAndroid Build Coastguard Worker        + xml.findall('.//enum[@alias]')
34*61046927SAndroid Build Coastguard Worker        + xml.findall('.//type[@alias]')
35*61046927SAndroid Build Coastguard Worker        + xml.findall('.//command[@alias]')
36*61046927SAndroid Build Coastguard Worker    ):
37*61046927SAndroid Build Coastguard Worker        # Some renames only apply to some APIs
38*61046927SAndroid Build Coastguard Worker        if 'api' in node.attrib and 'vulkan' not in node.attrib['api'].split(','):
39*61046927SAndroid Build Coastguard Worker            continue
40*61046927SAndroid Build Coastguard Worker
41*61046927SAndroid Build Coastguard Worker        yield node.attrib['name'], node.attrib['alias']
42*61046927SAndroid Build Coastguard Worker
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Workerdef remove_prefix(string: str, prefix: str):
45*61046927SAndroid Build Coastguard Worker    """
46*61046927SAndroid Build Coastguard Worker    Remove prefix if string starts with it, and return the full string
47*61046927SAndroid Build Coastguard Worker    otherwise.
48*61046927SAndroid Build Coastguard Worker    """
49*61046927SAndroid Build Coastguard Worker    if not string.startswith(prefix):
50*61046927SAndroid Build Coastguard Worker        return string
51*61046927SAndroid Build Coastguard Worker    return string[len(prefix):]
52*61046927SAndroid Build Coastguard Worker
53*61046927SAndroid Build Coastguard Worker
54*61046927SAndroid Build Coastguard Worker# Function from https://stackoverflow.com/a/312464
55*61046927SAndroid Build Coastguard Workerdef chunks(lst: list, n: int):
56*61046927SAndroid Build Coastguard Worker    """
57*61046927SAndroid Build Coastguard Worker    Yield successive n-sized chunks from lst.
58*61046927SAndroid Build Coastguard Worker    """
59*61046927SAndroid Build Coastguard Worker    for i in range(0, len(lst), n):
60*61046927SAndroid Build Coastguard Worker        yield lst[i:i + n]
61*61046927SAndroid Build Coastguard Worker
62*61046927SAndroid Build Coastguard Worker
63*61046927SAndroid Build Coastguard Workerdef main(paths: list[str]):
64*61046927SAndroid Build Coastguard Worker    """
65*61046927SAndroid Build Coastguard Worker    Entrypoint; perform the search for all the aliases and replace them.
66*61046927SAndroid Build Coastguard Worker    """
67*61046927SAndroid Build Coastguard Worker    def prepare_identifier(identifier: str) -> str:
68*61046927SAndroid Build Coastguard Worker        prefixes_seen = []
69*61046927SAndroid Build Coastguard Worker        for prefix in [
70*61046927SAndroid Build Coastguard Worker            # Various macros prepend these, so they will not appear in the code using them.
71*61046927SAndroid Build Coastguard Worker            # List generated using this command:
72*61046927SAndroid Build Coastguard Worker            #   $ prefixes=$(git grep -woiE 'VK_\w+_' -- src/ ':!src/vulkan/registry/' | cut -d: -f2 | sort -u)
73*61046927SAndroid Build Coastguard Worker            #   $ for prefix in $prefixes; do grep -q $prefix src/vulkan/registry/vk.xml && echo "'$prefix',"; done
74*61046927SAndroid Build Coastguard Worker            # (the second part eliminates prefixes used only in mesa code and not upstream)
75*61046927SAndroid Build Coastguard Worker            'VK_BLEND_FACTOR_',
76*61046927SAndroid Build Coastguard Worker            'VK_BLEND_OP_',
77*61046927SAndroid Build Coastguard Worker            'VK_BORDER_COLOR_',
78*61046927SAndroid Build Coastguard Worker            'VK_COMMAND_BUFFER_RESET_',
79*61046927SAndroid Build Coastguard Worker            'VK_COMMAND_POOL_RESET_',
80*61046927SAndroid Build Coastguard Worker            'VK_COMPARE_OP_',
81*61046927SAndroid Build Coastguard Worker            'VK_COMPONENT_SWIZZLE_',
82*61046927SAndroid Build Coastguard Worker            'VK_DESCRIPTOR_TYPE_',
83*61046927SAndroid Build Coastguard Worker            'VK_DRIVER_ID_',
84*61046927SAndroid Build Coastguard Worker            'VK_DYNAMIC_STATE_',
85*61046927SAndroid Build Coastguard Worker            'VK_FORMAT_',
86*61046927SAndroid Build Coastguard Worker            'VK_IMAGE_ASPECT_MEMORY_PLANE_',
87*61046927SAndroid Build Coastguard Worker            'VK_IMAGE_ASPECT_PLANE_',
88*61046927SAndroid Build Coastguard Worker            'VK_IMAGE_USAGE_',
89*61046927SAndroid Build Coastguard Worker            'VK_NV_',
90*61046927SAndroid Build Coastguard Worker            'VK_PERFORMANCE_COUNTER_UNIT_',
91*61046927SAndroid Build Coastguard Worker            'VK_PIPELINE_BIND_POINT_',
92*61046927SAndroid Build Coastguard Worker            'VK_SAMPLER_ADDRESS_MODE_',
93*61046927SAndroid Build Coastguard Worker            'VK_SHADER_STAGE_TESSELLATION_',
94*61046927SAndroid Build Coastguard Worker            'VK_SHADER_STAGE_',
95*61046927SAndroid Build Coastguard Worker            'VK_STENCIL_OP_',
96*61046927SAndroid Build Coastguard Worker            'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_',
97*61046927SAndroid Build Coastguard Worker            'VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_',
98*61046927SAndroid Build Coastguard Worker            'VK_STRUCTURE_TYPE_',
99*61046927SAndroid Build Coastguard Worker            'VK_USE_PLATFORM_',
100*61046927SAndroid Build Coastguard Worker            'VK_VERSION_',
101*61046927SAndroid Build Coastguard Worker
102*61046927SAndroid Build Coastguard Worker            # Many places use the identifier without the `vk` prefix
103*61046927SAndroid Build Coastguard Worker            # (eg. with the driver name as a prefix instead)
104*61046927SAndroid Build Coastguard Worker            'VK_',
105*61046927SAndroid Build Coastguard Worker            'Vk',
106*61046927SAndroid Build Coastguard Worker            'vk',
107*61046927SAndroid Build Coastguard Worker        ]:
108*61046927SAndroid Build Coastguard Worker            # The order matters!  A shorter substring will match before a longer
109*61046927SAndroid Build Coastguard Worker            # one, hiding its matches.
110*61046927SAndroid Build Coastguard Worker            for prefix_seen in prefixes_seen:
111*61046927SAndroid Build Coastguard Worker                assert not prefix.startswith(prefix_seen), f'{prefix_seen} must come before {prefix}'
112*61046927SAndroid Build Coastguard Worker            prefixes_seen.append(prefix)
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker            identifier = remove_prefix(identifier, prefix)
115*61046927SAndroid Build Coastguard Worker
116*61046927SAndroid Build Coastguard Worker        return identifier
117*61046927SAndroid Build Coastguard Worker
118*61046927SAndroid Build Coastguard Worker    aliases = {}
119*61046927SAndroid Build Coastguard Worker    for old_name, alias_for in get_aliases(VK_XML):
120*61046927SAndroid Build Coastguard Worker        old_name = prepare_identifier(old_name)
121*61046927SAndroid Build Coastguard Worker        alias_for = prepare_identifier(alias_for)
122*61046927SAndroid Build Coastguard Worker        aliases[old_name] = alias_for
123*61046927SAndroid Build Coastguard Worker
124*61046927SAndroid Build Coastguard Worker    print(f'Found {len(aliases)} aliases in {VK_XML.name}')
125*61046927SAndroid Build Coastguard Worker
126*61046927SAndroid Build Coastguard Worker    # Some aliases have aliases
127*61046927SAndroid Build Coastguard Worker    recursion_needs_checking = True
128*61046927SAndroid Build Coastguard Worker    while recursion_needs_checking:
129*61046927SAndroid Build Coastguard Worker        recursion_needs_checking = False
130*61046927SAndroid Build Coastguard Worker        for old, new in aliases.items():
131*61046927SAndroid Build Coastguard Worker            if new in aliases:
132*61046927SAndroid Build Coastguard Worker                aliases[old] = aliases[new]
133*61046927SAndroid Build Coastguard Worker                recursion_needs_checking = True
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker    # Doing the whole search in a single command breaks grep, so only
136*61046927SAndroid Build Coastguard Worker    # look for 500 aliases at a time. Searching them one at a time would
137*61046927SAndroid Build Coastguard Worker    # be extremely slow.
138*61046927SAndroid Build Coastguard Worker    files_with_aliases = set()
139*61046927SAndroid Build Coastguard Worker    for aliases_chunk in chunks([*aliases], 500):
140*61046927SAndroid Build Coastguard Worker        grep_cmd = [
141*61046927SAndroid Build Coastguard Worker            'git',
142*61046927SAndroid Build Coastguard Worker            'grep',
143*61046927SAndroid Build Coastguard Worker            '-rlP',
144*61046927SAndroid Build Coastguard Worker            '|'.join(aliases_chunk),
145*61046927SAndroid Build Coastguard Worker        ] + paths
146*61046927SAndroid Build Coastguard Worker        search_output = subprocess.run(
147*61046927SAndroid Build Coastguard Worker            grep_cmd,
148*61046927SAndroid Build Coastguard Worker            check=False,
149*61046927SAndroid Build Coastguard Worker            stdout=subprocess.PIPE,
150*61046927SAndroid Build Coastguard Worker            stderr=subprocess.DEVNULL,
151*61046927SAndroid Build Coastguard Worker        ).stdout.decode()
152*61046927SAndroid Build Coastguard Worker        files_with_aliases.update(search_output.splitlines())
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker    def file_matches_path(file: str, path: str) -> bool:
156*61046927SAndroid Build Coastguard Worker        # if path is a folder; match any file within
157*61046927SAndroid Build Coastguard Worker        if path.endswith('/') and file.startswith(path):
158*61046927SAndroid Build Coastguard Worker            return True
159*61046927SAndroid Build Coastguard Worker        return file == path
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker    for excluded_path in EXCLUDE_PATHS:
162*61046927SAndroid Build Coastguard Worker        files_with_aliases = {
163*61046927SAndroid Build Coastguard Worker            file for file in files_with_aliases
164*61046927SAndroid Build Coastguard Worker            if not file_matches_path(file, excluded_path)
165*61046927SAndroid Build Coastguard Worker        }
166*61046927SAndroid Build Coastguard Worker
167*61046927SAndroid Build Coastguard Worker    if not files_with_aliases:
168*61046927SAndroid Build Coastguard Worker        print('No alias found in any file.')
169*61046927SAndroid Build Coastguard Worker        sys.exit(0)
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker    print(f'{len(files_with_aliases)} files contain aliases:')
172*61046927SAndroid Build Coastguard Worker    print('\n'.join(f'- {file}' for file in sorted(files_with_aliases)))
173*61046927SAndroid Build Coastguard Worker
174*61046927SAndroid Build Coastguard Worker    command = [
175*61046927SAndroid Build Coastguard Worker        'sed',
176*61046927SAndroid Build Coastguard Worker        '-i',
177*61046927SAndroid Build Coastguard Worker        ";".join([f's/{old}/{new}/g' for old, new in aliases.items()]),
178*61046927SAndroid Build Coastguard Worker    ]
179*61046927SAndroid Build Coastguard Worker    command += files_with_aliases
180*61046927SAndroid Build Coastguard Worker    subprocess.check_call(command, stderr=subprocess.DEVNULL)
181*61046927SAndroid Build Coastguard Worker    print('All aliases have been replaced')
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker
184*61046927SAndroid Build Coastguard Workerif __name__ == '__main__':
185*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
186*61046927SAndroid Build Coastguard Worker    parser.add_argument('paths',
187*61046927SAndroid Build Coastguard Worker                        nargs=argparse.ZERO_OR_MORE,
188*61046927SAndroid Build Coastguard Worker                        default=['src/'],
189*61046927SAndroid Build Coastguard Worker                        help='Limit script to these paths (default: `src/`)')
190*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
191*61046927SAndroid Build Coastguard Worker    main(**vars(args))
192