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