xref: /aosp_15_r20/external/mesa3d/src/gfxstream/codegen/scripts/genvk.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#!/usr/bin/python3
2*61046927SAndroid Build Coastguard Worker#
3*61046927SAndroid Build Coastguard Worker# Copyright 2013-2023 The Khronos Group Inc.
4*61046927SAndroid Build Coastguard Worker# Copyright 2023-2024 Google Inc.
5*61046927SAndroid Build Coastguard Worker#
6*61046927SAndroid Build Coastguard Worker# SPDX-License-Identifier: Apache-2.0
7*61046927SAndroid Build Coastguard Worker
8*61046927SAndroid Build Coastguard Workerimport argparse
9*61046927SAndroid Build Coastguard Workerimport os
10*61046927SAndroid Build Coastguard Workerimport re
11*61046927SAndroid Build Coastguard Workerimport sys
12*61046927SAndroid Build Coastguard Workerimport xml.etree.ElementTree as etree
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Workersys.path.append(os.path.abspath(os.path.dirname(__file__)))
15*61046927SAndroid Build Coastguard Worker
16*61046927SAndroid Build Coastguard Workerfrom cgenerator import CGeneratorOptions, COutputGenerator
17*61046927SAndroid Build Coastguard Worker
18*61046927SAndroid Build Coastguard Workerfrom generator import write
19*61046927SAndroid Build Coastguard Workerfrom reg import Registry
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker# gfxstream + cereal modules
22*61046927SAndroid Build Coastguard Workerfrom cerealgenerator import CerealGenerator
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Workerfrom typing import Optional
25*61046927SAndroid Build Coastguard Worker
26*61046927SAndroid Build Coastguard Workerdef makeREstring(strings, default=None, strings_are_regex=False):
27*61046927SAndroid Build Coastguard Worker    """Turn a list of strings into a regexp string matching exactly those strings."""
28*61046927SAndroid Build Coastguard Worker    if strings or default is None:
29*61046927SAndroid Build Coastguard Worker        if not strings_are_regex:
30*61046927SAndroid Build Coastguard Worker            strings = (re.escape(s) for s in strings)
31*61046927SAndroid Build Coastguard Worker        return '^(' + '|'.join(strings) + ')$'
32*61046927SAndroid Build Coastguard Worker    return default
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker
35*61046927SAndroid Build Coastguard Workerdef makeGenOpts(args):
36*61046927SAndroid Build Coastguard Worker    """Returns a directory of [ generator function, generator options ] indexed
37*61046927SAndroid Build Coastguard Worker    by specified short names. The generator options incorporate the following
38*61046927SAndroid Build Coastguard Worker    parameters:
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker    args is an parsed argument object; see below for the fields that are used."""
41*61046927SAndroid Build Coastguard Worker    global genOpts
42*61046927SAndroid Build Coastguard Worker    genOpts = {}
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker    # Output target directory
45*61046927SAndroid Build Coastguard Worker    directory = args.directory
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker    # Descriptive names for various regexp patterns used to select
48*61046927SAndroid Build Coastguard Worker    # versions and extensions
49*61046927SAndroid Build Coastguard Worker    allFormats = allFeatures = allExtensions = r'.*'
50*61046927SAndroid Build Coastguard Worker
51*61046927SAndroid Build Coastguard Worker    # Turn lists of names/patterns into matching regular expressions
52*61046927SAndroid Build Coastguard Worker    emitExtensionsPat    = makeREstring([], allExtensions)
53*61046927SAndroid Build Coastguard Worker    emitFormatsPat       = makeREstring([], allFormats)
54*61046927SAndroid Build Coastguard Worker    featuresPat          = makeREstring([], allFeatures)
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker    # Copyright text prefixing all headers (list of strings).
57*61046927SAndroid Build Coastguard Worker    # The SPDX formatting below works around constraints of the 'reuse' tool
58*61046927SAndroid Build Coastguard Worker    prefixStrings = [
59*61046927SAndroid Build Coastguard Worker        '/*',
60*61046927SAndroid Build Coastguard Worker        '** Copyright 2015-2023 The Khronos Group Inc.',
61*61046927SAndroid Build Coastguard Worker        '**',
62*61046927SAndroid Build Coastguard Worker        '** SPDX-License-Identifier' + ': Apache-2.0',
63*61046927SAndroid Build Coastguard Worker        '*/',
64*61046927SAndroid Build Coastguard Worker        ''
65*61046927SAndroid Build Coastguard Worker    ]
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker    # Text specific to Vulkan headers
68*61046927SAndroid Build Coastguard Worker    vkPrefixStrings = [
69*61046927SAndroid Build Coastguard Worker        '/*',
70*61046927SAndroid Build Coastguard Worker        '** This header is generated from the Khronos Vulkan XML API Registry.',
71*61046927SAndroid Build Coastguard Worker        '**',
72*61046927SAndroid Build Coastguard Worker        '*/',
73*61046927SAndroid Build Coastguard Worker        ''
74*61046927SAndroid Build Coastguard Worker    ]
75*61046927SAndroid Build Coastguard Worker
76*61046927SAndroid Build Coastguard Worker    genOpts['cereal'] = [
77*61046927SAndroid Build Coastguard Worker            CerealGenerator,
78*61046927SAndroid Build Coastguard Worker            CGeneratorOptions(
79*61046927SAndroid Build Coastguard Worker                directory         = directory,
80*61046927SAndroid Build Coastguard Worker                versions          = featuresPat,
81*61046927SAndroid Build Coastguard Worker                emitversions      = featuresPat,
82*61046927SAndroid Build Coastguard Worker                addExtensions     = None,
83*61046927SAndroid Build Coastguard Worker                emitExtensions    = emitExtensionsPat,
84*61046927SAndroid Build Coastguard Worker                prefixText        = prefixStrings + vkPrefixStrings,
85*61046927SAndroid Build Coastguard Worker                apientry          = 'VKAPI_CALL ',
86*61046927SAndroid Build Coastguard Worker                apientryp         = 'VKAPI_PTR *',
87*61046927SAndroid Build Coastguard Worker                alignFuncParam    = 48)
88*61046927SAndroid Build Coastguard Worker        ]
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker    gfxstreamPrefixStrings = [
91*61046927SAndroid Build Coastguard Worker        '#pragma once',
92*61046927SAndroid Build Coastguard Worker        '#ifdef VK_GFXSTREAM_STRUCTURE_TYPE_EXT',
93*61046927SAndroid Build Coastguard Worker        '#include "vulkan_gfxstream_structure_type.h"',
94*61046927SAndroid Build Coastguard Worker        '#endif',
95*61046927SAndroid Build Coastguard Worker    ]
96*61046927SAndroid Build Coastguard Worker
97*61046927SAndroid Build Coastguard Worker    # gfxstream specific header
98*61046927SAndroid Build Coastguard Worker    genOpts['vulkan_gfxstream.h'] = [
99*61046927SAndroid Build Coastguard Worker          COutputGenerator,
100*61046927SAndroid Build Coastguard Worker          CGeneratorOptions(
101*61046927SAndroid Build Coastguard Worker            filename          = 'vulkan_gfxstream.h',
102*61046927SAndroid Build Coastguard Worker            directory         = directory,
103*61046927SAndroid Build Coastguard Worker            versions          = featuresPat,
104*61046927SAndroid Build Coastguard Worker            emitversions      = None,
105*61046927SAndroid Build Coastguard Worker            addExtensions     = makeREstring(['VK_GOOGLE_gfxstream'], None),
106*61046927SAndroid Build Coastguard Worker            emitExtensions    = makeREstring(['VK_GOOGLE_gfxstream'], None),
107*61046927SAndroid Build Coastguard Worker            prefixText        = prefixStrings + vkPrefixStrings + gfxstreamPrefixStrings,
108*61046927SAndroid Build Coastguard Worker            # Use #pragma once in the prefixText instead, so that we can put the copyright comments
109*61046927SAndroid Build Coastguard Worker            # at the beginning of the file.
110*61046927SAndroid Build Coastguard Worker            apientry          = 'VKAPI_CALL ',
111*61046927SAndroid Build Coastguard Worker            apientryp         = 'VKAPI_PTR *',
112*61046927SAndroid Build Coastguard Worker            alignFuncParam    = 48)
113*61046927SAndroid Build Coastguard Worker        ]
114*61046927SAndroid Build Coastguard Worker
115*61046927SAndroid Build Coastguard Workerdef genTarget(args):
116*61046927SAndroid Build Coastguard Worker    """Create an API generator and corresponding generator options based on
117*61046927SAndroid Build Coastguard Worker    the requested target and command line options.
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker    This is encapsulated in a function so it can be profiled and/or timed.
120*61046927SAndroid Build Coastguard Worker    The args parameter is an parsed argument object containing the following
121*61046927SAndroid Build Coastguard Worker    fields that are used:
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker    - target - target to generate
124*61046927SAndroid Build Coastguard Worker    - directory - directory to generate it in
125*61046927SAndroid Build Coastguard Worker    - extensions - list of additional extensions to include in generated interfaces"""
126*61046927SAndroid Build Coastguard Worker
127*61046927SAndroid Build Coastguard Worker    # Create generator options with parameters specified on command line
128*61046927SAndroid Build Coastguard Worker    makeGenOpts(args)
129*61046927SAndroid Build Coastguard Worker
130*61046927SAndroid Build Coastguard Worker    # Select a generator matching the requested target
131*61046927SAndroid Build Coastguard Worker    if args.target in genOpts:
132*61046927SAndroid Build Coastguard Worker        createGenerator = genOpts[args.target][0]
133*61046927SAndroid Build Coastguard Worker        options = genOpts[args.target][1]
134*61046927SAndroid Build Coastguard Worker
135*61046927SAndroid Build Coastguard Worker        gen = createGenerator(errFile=errWarn,
136*61046927SAndroid Build Coastguard Worker                              warnFile=errWarn,
137*61046927SAndroid Build Coastguard Worker                              diagFile=diag)
138*61046927SAndroid Build Coastguard Worker        return (gen, options)
139*61046927SAndroid Build Coastguard Worker    else:
140*61046927SAndroid Build Coastguard Worker        return None
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker
143*61046927SAndroid Build Coastguard Worker# -feature name
144*61046927SAndroid Build Coastguard Worker# -extension name
145*61046927SAndroid Build Coastguard Worker# For both, "name" may be a single name, or a space-separated list
146*61046927SAndroid Build Coastguard Worker# of names, or a regular expression.
147*61046927SAndroid Build Coastguard Workerif __name__ == '__main__':
148*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
149*61046927SAndroid Build Coastguard Worker    parser.add_argument('-registry', action='store',
150*61046927SAndroid Build Coastguard Worker                        default='vk.xml',
151*61046927SAndroid Build Coastguard Worker                        help='Use specified registry file instead of vk.xml')
152*61046927SAndroid Build Coastguard Worker    parser.add_argument('-registryGfxstream', action='store',
153*61046927SAndroid Build Coastguard Worker                        default=None,
154*61046927SAndroid Build Coastguard Worker                        help='Use specified gfxstream registry file')
155*61046927SAndroid Build Coastguard Worker    parser.add_argument('-o', action='store', dest='directory',
156*61046927SAndroid Build Coastguard Worker                        default='.',
157*61046927SAndroid Build Coastguard Worker                        help='Create target and related files in specified directory')
158*61046927SAndroid Build Coastguard Worker    parser.add_argument('target', metavar='target', nargs='?',
159*61046927SAndroid Build Coastguard Worker                        help='Specify target')
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker    errWarn = sys.stderr
164*61046927SAndroid Build Coastguard Worker    diag = None
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker    # Create the API generator & generator options
167*61046927SAndroid Build Coastguard Worker    (gen, options) = genTarget(args)
168*61046927SAndroid Build Coastguard Worker
169*61046927SAndroid Build Coastguard Worker    # Create the registry object with the specified generator and generator
170*61046927SAndroid Build Coastguard Worker    # options. The options are set before XML loading as they may affect it.
171*61046927SAndroid Build Coastguard Worker    reg = Registry(gen, options)
172*61046927SAndroid Build Coastguard Worker
173*61046927SAndroid Build Coastguard Worker    # Parse the specified registry XML into an ElementTree object
174*61046927SAndroid Build Coastguard Worker    tree = etree.parse(args.registry)
175*61046927SAndroid Build Coastguard Worker
176*61046927SAndroid Build Coastguard Worker    # Merge the gfxstream registry with the official Vulkan registry if the
177*61046927SAndroid Build Coastguard Worker    # target is the cereal generator
178*61046927SAndroid Build Coastguard Worker    if args.registryGfxstream is not None and args.target == 'cereal':
179*61046927SAndroid Build Coastguard Worker        treeGfxstream = etree.parse(args.registryGfxstream)
180*61046927SAndroid Build Coastguard Worker        treeRoot = tree.getroot()
181*61046927SAndroid Build Coastguard Worker        treeGfxstreamRoot = treeGfxstream.getroot()
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker        def getEntryName(entry) -> Optional[str]:
184*61046927SAndroid Build Coastguard Worker            name = entry.get("name")
185*61046927SAndroid Build Coastguard Worker            if name is not None:
186*61046927SAndroid Build Coastguard Worker                return name
187*61046927SAndroid Build Coastguard Worker            try:
188*61046927SAndroid Build Coastguard Worker                return entry.find("proto").find("name").text
189*61046927SAndroid Build Coastguard Worker            except AttributeError:
190*61046927SAndroid Build Coastguard Worker                return None
191*61046927SAndroid Build Coastguard Worker
192*61046927SAndroid Build Coastguard Worker        for entriesName in ['types', 'commands', 'extensions']:
193*61046927SAndroid Build Coastguard Worker            treeEntries = treeRoot.find(entriesName)
194*61046927SAndroid Build Coastguard Worker
195*61046927SAndroid Build Coastguard Worker            originalEntryDict = {}
196*61046927SAndroid Build Coastguard Worker            for entry in treeEntries:
197*61046927SAndroid Build Coastguard Worker                name = getEntryName(entry)
198*61046927SAndroid Build Coastguard Worker                if name is not None:
199*61046927SAndroid Build Coastguard Worker                    originalEntryDict[name] = entry
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker            for entry in treeGfxstreamRoot.find(entriesName):
202*61046927SAndroid Build Coastguard Worker                name = getEntryName(entry)
203*61046927SAndroid Build Coastguard Worker                # New entry, just append to entry list
204*61046927SAndroid Build Coastguard Worker                if name not in originalEntryDict.keys():
205*61046927SAndroid Build Coastguard Worker                    treeEntries.append(entry)
206*61046927SAndroid Build Coastguard Worker                    continue
207*61046927SAndroid Build Coastguard Worker
208*61046927SAndroid Build Coastguard Worker                originalEntry = originalEntryDict[name]
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker                # Extending an existing entry. This happens for MVK.
211*61046927SAndroid Build Coastguard Worker                if entriesName == "extensions":
212*61046927SAndroid Build Coastguard Worker                    for key, value in entry.attrib.items():
213*61046927SAndroid Build Coastguard Worker                        originalEntry.set(key, value)
214*61046927SAndroid Build Coastguard Worker                    require = entry.find("require")
215*61046927SAndroid Build Coastguard Worker                    if require is not None:
216*61046927SAndroid Build Coastguard Worker                        for child in require:
217*61046927SAndroid Build Coastguard Worker                            originalEntry.find("require").append(child)
218*61046927SAndroid Build Coastguard Worker                    continue
219*61046927SAndroid Build Coastguard Worker
220*61046927SAndroid Build Coastguard Worker                # Overwriting an existing entry. This happen for
221*61046927SAndroid Build Coastguard Worker                # VkNativeBufferANDROID
222*61046927SAndroid Build Coastguard Worker                if entriesName == "types" or entriesName == "commands":
223*61046927SAndroid Build Coastguard Worker                    originalEntry.clear()
224*61046927SAndroid Build Coastguard Worker                    originalEntry.attrib = entry.attrib
225*61046927SAndroid Build Coastguard Worker                    for child in entry:
226*61046927SAndroid Build Coastguard Worker                        originalEntry.append(child)
227*61046927SAndroid Build Coastguard Worker
228*61046927SAndroid Build Coastguard Worker    # Load the XML tree into the registry object
229*61046927SAndroid Build Coastguard Worker    reg.loadElementTree(tree)
230*61046927SAndroid Build Coastguard Worker    reg.apiGen()
231