1*61046927SAndroid Build Coastguard Worker#!/usr/bin/python3 -i 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 Worker"""Types and classes for manipulating an API registry.""" 9*61046927SAndroid Build Coastguard Worker 10*61046927SAndroid Build Coastguard Workerimport copy 11*61046927SAndroid Build Coastguard Workerimport re 12*61046927SAndroid Build Coastguard Workerimport sys 13*61046927SAndroid Build Coastguard Workerimport xml.etree.ElementTree as etree 14*61046927SAndroid Build Coastguard Workerfrom collections import defaultdict, deque, namedtuple 15*61046927SAndroid Build Coastguard Worker 16*61046927SAndroid Build Coastguard Workerfrom generator import GeneratorOptions, OutputGenerator, noneStr, write 17*61046927SAndroid Build Coastguard Worker 18*61046927SAndroid Build Coastguard Workerdef apiNameMatch(str, supported): 19*61046927SAndroid Build Coastguard Worker """Return whether a required api name matches a pattern specified for an 20*61046927SAndroid Build Coastguard Worker XML <feature> 'api' attribute or <extension> 'supported' attribute. 21*61046927SAndroid Build Coastguard Worker 22*61046927SAndroid Build Coastguard Worker - str - API name such as 'vulkan' or 'openxr'. May be None, in which 23*61046927SAndroid Build Coastguard Worker case it never matches (this should not happen). 24*61046927SAndroid Build Coastguard Worker - supported - comma-separated list of XML API names. May be None, in 25*61046927SAndroid Build Coastguard Worker which case str always matches (this is the usual case).""" 26*61046927SAndroid Build Coastguard Worker 27*61046927SAndroid Build Coastguard Worker if str is not None: 28*61046927SAndroid Build Coastguard Worker return supported is None or str in supported.split(',') 29*61046927SAndroid Build Coastguard Worker 30*61046927SAndroid Build Coastguard Worker # Fallthrough case - either str is None or the test failed 31*61046927SAndroid Build Coastguard Worker return False 32*61046927SAndroid Build Coastguard Worker 33*61046927SAndroid Build Coastguard Workerdef matchAPIProfile(api, elem): 34*61046927SAndroid Build Coastguard Worker """Return whether an API and profile 35*61046927SAndroid Build Coastguard Worker like `"gl(core)|gles1(common-lite)"`.""" 36*61046927SAndroid Build Coastguard Worker # Match 'api', if present 37*61046927SAndroid Build Coastguard Worker elem_api = elem.get('api') 38*61046927SAndroid Build Coastguard Worker if elem_api: 39*61046927SAndroid Build Coastguard Worker if api is None: 40*61046927SAndroid Build Coastguard Worker raise UserWarning("No API requested, but 'api' attribute is present with value '" 41*61046927SAndroid Build Coastguard Worker + elem_api + "'") 42*61046927SAndroid Build Coastguard Worker elif api != elem_api: 43*61046927SAndroid Build Coastguard Worker # Requested API does not match attribute 44*61046927SAndroid Build Coastguard Worker return False 45*61046927SAndroid Build Coastguard Worker return True 46*61046927SAndroid Build Coastguard Worker 47*61046927SAndroid Build Coastguard Workerclass BaseInfo: 48*61046927SAndroid Build Coastguard Worker """Base class for information about a registry feature 49*61046927SAndroid Build Coastguard Worker (type/group/enum/command/API/extension). 50*61046927SAndroid Build Coastguard Worker 51*61046927SAndroid Build Coastguard Worker Represents the state of a registry feature, used during API generation. 52*61046927SAndroid Build Coastguard Worker """ 53*61046927SAndroid Build Coastguard Worker 54*61046927SAndroid Build Coastguard Worker def __init__(self, elem): 55*61046927SAndroid Build Coastguard Worker self.required = False 56*61046927SAndroid Build Coastguard Worker """should this feature be defined during header generation 57*61046927SAndroid Build Coastguard Worker (has it been removed by a profile or version)?""" 58*61046927SAndroid Build Coastguard Worker 59*61046927SAndroid Build Coastguard Worker self.declared = False 60*61046927SAndroid Build Coastguard Worker "has this feature been defined already?" 61*61046927SAndroid Build Coastguard Worker 62*61046927SAndroid Build Coastguard Worker self.elem = elem 63*61046927SAndroid Build Coastguard Worker "etree Element for this feature" 64*61046927SAndroid Build Coastguard Worker 65*61046927SAndroid Build Coastguard Worker def resetState(self): 66*61046927SAndroid Build Coastguard Worker """Reset required/declared to initial values. Used 67*61046927SAndroid Build Coastguard Worker prior to generating a new API interface.""" 68*61046927SAndroid Build Coastguard Worker self.required = False 69*61046927SAndroid Build Coastguard Worker self.declared = False 70*61046927SAndroid Build Coastguard Worker 71*61046927SAndroid Build Coastguard Worker def compareKeys(self, info, key, required = False): 72*61046927SAndroid Build Coastguard Worker """Return True if self.elem and info.elem have the same attribute 73*61046927SAndroid Build Coastguard Worker value for key. 74*61046927SAndroid Build Coastguard Worker If 'required' is not True, also returns True if neither element 75*61046927SAndroid Build Coastguard Worker has an attribute value for key.""" 76*61046927SAndroid Build Coastguard Worker 77*61046927SAndroid Build Coastguard Worker if required and key not in self.elem.keys(): 78*61046927SAndroid Build Coastguard Worker return False 79*61046927SAndroid Build Coastguard Worker return self.elem.get(key) == info.elem.get(key) 80*61046927SAndroid Build Coastguard Worker 81*61046927SAndroid Build Coastguard Worker def compareElem(self, info, infoName): 82*61046927SAndroid Build Coastguard Worker """Return True if self.elem and info.elem have the same definition. 83*61046927SAndroid Build Coastguard Worker info - the other object 84*61046927SAndroid Build Coastguard Worker infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 85*61046927SAndroid Build Coastguard Worker 'extension'""" 86*61046927SAndroid Build Coastguard Worker 87*61046927SAndroid Build Coastguard Worker if infoName == 'enum': 88*61046927SAndroid Build Coastguard Worker if self.compareKeys(info, 'extends'): 89*61046927SAndroid Build Coastguard Worker # Either both extend the same type, or no type 90*61046927SAndroid Build Coastguard Worker if (self.compareKeys(info, 'value', required = True) or 91*61046927SAndroid Build Coastguard Worker self.compareKeys(info, 'bitpos', required = True)): 92*61046927SAndroid Build Coastguard Worker # If both specify the same value or bit position, 93*61046927SAndroid Build Coastguard Worker # they are equal 94*61046927SAndroid Build Coastguard Worker return True 95*61046927SAndroid Build Coastguard Worker elif (self.compareKeys(info, 'extnumber') and 96*61046927SAndroid Build Coastguard Worker self.compareKeys(info, 'offset') and 97*61046927SAndroid Build Coastguard Worker self.compareKeys(info, 'dir')): 98*61046927SAndroid Build Coastguard Worker # If both specify the same relative offset, they are equal 99*61046927SAndroid Build Coastguard Worker return True 100*61046927SAndroid Build Coastguard Worker elif (self.compareKeys(info, 'alias')): 101*61046927SAndroid Build Coastguard Worker # If both are aliases of the same value 102*61046927SAndroid Build Coastguard Worker return True 103*61046927SAndroid Build Coastguard Worker else: 104*61046927SAndroid Build Coastguard Worker return False 105*61046927SAndroid Build Coastguard Worker else: 106*61046927SAndroid Build Coastguard Worker # The same enum cannot extend two different types 107*61046927SAndroid Build Coastguard Worker return False 108*61046927SAndroid Build Coastguard Worker else: 109*61046927SAndroid Build Coastguard Worker # Non-<enum>s should never be redefined 110*61046927SAndroid Build Coastguard Worker return False 111*61046927SAndroid Build Coastguard Worker 112*61046927SAndroid Build Coastguard Worker 113*61046927SAndroid Build Coastguard Workerclass TypeInfo(BaseInfo): 114*61046927SAndroid Build Coastguard Worker """Registry information about a type. No additional state 115*61046927SAndroid Build Coastguard Worker beyond BaseInfo is required.""" 116*61046927SAndroid Build Coastguard Worker 117*61046927SAndroid Build Coastguard Worker def __init__(self, elem): 118*61046927SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 119*61046927SAndroid Build Coastguard Worker self.additionalValidity = [] 120*61046927SAndroid Build Coastguard Worker self.removedValidity = [] 121*61046927SAndroid Build Coastguard Worker 122*61046927SAndroid Build Coastguard Worker def getMembers(self): 123*61046927SAndroid Build Coastguard Worker """Get a collection of all member elements for this type, if any.""" 124*61046927SAndroid Build Coastguard Worker return self.elem.findall('member') 125*61046927SAndroid Build Coastguard Worker 126*61046927SAndroid Build Coastguard Worker def resetState(self): 127*61046927SAndroid Build Coastguard Worker BaseInfo.resetState(self) 128*61046927SAndroid Build Coastguard Worker self.additionalValidity = [] 129*61046927SAndroid Build Coastguard Worker self.removedValidity = [] 130*61046927SAndroid Build Coastguard Worker 131*61046927SAndroid Build Coastguard Worker 132*61046927SAndroid Build Coastguard Workerclass GroupInfo(BaseInfo): 133*61046927SAndroid Build Coastguard Worker """Registry information about a group of related enums 134*61046927SAndroid Build Coastguard Worker in an <enums> block, generally corresponding to a C "enum" type.""" 135*61046927SAndroid Build Coastguard Worker 136*61046927SAndroid Build Coastguard Worker def __init__(self, elem): 137*61046927SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 138*61046927SAndroid Build Coastguard Worker 139*61046927SAndroid Build Coastguard Worker 140*61046927SAndroid Build Coastguard Workerclass EnumInfo(BaseInfo): 141*61046927SAndroid Build Coastguard Worker """Registry information about an enum""" 142*61046927SAndroid Build Coastguard Worker 143*61046927SAndroid Build Coastguard Worker def __init__(self, elem): 144*61046927SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 145*61046927SAndroid Build Coastguard Worker self.type = elem.get('type') 146*61046927SAndroid Build Coastguard Worker """numeric type of the value of the <enum> tag 147*61046927SAndroid Build Coastguard Worker ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )""" 148*61046927SAndroid Build Coastguard Worker if self.type is None: 149*61046927SAndroid Build Coastguard Worker self.type = '' 150*61046927SAndroid Build Coastguard Worker 151*61046927SAndroid Build Coastguard Worker 152*61046927SAndroid Build Coastguard Workerclass CmdInfo(BaseInfo): 153*61046927SAndroid Build Coastguard Worker """Registry information about a command""" 154*61046927SAndroid Build Coastguard Worker 155*61046927SAndroid Build Coastguard Worker def __init__(self, elem): 156*61046927SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 157*61046927SAndroid Build Coastguard Worker self.additionalValidity = [] 158*61046927SAndroid Build Coastguard Worker self.removedValidity = [] 159*61046927SAndroid Build Coastguard Worker 160*61046927SAndroid Build Coastguard Worker def getParams(self): 161*61046927SAndroid Build Coastguard Worker """Get a collection of all param elements for this command, if any.""" 162*61046927SAndroid Build Coastguard Worker return self.elem.findall('param') 163*61046927SAndroid Build Coastguard Worker 164*61046927SAndroid Build Coastguard Worker def resetState(self): 165*61046927SAndroid Build Coastguard Worker BaseInfo.resetState(self) 166*61046927SAndroid Build Coastguard Worker self.additionalValidity = [] 167*61046927SAndroid Build Coastguard Worker self.removedValidity = [] 168*61046927SAndroid Build Coastguard Worker 169*61046927SAndroid Build Coastguard Worker 170*61046927SAndroid Build Coastguard Workerclass FeatureInfo(BaseInfo): 171*61046927SAndroid Build Coastguard Worker """Registry information about an API <feature> 172*61046927SAndroid Build Coastguard Worker or <extension>.""" 173*61046927SAndroid Build Coastguard Worker 174*61046927SAndroid Build Coastguard Worker def __init__(self, elem): 175*61046927SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 176*61046927SAndroid Build Coastguard Worker self.name = elem.get('name') 177*61046927SAndroid Build Coastguard Worker "feature name string (e.g. 'VK_KHR_surface')" 178*61046927SAndroid Build Coastguard Worker 179*61046927SAndroid Build Coastguard Worker self.emit = False 180*61046927SAndroid Build Coastguard Worker "has this feature been defined already?" 181*61046927SAndroid Build Coastguard Worker 182*61046927SAndroid Build Coastguard Worker self.sortorder = int(elem.get('sortorder', 0)) 183*61046927SAndroid Build Coastguard Worker """explicit numeric sort key within feature and extension groups. 184*61046927SAndroid Build Coastguard Worker Defaults to 0.""" 185*61046927SAndroid Build Coastguard Worker 186*61046927SAndroid Build Coastguard Worker # Determine element category (vendor). Only works 187*61046927SAndroid Build Coastguard Worker # for <extension> elements. 188*61046927SAndroid Build Coastguard Worker if elem.tag == 'feature': 189*61046927SAndroid Build Coastguard Worker # Element category (vendor) is meaningless for <feature> 190*61046927SAndroid Build Coastguard Worker self.category = 'VERSION' 191*61046927SAndroid Build Coastguard Worker """category, e.g. VERSION or khr/vendor tag""" 192*61046927SAndroid Build Coastguard Worker 193*61046927SAndroid Build Coastguard Worker self.version = elem.get('name') 194*61046927SAndroid Build Coastguard Worker """feature name string""" 195*61046927SAndroid Build Coastguard Worker 196*61046927SAndroid Build Coastguard Worker self.versionNumber = elem.get('number') 197*61046927SAndroid Build Coastguard Worker """versionNumber - API version number, taken from the 'number' 198*61046927SAndroid Build Coastguard Worker attribute of <feature>. Extensions do not have API version 199*61046927SAndroid Build Coastguard Worker numbers and are assigned number 0.""" 200*61046927SAndroid Build Coastguard Worker 201*61046927SAndroid Build Coastguard Worker self.number = 0 202*61046927SAndroid Build Coastguard Worker self.supported = None 203*61046927SAndroid Build Coastguard Worker else: 204*61046927SAndroid Build Coastguard Worker # Extract vendor portion of <APIprefix>_<vendor>_<name> 205*61046927SAndroid Build Coastguard Worker self.category = self.name.split('_', 2)[1] 206*61046927SAndroid Build Coastguard Worker self.version = "0" 207*61046927SAndroid Build Coastguard Worker self.versionNumber = "0" 208*61046927SAndroid Build Coastguard Worker 209*61046927SAndroid Build Coastguard Worker self.number = int(elem.get('number','0')) 210*61046927SAndroid Build Coastguard Worker """extension number, used for ordering and for assigning 211*61046927SAndroid Build Coastguard Worker enumerant offsets. <feature> features do not have extension 212*61046927SAndroid Build Coastguard Worker numbers and are assigned number 0, as are extensions without 213*61046927SAndroid Build Coastguard Worker numbers, so sorting works.""" 214*61046927SAndroid Build Coastguard Worker 215*61046927SAndroid Build Coastguard Worker self.supported = elem.get('supported', 'disabled') 216*61046927SAndroid Build Coastguard Worker 217*61046927SAndroid Build Coastguard Workerclass Registry: 218*61046927SAndroid Build Coastguard Worker """Object representing an API registry, loaded from an XML file.""" 219*61046927SAndroid Build Coastguard Worker 220*61046927SAndroid Build Coastguard Worker def __init__(self, gen=None, genOpts=None): 221*61046927SAndroid Build Coastguard Worker if gen is None: 222*61046927SAndroid Build Coastguard Worker # If not specified, give a default object so messaging will work 223*61046927SAndroid Build Coastguard Worker self.gen = OutputGenerator() 224*61046927SAndroid Build Coastguard Worker else: 225*61046927SAndroid Build Coastguard Worker self.gen = gen 226*61046927SAndroid Build Coastguard Worker "Output generator used to write headers / messages" 227*61046927SAndroid Build Coastguard Worker 228*61046927SAndroid Build Coastguard Worker if genOpts is None: 229*61046927SAndroid Build Coastguard Worker # If no generator is provided, we may still need the XML API name 230*61046927SAndroid Build Coastguard Worker # (for example, in genRef.py). 231*61046927SAndroid Build Coastguard Worker self.genOpts = GeneratorOptions(apiname = 'vulkan') 232*61046927SAndroid Build Coastguard Worker else: 233*61046927SAndroid Build Coastguard Worker self.genOpts = genOpts 234*61046927SAndroid Build Coastguard Worker "Options controlling features to write and how to format them" 235*61046927SAndroid Build Coastguard Worker 236*61046927SAndroid Build Coastguard Worker self.gen.registry = self 237*61046927SAndroid Build Coastguard Worker self.gen.genOpts = self.genOpts 238*61046927SAndroid Build Coastguard Worker self.gen.genOpts.registry = self 239*61046927SAndroid Build Coastguard Worker 240*61046927SAndroid Build Coastguard Worker self.tree = None 241*61046927SAndroid Build Coastguard Worker "ElementTree containing the root `<registry>`" 242*61046927SAndroid Build Coastguard Worker 243*61046927SAndroid Build Coastguard Worker self.typedict = {} 244*61046927SAndroid Build Coastguard Worker "dictionary of TypeInfo objects keyed by type name" 245*61046927SAndroid Build Coastguard Worker 246*61046927SAndroid Build Coastguard Worker self.groupdict = {} 247*61046927SAndroid Build Coastguard Worker "dictionary of GroupInfo objects keyed by group name" 248*61046927SAndroid Build Coastguard Worker 249*61046927SAndroid Build Coastguard Worker self.enumdict = {} 250*61046927SAndroid Build Coastguard Worker "dictionary of EnumInfo objects keyed by enum name" 251*61046927SAndroid Build Coastguard Worker 252*61046927SAndroid Build Coastguard Worker self.cmddict = {} 253*61046927SAndroid Build Coastguard Worker "dictionary of CmdInfo objects keyed by command name" 254*61046927SAndroid Build Coastguard Worker 255*61046927SAndroid Build Coastguard Worker self.apidict = {} 256*61046927SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<feature>` elements keyed by API name" 257*61046927SAndroid Build Coastguard Worker 258*61046927SAndroid Build Coastguard Worker self.extensions = [] 259*61046927SAndroid Build Coastguard Worker "list of `<extension>` Elements" 260*61046927SAndroid Build Coastguard Worker 261*61046927SAndroid Build Coastguard Worker self.extdict = {} 262*61046927SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<extension>` elements keyed by extension name" 263*61046927SAndroid Build Coastguard Worker 264*61046927SAndroid Build Coastguard Worker self.emitFeatures = False 265*61046927SAndroid Build Coastguard Worker """True to actually emit features for a version / extension, 266*61046927SAndroid Build Coastguard Worker or False to just treat them as emitted""" 267*61046927SAndroid Build Coastguard Worker 268*61046927SAndroid Build Coastguard Worker self.filename = None 269*61046927SAndroid Build Coastguard Worker 270*61046927SAndroid Build Coastguard Worker def loadElementTree(self, tree): 271*61046927SAndroid Build Coastguard Worker """Load ElementTree into a Registry object and parse it.""" 272*61046927SAndroid Build Coastguard Worker self.tree = tree 273*61046927SAndroid Build Coastguard Worker self.parseTree() 274*61046927SAndroid Build Coastguard Worker 275*61046927SAndroid Build Coastguard Worker def loadFile(self, file): 276*61046927SAndroid Build Coastguard Worker """Load an API registry XML file into a Registry object and parse it""" 277*61046927SAndroid Build Coastguard Worker self.filename = file 278*61046927SAndroid Build Coastguard Worker self.tree = etree.parse(file) 279*61046927SAndroid Build Coastguard Worker self.parseTree() 280*61046927SAndroid Build Coastguard Worker 281*61046927SAndroid Build Coastguard Worker def setGenerator(self, gen): 282*61046927SAndroid Build Coastguard Worker """Specify output generator object. 283*61046927SAndroid Build Coastguard Worker 284*61046927SAndroid Build Coastguard Worker `None` restores the default generator.""" 285*61046927SAndroid Build Coastguard Worker self.gen = gen 286*61046927SAndroid Build Coastguard Worker self.gen.setRegistry(self) 287*61046927SAndroid Build Coastguard Worker 288*61046927SAndroid Build Coastguard Worker def addElementInfo(self, elem, info, infoName, dictionary): 289*61046927SAndroid Build Coastguard Worker """Add information about an element to the corresponding dictionary. 290*61046927SAndroid Build Coastguard Worker 291*61046927SAndroid Build Coastguard Worker Intended for internal use only. 292*61046927SAndroid Build Coastguard Worker 293*61046927SAndroid Build Coastguard Worker - elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>`/`<spirvextension>`/`<spirvcapability>`/`<format>`/`<syncstage>`/`<syncaccess>`/`<syncpipeline>` Element 294*61046927SAndroid Build Coastguard Worker - info - corresponding {Type|Group|Enum|Cmd|Feature|Spirv|Format|SyncStage|SyncAccess|SyncPipeline}Info object 295*61046927SAndroid Build Coastguard Worker - infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' / 'spirvextension' / 'spirvcapability' / 'format' / 'syncstage' / 'syncaccess' / 'syncpipeline' 296*61046927SAndroid Build Coastguard Worker - dictionary - self.{type|group|enum|cmd|api|ext|format|spirvext|spirvcap|sync}dict 297*61046927SAndroid Build Coastguard Worker 298*61046927SAndroid Build Coastguard Worker The dictionary key is the element 'name' attribute.""" 299*61046927SAndroid Build Coastguard Worker 300*61046927SAndroid Build Coastguard Worker key = elem.get('name') 301*61046927SAndroid Build Coastguard Worker if key in dictionary: 302*61046927SAndroid Build Coastguard Worker if not dictionary[key].compareElem(info, infoName): 303*61046927SAndroid Build Coastguard Worker return 304*61046927SAndroid Build Coastguard Worker else: 305*61046927SAndroid Build Coastguard Worker dictionary[key] = info 306*61046927SAndroid Build Coastguard Worker 307*61046927SAndroid Build Coastguard Worker def lookupElementInfo(self, fname, dictionary): 308*61046927SAndroid Build Coastguard Worker """Find a {Type|Enum|Cmd}Info object by name. 309*61046927SAndroid Build Coastguard Worker 310*61046927SAndroid Build Coastguard Worker Intended for internal use only. 311*61046927SAndroid Build Coastguard Worker 312*61046927SAndroid Build Coastguard Worker If an object qualified by API name exists, use that. 313*61046927SAndroid Build Coastguard Worker 314*61046927SAndroid Build Coastguard Worker - fname - name of type / enum / command 315*61046927SAndroid Build Coastguard Worker - dictionary - self.{type|enum|cmd}dict""" 316*61046927SAndroid Build Coastguard Worker key = (fname, 'vulkan') 317*61046927SAndroid Build Coastguard Worker if key in dictionary: 318*61046927SAndroid Build Coastguard Worker return dictionary[key] 319*61046927SAndroid Build Coastguard Worker if fname in dictionary: 320*61046927SAndroid Build Coastguard Worker return dictionary[fname] 321*61046927SAndroid Build Coastguard Worker 322*61046927SAndroid Build Coastguard Worker return None 323*61046927SAndroid Build Coastguard Worker 324*61046927SAndroid Build Coastguard Worker def parseTree(self): 325*61046927SAndroid Build Coastguard Worker """Parse the registry Element, once created""" 326*61046927SAndroid Build Coastguard Worker # This must be the Element for the root <registry> 327*61046927SAndroid Build Coastguard Worker if self.tree is None: 328*61046927SAndroid Build Coastguard Worker raise RuntimeError("Tree not initialized!") 329*61046927SAndroid Build Coastguard Worker self.reg = self.tree.getroot() 330*61046927SAndroid Build Coastguard Worker 331*61046927SAndroid Build Coastguard Worker # There is usually one <types> block; more are OK 332*61046927SAndroid Build Coastguard Worker # Required <type> attributes: 'name' or nested <name> tag contents 333*61046927SAndroid Build Coastguard Worker self.typedict = {} 334*61046927SAndroid Build Coastguard Worker for type_elem in self.reg.findall('types/type'): 335*61046927SAndroid Build Coastguard Worker # If the <type> does not already have a 'name' attribute, set 336*61046927SAndroid Build Coastguard Worker # it from contents of its <name> tag. 337*61046927SAndroid Build Coastguard Worker if type_elem.get('name') is None: 338*61046927SAndroid Build Coastguard Worker name_elem = type_elem.find('name') 339*61046927SAndroid Build Coastguard Worker if name_elem is None or not name_elem.text: 340*61046927SAndroid Build Coastguard Worker raise RuntimeError("Type without a name!") 341*61046927SAndroid Build Coastguard Worker type_elem.set('name', name_elem.text) 342*61046927SAndroid Build Coastguard Worker self.addElementInfo(type_elem, TypeInfo(type_elem), 'type', self.typedict) 343*61046927SAndroid Build Coastguard Worker 344*61046927SAndroid Build Coastguard Worker # Create dictionary of registry enum groups from <enums> tags. 345*61046927SAndroid Build Coastguard Worker # 346*61046927SAndroid Build Coastguard Worker # Required <enums> attributes: 'name'. If no name is given, one is 347*61046927SAndroid Build Coastguard Worker # generated, but that group cannot be identified and turned into an 348*61046927SAndroid Build Coastguard Worker # enum type definition - it is just a container for <enum> tags. 349*61046927SAndroid Build Coastguard Worker self.groupdict = {} 350*61046927SAndroid Build Coastguard Worker for group in self.reg.findall('enums'): 351*61046927SAndroid Build Coastguard Worker self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) 352*61046927SAndroid Build Coastguard Worker 353*61046927SAndroid Build Coastguard Worker # Create dictionary of registry enums from <enum> tags 354*61046927SAndroid Build Coastguard Worker # 355*61046927SAndroid Build Coastguard Worker # <enums> tags usually define different namespaces for the values 356*61046927SAndroid Build Coastguard Worker # defined in those tags, but the actual names all share the 357*61046927SAndroid Build Coastguard Worker # same dictionary. 358*61046927SAndroid Build Coastguard Worker # Required <enum> attributes: 'name', 'value' 359*61046927SAndroid Build Coastguard Worker # For containing <enums> which have type="enum" or type="bitmask", 360*61046927SAndroid Build Coastguard Worker # tag all contained <enum>s are required. This is a stopgap until 361*61046927SAndroid Build Coastguard Worker # a better scheme for tagging core and extension enums is created. 362*61046927SAndroid Build Coastguard Worker self.enumdict = {} 363*61046927SAndroid Build Coastguard Worker for enums in self.reg.findall('enums'): 364*61046927SAndroid Build Coastguard Worker required = (enums.get('type') is not None) 365*61046927SAndroid Build Coastguard Worker for enum in enums.findall('enum'): 366*61046927SAndroid Build Coastguard Worker enumInfo = EnumInfo(enum) 367*61046927SAndroid Build Coastguard Worker enumInfo.required = required 368*61046927SAndroid Build Coastguard Worker self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 369*61046927SAndroid Build Coastguard Worker 370*61046927SAndroid Build Coastguard Worker # Create dictionary of registry commands from <command> tags 371*61046927SAndroid Build Coastguard Worker # and add 'name' attribute to each <command> tag (where missing) 372*61046927SAndroid Build Coastguard Worker # based on its <proto><name> element. 373*61046927SAndroid Build Coastguard Worker # 374*61046927SAndroid Build Coastguard Worker # There is usually only one <commands> block; more are OK. 375*61046927SAndroid Build Coastguard Worker # Required <command> attributes: 'name' or <proto><name> tag contents 376*61046927SAndroid Build Coastguard Worker self.cmddict = {} 377*61046927SAndroid Build Coastguard Worker # List of commands which alias others. Contains 378*61046927SAndroid Build Coastguard Worker # [ aliasName, element ] 379*61046927SAndroid Build Coastguard Worker # for each alias 380*61046927SAndroid Build Coastguard Worker cmdAlias = [] 381*61046927SAndroid Build Coastguard Worker for cmd in self.reg.findall('commands/command'): 382*61046927SAndroid Build Coastguard Worker # If the <command> does not already have a 'name' attribute, set 383*61046927SAndroid Build Coastguard Worker # it from contents of its <proto><name> tag. 384*61046927SAndroid Build Coastguard Worker name = cmd.get('name') 385*61046927SAndroid Build Coastguard Worker if name is None: 386*61046927SAndroid Build Coastguard Worker name_elem = cmd.find('proto/name') 387*61046927SAndroid Build Coastguard Worker if name_elem is None or not name_elem.text: 388*61046927SAndroid Build Coastguard Worker raise RuntimeError("Command without a name!") 389*61046927SAndroid Build Coastguard Worker name = cmd.set('name', name_elem.text) 390*61046927SAndroid Build Coastguard Worker ci = CmdInfo(cmd) 391*61046927SAndroid Build Coastguard Worker self.addElementInfo(cmd, ci, 'command', self.cmddict) 392*61046927SAndroid Build Coastguard Worker alias = cmd.get('alias') 393*61046927SAndroid Build Coastguard Worker if alias: 394*61046927SAndroid Build Coastguard Worker cmdAlias.append([name, alias, cmd]) 395*61046927SAndroid Build Coastguard Worker 396*61046927SAndroid Build Coastguard Worker # Now loop over aliases, injecting a copy of the aliased command's 397*61046927SAndroid Build Coastguard Worker # Element with the aliased prototype name replaced with the command 398*61046927SAndroid Build Coastguard Worker # name - if it exists. 399*61046927SAndroid Build Coastguard Worker for (name, alias, cmd) in cmdAlias: 400*61046927SAndroid Build Coastguard Worker if alias in self.cmddict: 401*61046927SAndroid Build Coastguard Worker aliasInfo = self.cmddict[alias] 402*61046927SAndroid Build Coastguard Worker cmdElem = copy.deepcopy(aliasInfo.elem) 403*61046927SAndroid Build Coastguard Worker cmdElem.find('proto/name').text = name 404*61046927SAndroid Build Coastguard Worker cmdElem.set('name', name) 405*61046927SAndroid Build Coastguard Worker cmdElem.set('alias', alias) 406*61046927SAndroid Build Coastguard Worker ci = CmdInfo(cmdElem) 407*61046927SAndroid Build Coastguard Worker # Replace the dictionary entry for the CmdInfo element 408*61046927SAndroid Build Coastguard Worker self.cmddict[name] = ci 409*61046927SAndroid Build Coastguard Worker 410*61046927SAndroid Build Coastguard Worker # Create dictionaries of API and extension interfaces 411*61046927SAndroid Build Coastguard Worker # from toplevel <api> and <extension> tags. 412*61046927SAndroid Build Coastguard Worker self.apidict = {} 413*61046927SAndroid Build Coastguard Worker for feature in self.reg.findall('feature'): 414*61046927SAndroid Build Coastguard Worker featureInfo = FeatureInfo(feature) 415*61046927SAndroid Build Coastguard Worker self.addElementInfo(feature, featureInfo, 'feature', self.apidict) 416*61046927SAndroid Build Coastguard Worker 417*61046927SAndroid Build Coastguard Worker # Add additional enums defined only in <feature> tags 418*61046927SAndroid Build Coastguard Worker # to the corresponding enumerated type. 419*61046927SAndroid Build Coastguard Worker # When seen here, the <enum> element, processed to contain the 420*61046927SAndroid Build Coastguard Worker # numeric enum value, is added to the corresponding <enums> 421*61046927SAndroid Build Coastguard Worker # element, as well as adding to the enum dictionary. It is no 422*61046927SAndroid Build Coastguard Worker # longer removed from the <require> element it is introduced in. 423*61046927SAndroid Build Coastguard Worker # Instead, generateRequiredInterface ignores <enum> elements 424*61046927SAndroid Build Coastguard Worker # that extend enumerated types. 425*61046927SAndroid Build Coastguard Worker # 426*61046927SAndroid Build Coastguard Worker # For <enum> tags which are actually just constants, if there is 427*61046927SAndroid Build Coastguard Worker # no 'extends' tag but there is a 'value' or 'bitpos' tag, just 428*61046927SAndroid Build Coastguard Worker # add an EnumInfo record to the dictionary. That works because 429*61046927SAndroid Build Coastguard Worker # output generation of constants is purely dependency-based, and 430*61046927SAndroid Build Coastguard Worker # does not need to iterate through the XML tags. 431*61046927SAndroid Build Coastguard Worker for elem in feature.findall('require'): 432*61046927SAndroid Build Coastguard Worker for enum in elem.findall('enum'): 433*61046927SAndroid Build Coastguard Worker addEnumInfo = False 434*61046927SAndroid Build Coastguard Worker groupName = enum.get('extends') 435*61046927SAndroid Build Coastguard Worker if groupName is not None: 436*61046927SAndroid Build Coastguard Worker # Add version number attribute to the <enum> element 437*61046927SAndroid Build Coastguard Worker enum.set('version', featureInfo.version) 438*61046927SAndroid Build Coastguard Worker # Look up the GroupInfo with matching groupName 439*61046927SAndroid Build Coastguard Worker if groupName in self.groupdict: 440*61046927SAndroid Build Coastguard Worker gi = self.groupdict[groupName] 441*61046927SAndroid Build Coastguard Worker gi.elem.append(copy.deepcopy(enum)) 442*61046927SAndroid Build Coastguard Worker addEnumInfo = True 443*61046927SAndroid Build Coastguard Worker elif enum.get('value') or enum.get('bitpos') or enum.get('alias'): 444*61046927SAndroid Build Coastguard Worker addEnumInfo = True 445*61046927SAndroid Build Coastguard Worker if addEnumInfo: 446*61046927SAndroid Build Coastguard Worker enumInfo = EnumInfo(enum) 447*61046927SAndroid Build Coastguard Worker self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 448*61046927SAndroid Build Coastguard Worker 449*61046927SAndroid Build Coastguard Worker self.extensions = self.reg.findall('extensions/extension') 450*61046927SAndroid Build Coastguard Worker self.extdict = {} 451*61046927SAndroid Build Coastguard Worker for feature in self.extensions: 452*61046927SAndroid Build Coastguard Worker featureInfo = FeatureInfo(feature) 453*61046927SAndroid Build Coastguard Worker self.addElementInfo(feature, featureInfo, 'extension', self.extdict) 454*61046927SAndroid Build Coastguard Worker 455*61046927SAndroid Build Coastguard Worker # Add additional enums defined only in <extension> tags 456*61046927SAndroid Build Coastguard Worker # to the corresponding core type. 457*61046927SAndroid Build Coastguard Worker # Algorithm matches that of enums in a "feature" tag as above. 458*61046927SAndroid Build Coastguard Worker # 459*61046927SAndroid Build Coastguard Worker # This code also adds a 'extnumber' attribute containing the 460*61046927SAndroid Build Coastguard Worker # extension number, used for enumerant value calculation. 461*61046927SAndroid Build Coastguard Worker for elem in feature.findall('require'): 462*61046927SAndroid Build Coastguard Worker for enum in elem.findall('enum'): 463*61046927SAndroid Build Coastguard Worker addEnumInfo = False 464*61046927SAndroid Build Coastguard Worker groupName = enum.get('extends') 465*61046927SAndroid Build Coastguard Worker if groupName is not None: 466*61046927SAndroid Build Coastguard Worker 467*61046927SAndroid Build Coastguard Worker # Add <extension> block's extension number attribute to 468*61046927SAndroid Build Coastguard Worker # the <enum> element unless specified explicitly, such 469*61046927SAndroid Build Coastguard Worker # as when redefining an enum in another extension. 470*61046927SAndroid Build Coastguard Worker extnumber = enum.get('extnumber') 471*61046927SAndroid Build Coastguard Worker if not extnumber: 472*61046927SAndroid Build Coastguard Worker enum.set('extnumber', str(featureInfo.number)) 473*61046927SAndroid Build Coastguard Worker 474*61046927SAndroid Build Coastguard Worker enum.set('extname', featureInfo.name) 475*61046927SAndroid Build Coastguard Worker enum.set('supported', noneStr(featureInfo.supported)) 476*61046927SAndroid Build Coastguard Worker # Look up the GroupInfo with matching groupName 477*61046927SAndroid Build Coastguard Worker if groupName in self.groupdict: 478*61046927SAndroid Build Coastguard Worker gi = self.groupdict[groupName] 479*61046927SAndroid Build Coastguard Worker gi.elem.append(copy.deepcopy(enum)) 480*61046927SAndroid Build Coastguard Worker 481*61046927SAndroid Build Coastguard Worker addEnumInfo = True 482*61046927SAndroid Build Coastguard Worker elif enum.get('value') or enum.get('bitpos') or enum.get('alias'): 483*61046927SAndroid Build Coastguard Worker addEnumInfo = True 484*61046927SAndroid Build Coastguard Worker if addEnumInfo: 485*61046927SAndroid Build Coastguard Worker enumInfo = EnumInfo(enum) 486*61046927SAndroid Build Coastguard Worker self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 487*61046927SAndroid Build Coastguard Worker 488*61046927SAndroid Build Coastguard Worker def markTypeRequired(self, typename, required): 489*61046927SAndroid Build Coastguard Worker """Require (along with its dependencies) or remove (but not its dependencies) a type. 490*61046927SAndroid Build Coastguard Worker 491*61046927SAndroid Build Coastguard Worker - typename - name of type 492*61046927SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not) 493*61046927SAndroid Build Coastguard Worker """ 494*61046927SAndroid Build Coastguard Worker # Get TypeInfo object for <type> tag corresponding to typename 495*61046927SAndroid Build Coastguard Worker typeinfo = self.lookupElementInfo(typename, self.typedict) 496*61046927SAndroid Build Coastguard Worker if typeinfo is not None: 497*61046927SAndroid Build Coastguard Worker if required: 498*61046927SAndroid Build Coastguard Worker # Tag type dependencies in 'alias' and 'required' attributes as 499*61046927SAndroid Build Coastguard Worker # required. This does not un-tag dependencies in a <remove> 500*61046927SAndroid Build Coastguard Worker # tag. See comments in markRequired() below for the reason. 501*61046927SAndroid Build Coastguard Worker for attrib_name in ['requires', 'alias']: 502*61046927SAndroid Build Coastguard Worker depname = typeinfo.elem.get(attrib_name) 503*61046927SAndroid Build Coastguard Worker if depname: 504*61046927SAndroid Build Coastguard Worker # Do not recurse on self-referential structures. 505*61046927SAndroid Build Coastguard Worker if typename != depname: 506*61046927SAndroid Build Coastguard Worker self.markTypeRequired(depname, required) 507*61046927SAndroid Build Coastguard Worker # Tag types used in defining this type (e.g. in nested 508*61046927SAndroid Build Coastguard Worker # <type> tags) 509*61046927SAndroid Build Coastguard Worker # Look for <type> in entire <command> tree, 510*61046927SAndroid Build Coastguard Worker # not just immediate children 511*61046927SAndroid Build Coastguard Worker for subtype in typeinfo.elem.findall('.//type'): 512*61046927SAndroid Build Coastguard Worker if typename != subtype.text: 513*61046927SAndroid Build Coastguard Worker self.markTypeRequired(subtype.text, required) 514*61046927SAndroid Build Coastguard Worker # Tag enums used in defining this type, for example in 515*61046927SAndroid Build Coastguard Worker # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member> 516*61046927SAndroid Build Coastguard Worker for subenum in typeinfo.elem.findall('.//enum'): 517*61046927SAndroid Build Coastguard Worker self.markEnumRequired(subenum.text, required) 518*61046927SAndroid Build Coastguard Worker # Tag type dependency in 'bitvalues' attributes as 519*61046927SAndroid Build Coastguard Worker # required. This ensures that the bit values for a flag 520*61046927SAndroid Build Coastguard Worker # are emitted 521*61046927SAndroid Build Coastguard Worker depType = typeinfo.elem.get('bitvalues') 522*61046927SAndroid Build Coastguard Worker if depType: 523*61046927SAndroid Build Coastguard Worker self.markTypeRequired(depType, required) 524*61046927SAndroid Build Coastguard Worker group = self.lookupElementInfo(depType, self.groupdict) 525*61046927SAndroid Build Coastguard Worker if group is not None: 526*61046927SAndroid Build Coastguard Worker group.flagType = typeinfo 527*61046927SAndroid Build Coastguard Worker 528*61046927SAndroid Build Coastguard Worker typeinfo.required = required 529*61046927SAndroid Build Coastguard Worker 530*61046927SAndroid Build Coastguard Worker def markEnumRequired(self, enumname, required): 531*61046927SAndroid Build Coastguard Worker """Mark an enum as required or not. 532*61046927SAndroid Build Coastguard Worker 533*61046927SAndroid Build Coastguard Worker - enumname - name of enum 534*61046927SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not)""" 535*61046927SAndroid Build Coastguard Worker 536*61046927SAndroid Build Coastguard Worker enum = self.lookupElementInfo(enumname, self.enumdict) 537*61046927SAndroid Build Coastguard Worker if enum is not None: 538*61046927SAndroid Build Coastguard Worker # If the enum is part of a group, and is being removed, then 539*61046927SAndroid Build Coastguard Worker # look it up in that <enums> tag and remove the Element there, 540*61046927SAndroid Build Coastguard Worker # so that it is not visible to generators (which traverse the 541*61046927SAndroid Build Coastguard Worker # <enums> tag elements rather than using the dictionaries). 542*61046927SAndroid Build Coastguard Worker if not required: 543*61046927SAndroid Build Coastguard Worker groupName = enum.elem.get('extends') 544*61046927SAndroid Build Coastguard Worker if groupName is not None: 545*61046927SAndroid Build Coastguard Worker 546*61046927SAndroid Build Coastguard Worker # Look up the Info with matching groupName 547*61046927SAndroid Build Coastguard Worker if groupName in self.groupdict: 548*61046927SAndroid Build Coastguard Worker gi = self.groupdict[groupName] 549*61046927SAndroid Build Coastguard Worker gienum = gi.elem.find("enum[@name='" + enumname + "']") 550*61046927SAndroid Build Coastguard Worker if gienum is not None: 551*61046927SAndroid Build Coastguard Worker # Remove copy of this enum from the group 552*61046927SAndroid Build Coastguard Worker gi.elem.remove(gienum) 553*61046927SAndroid Build Coastguard Worker else: 554*61046927SAndroid Build Coastguard Worker # This enum is not an extending enum. 555*61046927SAndroid Build Coastguard Worker # The XML tree must be searched for all <enums> that 556*61046927SAndroid Build Coastguard Worker # might have it, so we know the parent to delete from. 557*61046927SAndroid Build Coastguard Worker 558*61046927SAndroid Build Coastguard Worker enumName = enum.elem.get('name') 559*61046927SAndroid Build Coastguard Worker count = 0 560*61046927SAndroid Build Coastguard Worker for enums in self.reg.findall('enums'): 561*61046927SAndroid Build Coastguard Worker for thisEnum in enums.findall('enum'): 562*61046927SAndroid Build Coastguard Worker if thisEnum.get('name') == enumName: 563*61046927SAndroid Build Coastguard Worker # Actually remove it 564*61046927SAndroid Build Coastguard Worker count = count + 1 565*61046927SAndroid Build Coastguard Worker enums.remove(thisEnum) 566*61046927SAndroid Build Coastguard Worker 567*61046927SAndroid Build Coastguard Worker enum.required = required 568*61046927SAndroid Build Coastguard Worker # Tag enum dependencies in 'alias' attribute as required 569*61046927SAndroid Build Coastguard Worker depname = enum.elem.get('alias') 570*61046927SAndroid Build Coastguard Worker if depname: 571*61046927SAndroid Build Coastguard Worker self.markEnumRequired(depname, required) 572*61046927SAndroid Build Coastguard Worker 573*61046927SAndroid Build Coastguard Worker def markCmdRequired(self, cmdname, required): 574*61046927SAndroid Build Coastguard Worker """Mark a command as required or not. 575*61046927SAndroid Build Coastguard Worker 576*61046927SAndroid Build Coastguard Worker - cmdname - name of command 577*61046927SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not)""" 578*61046927SAndroid Build Coastguard Worker cmd = self.lookupElementInfo(cmdname, self.cmddict) 579*61046927SAndroid Build Coastguard Worker if cmd is not None: 580*61046927SAndroid Build Coastguard Worker cmd.required = required 581*61046927SAndroid Build Coastguard Worker # Tag all parameter types of this command as required. 582*61046927SAndroid Build Coastguard Worker # This does not remove types of commands in a <remove> 583*61046927SAndroid Build Coastguard Worker # tag, because many other commands may use the same type. 584*61046927SAndroid Build Coastguard Worker # We could be more clever and reference count types, 585*61046927SAndroid Build Coastguard Worker # instead of using a boolean. 586*61046927SAndroid Build Coastguard Worker if required: 587*61046927SAndroid Build Coastguard Worker # Look for <type> in entire <command> tree, 588*61046927SAndroid Build Coastguard Worker # not just immediate children 589*61046927SAndroid Build Coastguard Worker for type_elem in cmd.elem.findall('.//type'): 590*61046927SAndroid Build Coastguard Worker self.markTypeRequired(type_elem.text, required) 591*61046927SAndroid Build Coastguard Worker 592*61046927SAndroid Build Coastguard Worker def markRequired(self, featurename, feature, required): 593*61046927SAndroid Build Coastguard Worker """Require or remove features specified in the Element. 594*61046927SAndroid Build Coastguard Worker 595*61046927SAndroid Build Coastguard Worker - featurename - name of the feature 596*61046927SAndroid Build Coastguard Worker - feature - Element for `<require>` or `<remove>` tag 597*61046927SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not)""" 598*61046927SAndroid Build Coastguard Worker # Loop over types, enums, and commands in the tag 599*61046927SAndroid Build Coastguard Worker # @@ It would be possible to respect 'api' and 'profile' attributes 600*61046927SAndroid Build Coastguard Worker # in individual features, but that is not done yet. 601*61046927SAndroid Build Coastguard Worker for typeElem in feature.findall('type'): 602*61046927SAndroid Build Coastguard Worker self.markTypeRequired(typeElem.get('name'), required) 603*61046927SAndroid Build Coastguard Worker for enumElem in feature.findall('enum'): 604*61046927SAndroid Build Coastguard Worker self.markEnumRequired(enumElem.get('name'), required) 605*61046927SAndroid Build Coastguard Worker 606*61046927SAndroid Build Coastguard Worker for cmdElem in feature.findall('command'): 607*61046927SAndroid Build Coastguard Worker self.markCmdRequired(cmdElem.get('name'), required) 608*61046927SAndroid Build Coastguard Worker 609*61046927SAndroid Build Coastguard Worker def fillFeatureDictionary(self, interface, featurename, api): 610*61046927SAndroid Build Coastguard Worker """Capture added interfaces for a `<version>` or `<extension>`. 611*61046927SAndroid Build Coastguard Worker 612*61046927SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`, containing 613*61046927SAndroid Build Coastguard Worker `<require>` and `<remove>` tags 614*61046927SAndroid Build Coastguard Worker - featurename - name of the feature 615*61046927SAndroid Build Coastguard Worker - api - string specifying API name being generated 616*61046927SAndroid Build Coastguard Worker """ 617*61046927SAndroid Build Coastguard Worker 618*61046927SAndroid Build Coastguard Worker # Explicitly initialize known types - errors for unhandled categories 619*61046927SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename] = { 620*61046927SAndroid Build Coastguard Worker "enumconstant": {}, 621*61046927SAndroid Build Coastguard Worker "command": {}, 622*61046927SAndroid Build Coastguard Worker "enum": {}, 623*61046927SAndroid Build Coastguard Worker "struct": {}, 624*61046927SAndroid Build Coastguard Worker "handle": {}, 625*61046927SAndroid Build Coastguard Worker "basetype": {}, 626*61046927SAndroid Build Coastguard Worker "include": {}, 627*61046927SAndroid Build Coastguard Worker "define": {}, 628*61046927SAndroid Build Coastguard Worker "bitmask": {}, 629*61046927SAndroid Build Coastguard Worker "union": {}, 630*61046927SAndroid Build Coastguard Worker "funcpointer": {}, 631*61046927SAndroid Build Coastguard Worker } 632*61046927SAndroid Build Coastguard Worker 633*61046927SAndroid Build Coastguard Worker def requireFeatures(self, interface, featurename, api): 634*61046927SAndroid Build Coastguard Worker """Process `<require>` tags for a `<version>` or `<extension>`. 635*61046927SAndroid Build Coastguard Worker 636*61046927SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`, containing 637*61046927SAndroid Build Coastguard Worker `<require>` tags 638*61046927SAndroid Build Coastguard Worker - featurename - name of the feature 639*61046927SAndroid Build Coastguard Worker - api - string specifying API name being generated 640*61046927SAndroid Build Coastguard Worker - profile - string specifying API profile being generated""" 641*61046927SAndroid Build Coastguard Worker 642*61046927SAndroid Build Coastguard Worker # <require> marks things that are required by this version/profile 643*61046927SAndroid Build Coastguard Worker for feature in interface.findall('require'): 644*61046927SAndroid Build Coastguard Worker if matchAPIProfile(api, feature): 645*61046927SAndroid Build Coastguard Worker self.markRequired(featurename, feature, True) 646*61046927SAndroid Build Coastguard Worker 647*61046927SAndroid Build Coastguard Worker def generateFeature(self, fname, ftype, dictionary, explicit=False): 648*61046927SAndroid Build Coastguard Worker """Generate a single type / enum group / enum / command, 649*61046927SAndroid Build Coastguard Worker and all its dependencies as needed. 650*61046927SAndroid Build Coastguard Worker 651*61046927SAndroid Build Coastguard Worker - fname - name of feature (`<type>`/`<enum>`/`<command>`) 652*61046927SAndroid Build Coastguard Worker - ftype - type of feature, 'type' | 'enum' | 'command' 653*61046927SAndroid Build Coastguard Worker - dictionary - of *Info objects - self.{type|enum|cmd}dict 654*61046927SAndroid Build Coastguard Worker - explicit - True if this is explicitly required by the top-level 655*61046927SAndroid Build Coastguard Worker XML <require> tag, False if it is a dependency of an explicit 656*61046927SAndroid Build Coastguard Worker requirement.""" 657*61046927SAndroid Build Coastguard Worker 658*61046927SAndroid Build Coastguard Worker f = self.lookupElementInfo(fname, dictionary) 659*61046927SAndroid Build Coastguard Worker if f is None: 660*61046927SAndroid Build Coastguard Worker return 661*61046927SAndroid Build Coastguard Worker 662*61046927SAndroid Build Coastguard Worker if not f.required: 663*61046927SAndroid Build Coastguard Worker return 664*61046927SAndroid Build Coastguard Worker 665*61046927SAndroid Build Coastguard Worker # If feature is not required, or has already been declared, return 666*61046927SAndroid Build Coastguard Worker if f.declared: 667*61046927SAndroid Build Coastguard Worker return 668*61046927SAndroid Build Coastguard Worker # Always mark feature declared, as though actually emitted 669*61046927SAndroid Build Coastguard Worker f.declared = True 670*61046927SAndroid Build Coastguard Worker 671*61046927SAndroid Build Coastguard Worker # Determine if this is an alias, and of what, if so 672*61046927SAndroid Build Coastguard Worker alias = f.elem.get('alias') 673*61046927SAndroid Build Coastguard Worker # Pull in dependent declaration(s) of the feature. 674*61046927SAndroid Build Coastguard Worker # For types, there may be one type in the 'requires' attribute of 675*61046927SAndroid Build Coastguard Worker # the element, one in the 'alias' attribute, and many in 676*61046927SAndroid Build Coastguard Worker # embedded <type> and <enum> tags within the element. 677*61046927SAndroid Build Coastguard Worker # For commands, there may be many in <type> tags within the element. 678*61046927SAndroid Build Coastguard Worker # For enums, no dependencies are allowed (though perhaps if you 679*61046927SAndroid Build Coastguard Worker # have a uint64 enum, it should require that type). 680*61046927SAndroid Build Coastguard Worker genProc = None 681*61046927SAndroid Build Coastguard Worker followupFeature = None 682*61046927SAndroid Build Coastguard Worker if ftype == 'type': 683*61046927SAndroid Build Coastguard Worker genProc = self.gen.genType 684*61046927SAndroid Build Coastguard Worker 685*61046927SAndroid Build Coastguard Worker # Generate type dependencies in 'alias' and 'requires' attributes 686*61046927SAndroid Build Coastguard Worker if alias: 687*61046927SAndroid Build Coastguard Worker self.generateFeature(alias, 'type', self.typedict) 688*61046927SAndroid Build Coastguard Worker requires = f.elem.get('requires') 689*61046927SAndroid Build Coastguard Worker if requires: 690*61046927SAndroid Build Coastguard Worker self.generateFeature(requires, 'type', self.typedict) 691*61046927SAndroid Build Coastguard Worker 692*61046927SAndroid Build Coastguard Worker # Generate types used in defining this type (e.g. in nested 693*61046927SAndroid Build Coastguard Worker # <type> tags) 694*61046927SAndroid Build Coastguard Worker # Look for <type> in entire <command> tree, 695*61046927SAndroid Build Coastguard Worker # not just immediate children 696*61046927SAndroid Build Coastguard Worker for subtype in f.elem.findall('.//type'): 697*61046927SAndroid Build Coastguard Worker self.generateFeature(subtype.text, 'type', self.typedict) 698*61046927SAndroid Build Coastguard Worker 699*61046927SAndroid Build Coastguard Worker # Generate enums used in defining this type, for example in 700*61046927SAndroid Build Coastguard Worker # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member> 701*61046927SAndroid Build Coastguard Worker for subtype in f.elem.findall('.//enum'): 702*61046927SAndroid Build Coastguard Worker self.generateFeature(subtype.text, 'enum', self.enumdict) 703*61046927SAndroid Build Coastguard Worker 704*61046927SAndroid Build Coastguard Worker # If the type is an enum group, look up the corresponding 705*61046927SAndroid Build Coastguard Worker # group in the group dictionary and generate that instead. 706*61046927SAndroid Build Coastguard Worker if f.elem.get('category') == 'enum': 707*61046927SAndroid Build Coastguard Worker group = self.lookupElementInfo(fname, self.groupdict) 708*61046927SAndroid Build Coastguard Worker if alias is not None: 709*61046927SAndroid Build Coastguard Worker # Now, pass the *aliased* GroupInfo to the genGroup, but 710*61046927SAndroid Build Coastguard Worker # with an additional parameter which is the alias name. 711*61046927SAndroid Build Coastguard Worker genProc = self.gen.genGroup 712*61046927SAndroid Build Coastguard Worker f = self.lookupElementInfo(alias, self.groupdict) 713*61046927SAndroid Build Coastguard Worker elif group is None: 714*61046927SAndroid Build Coastguard Worker return 715*61046927SAndroid Build Coastguard Worker else: 716*61046927SAndroid Build Coastguard Worker genProc = self.gen.genGroup 717*61046927SAndroid Build Coastguard Worker f = group 718*61046927SAndroid Build Coastguard Worker 719*61046927SAndroid Build Coastguard Worker # @ The enum group is not ready for generation. At this 720*61046927SAndroid Build Coastguard Worker # @ point, it contains all <enum> tags injected by 721*61046927SAndroid Build Coastguard Worker # @ <extension> tags without any verification of whether 722*61046927SAndroid Build Coastguard Worker # @ they are required or not. It may also contain 723*61046927SAndroid Build Coastguard Worker # @ duplicates injected by multiple consistent 724*61046927SAndroid Build Coastguard Worker # @ definitions of an <enum>. 725*61046927SAndroid Build Coastguard Worker 726*61046927SAndroid Build Coastguard Worker # @ Pass over each enum, marking its enumdict[] entry as 727*61046927SAndroid Build Coastguard Worker # @ required or not. Mark aliases of enums as required, 728*61046927SAndroid Build Coastguard Worker # @ too. 729*61046927SAndroid Build Coastguard Worker 730*61046927SAndroid Build Coastguard Worker enums = group.elem.findall('enum') 731*61046927SAndroid Build Coastguard Worker # Check for required enums, including aliases 732*61046927SAndroid Build Coastguard Worker # LATER - Check for, report, and remove duplicates? 733*61046927SAndroid Build Coastguard Worker enumAliases = [] 734*61046927SAndroid Build Coastguard Worker for elem in enums: 735*61046927SAndroid Build Coastguard Worker name = elem.get('name') 736*61046927SAndroid Build Coastguard Worker 737*61046927SAndroid Build Coastguard Worker required = False 738*61046927SAndroid Build Coastguard Worker 739*61046927SAndroid Build Coastguard Worker extname = elem.get('extname') 740*61046927SAndroid Build Coastguard Worker version = elem.get('version') 741*61046927SAndroid Build Coastguard Worker if extname is not None: 742*61046927SAndroid Build Coastguard Worker # 'supported' attribute was injected when the <enum> element was 743*61046927SAndroid Build Coastguard Worker # moved into the <enums> group in Registry.parseTree() 744*61046927SAndroid Build Coastguard Worker supported_list = elem.get('supported').split(",") 745*61046927SAndroid Build Coastguard Worker if 'vulkan' in supported_list: 746*61046927SAndroid Build Coastguard Worker required = True 747*61046927SAndroid Build Coastguard Worker elif re.match(self.genOpts.addExtensions, extname) is not None: 748*61046927SAndroid Build Coastguard Worker required = True 749*61046927SAndroid Build Coastguard Worker elif version is not None: 750*61046927SAndroid Build Coastguard Worker required = re.match(self.genOpts.emitversions, version) is not None 751*61046927SAndroid Build Coastguard Worker else: 752*61046927SAndroid Build Coastguard Worker required = True 753*61046927SAndroid Build Coastguard Worker 754*61046927SAndroid Build Coastguard Worker if required: 755*61046927SAndroid Build Coastguard Worker # Mark this element as required (in the element, not the EnumInfo) 756*61046927SAndroid Build Coastguard Worker elem.set('required', 'true') 757*61046927SAndroid Build Coastguard Worker # If it is an alias, track that for later use 758*61046927SAndroid Build Coastguard Worker enumAlias = elem.get('alias') 759*61046927SAndroid Build Coastguard Worker if enumAlias: 760*61046927SAndroid Build Coastguard Worker enumAliases.append(enumAlias) 761*61046927SAndroid Build Coastguard Worker for elem in enums: 762*61046927SAndroid Build Coastguard Worker name = elem.get('name') 763*61046927SAndroid Build Coastguard Worker if name in enumAliases: 764*61046927SAndroid Build Coastguard Worker elem.set('required', 'true') 765*61046927SAndroid Build Coastguard Worker if f is None: 766*61046927SAndroid Build Coastguard Worker raise RuntimeError("Should not get here") 767*61046927SAndroid Build Coastguard Worker if f.elem.get('category') == 'bitmask': 768*61046927SAndroid Build Coastguard Worker followupFeature = f.elem.get('bitvalues') 769*61046927SAndroid Build Coastguard Worker elif ftype == 'command': 770*61046927SAndroid Build Coastguard Worker # Generate command dependencies in 'alias' attribute 771*61046927SAndroid Build Coastguard Worker if alias: 772*61046927SAndroid Build Coastguard Worker self.generateFeature(alias, 'command', self.cmddict) 773*61046927SAndroid Build Coastguard Worker 774*61046927SAndroid Build Coastguard Worker genProc = self.gen.genCmd 775*61046927SAndroid Build Coastguard Worker for type_elem in f.elem.findall('.//type'): 776*61046927SAndroid Build Coastguard Worker depname = type_elem.text 777*61046927SAndroid Build Coastguard Worker self.generateFeature(depname, 'type', self.typedict) 778*61046927SAndroid Build Coastguard Worker elif ftype == 'enum': 779*61046927SAndroid Build Coastguard Worker # Generate enum dependencies in 'alias' attribute 780*61046927SAndroid Build Coastguard Worker if alias: 781*61046927SAndroid Build Coastguard Worker self.generateFeature(alias, 'enum', self.enumdict) 782*61046927SAndroid Build Coastguard Worker genProc = self.gen.genEnum 783*61046927SAndroid Build Coastguard Worker 784*61046927SAndroid Build Coastguard Worker # Actually generate the type only if emitting declarations 785*61046927SAndroid Build Coastguard Worker if self.emitFeatures: 786*61046927SAndroid Build Coastguard Worker if genProc is None: 787*61046927SAndroid Build Coastguard Worker raise RuntimeError("genProc is None when we should be emitting") 788*61046927SAndroid Build Coastguard Worker genProc(f, fname, alias) 789*61046927SAndroid Build Coastguard Worker 790*61046927SAndroid Build Coastguard Worker if followupFeature: 791*61046927SAndroid Build Coastguard Worker self.generateFeature(followupFeature, "type", self.typedict) 792*61046927SAndroid Build Coastguard Worker 793*61046927SAndroid Build Coastguard Worker def generateRequiredInterface(self, interface): 794*61046927SAndroid Build Coastguard Worker """Generate all interfaces required by an API version or extension. 795*61046927SAndroid Build Coastguard Worker 796*61046927SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`""" 797*61046927SAndroid Build Coastguard Worker 798*61046927SAndroid Build Coastguard Worker # Loop over all features inside all <require> tags. 799*61046927SAndroid Build Coastguard Worker for features in interface.findall('require'): 800*61046927SAndroid Build Coastguard Worker for t in features.findall('type'): 801*61046927SAndroid Build Coastguard Worker self.generateFeature(t.get('name'), 'type', self.typedict, explicit=True) 802*61046927SAndroid Build Coastguard Worker for e in features.findall('enum'): 803*61046927SAndroid Build Coastguard Worker # If this is an enum extending an enumerated type, do not 804*61046927SAndroid Build Coastguard Worker # generate it - this has already been done in reg.parseTree, 805*61046927SAndroid Build Coastguard Worker # by copying this element into the enumerated type. 806*61046927SAndroid Build Coastguard Worker enumextends = e.get('extends') 807*61046927SAndroid Build Coastguard Worker if not enumextends: 808*61046927SAndroid Build Coastguard Worker self.generateFeature(e.get('name'), 'enum', self.enumdict, explicit=True) 809*61046927SAndroid Build Coastguard Worker for c in features.findall('command'): 810*61046927SAndroid Build Coastguard Worker self.generateFeature(c.get('name'), 'command', self.cmddict, explicit=True) 811*61046927SAndroid Build Coastguard Worker 812*61046927SAndroid Build Coastguard Worker def apiGen(self): 813*61046927SAndroid Build Coastguard Worker """Generate interface for specified versions using the current 814*61046927SAndroid Build Coastguard Worker generator and generator options""" 815*61046927SAndroid Build Coastguard Worker 816*61046927SAndroid Build Coastguard Worker # Could reset required/declared flags for all features here. 817*61046927SAndroid Build Coastguard Worker # This has been removed as never used. The initial motivation was 818*61046927SAndroid Build Coastguard Worker # the idea of calling apiGen() repeatedly for different targets, but 819*61046927SAndroid Build Coastguard Worker # this has never been done. The 20% or so build-time speedup that 820*61046927SAndroid Build Coastguard Worker # might result is not worth the effort to make it actually work. 821*61046927SAndroid Build Coastguard Worker # 822*61046927SAndroid Build Coastguard Worker # self.apiReset() 823*61046927SAndroid Build Coastguard Worker 824*61046927SAndroid Build Coastguard Worker # Compile regexps used to select versions & extensions 825*61046927SAndroid Build Coastguard Worker regVersions = re.compile(self.genOpts.versions) 826*61046927SAndroid Build Coastguard Worker regEmitVersions = re.compile(self.genOpts.emitversions) 827*61046927SAndroid Build Coastguard Worker regAddExtensions = re.compile(self.genOpts.addExtensions) 828*61046927SAndroid Build Coastguard Worker regEmitExtensions = re.compile(self.genOpts.emitExtensions) 829*61046927SAndroid Build Coastguard Worker 830*61046927SAndroid Build Coastguard Worker # Get all matching API feature names & add to list of FeatureInfo 831*61046927SAndroid Build Coastguard Worker # Note we used to select on feature version attributes, not names. 832*61046927SAndroid Build Coastguard Worker features = [] 833*61046927SAndroid Build Coastguard Worker apiMatch = False 834*61046927SAndroid Build Coastguard Worker for key in self.apidict: 835*61046927SAndroid Build Coastguard Worker fi = self.apidict[key] 836*61046927SAndroid Build Coastguard Worker api = fi.elem.get('api') 837*61046927SAndroid Build Coastguard Worker if apiNameMatch('vulkan', api): 838*61046927SAndroid Build Coastguard Worker apiMatch = True 839*61046927SAndroid Build Coastguard Worker if regVersions.match(fi.name): 840*61046927SAndroid Build Coastguard Worker # Matches API & version #s being generated. Mark for 841*61046927SAndroid Build Coastguard Worker # emission and add to the features[] list . 842*61046927SAndroid Build Coastguard Worker # @@ Could use 'declared' instead of 'emit'? 843*61046927SAndroid Build Coastguard Worker fi.emit = (regEmitVersions.match(fi.name) is not None) 844*61046927SAndroid Build Coastguard Worker features.append(fi) 845*61046927SAndroid Build Coastguard Worker 846*61046927SAndroid Build Coastguard Worker # Get all matching extensions, in order by their extension number, 847*61046927SAndroid Build Coastguard Worker # and add to the list of features. 848*61046927SAndroid Build Coastguard Worker # Start with extensions whose 'supported' attributes match the API 849*61046927SAndroid Build Coastguard Worker # being generated. Add extensions matching the pattern specified in 850*61046927SAndroid Build Coastguard Worker # regExtensions, then remove extensions matching the pattern 851*61046927SAndroid Build Coastguard Worker # specified in regRemoveExtensions 852*61046927SAndroid Build Coastguard Worker for (extName, ei) in sorted(self.extdict.items(), key=lambda x: x[1].number if x[1].number is not None else '0'): 853*61046927SAndroid Build Coastguard Worker extName = ei.name 854*61046927SAndroid Build Coastguard Worker include = False 855*61046927SAndroid Build Coastguard Worker 856*61046927SAndroid Build Coastguard Worker # Include extension if defaultExtensions is not None and is 857*61046927SAndroid Build Coastguard Worker # exactly matched by the 'supported' attribute. 858*61046927SAndroid Build Coastguard Worker if apiNameMatch('vulkan', ei.elem.get('supported')): 859*61046927SAndroid Build Coastguard Worker include = True 860*61046927SAndroid Build Coastguard Worker 861*61046927SAndroid Build Coastguard Worker # Include additional extensions if the extension name matches 862*61046927SAndroid Build Coastguard Worker # the regexp specified in the generator options. This allows 863*61046927SAndroid Build Coastguard Worker # forcing extensions into an interface even if they are not 864*61046927SAndroid Build Coastguard Worker # tagged appropriately in the registry. 865*61046927SAndroid Build Coastguard Worker # However, we still respect the 'supported' attribute. 866*61046927SAndroid Build Coastguard Worker if regAddExtensions.match(extName) is not None: 867*61046927SAndroid Build Coastguard Worker if not apiNameMatch('vulkan', ei.elem.get('supported')): 868*61046927SAndroid Build Coastguard Worker include = False 869*61046927SAndroid Build Coastguard Worker else: 870*61046927SAndroid Build Coastguard Worker include = True 871*61046927SAndroid Build Coastguard Worker # If the extension is to be included, add it to the 872*61046927SAndroid Build Coastguard Worker # extension features list. 873*61046927SAndroid Build Coastguard Worker if include: 874*61046927SAndroid Build Coastguard Worker ei.emit = (regEmitExtensions.match(extName) is not None) 875*61046927SAndroid Build Coastguard Worker features.append(ei) 876*61046927SAndroid Build Coastguard Worker 877*61046927SAndroid Build Coastguard Worker # Sort the features list, if a sort procedure is defined 878*61046927SAndroid Build Coastguard Worker if self.genOpts.sortProcedure: 879*61046927SAndroid Build Coastguard Worker self.genOpts.sortProcedure(features) 880*61046927SAndroid Build Coastguard Worker 881*61046927SAndroid Build Coastguard Worker # Passes 1+2: loop over requested API versions and extensions tagging 882*61046927SAndroid Build Coastguard Worker # types/commands/features as required (in an <require> block) or no 883*61046927SAndroid Build Coastguard Worker # longer required (in an <remove> block). <remove>s are processed 884*61046927SAndroid Build Coastguard Worker # after all <require>s, so removals win. 885*61046927SAndroid Build Coastguard Worker # If a profile other than 'None' is being generated, it must 886*61046927SAndroid Build Coastguard Worker # match the profile attribute (if any) of the <require> and 887*61046927SAndroid Build Coastguard Worker # <remove> tags. 888*61046927SAndroid Build Coastguard Worker for f in features: 889*61046927SAndroid Build Coastguard Worker self.fillFeatureDictionary(f.elem, f.name, 'vulkan') 890*61046927SAndroid Build Coastguard Worker self.requireFeatures(f.elem, f.name, 'vulkan') 891*61046927SAndroid Build Coastguard Worker 892*61046927SAndroid Build Coastguard Worker # @@May need to strip <spirvcapability> / <spirvextension> <enable> 893*61046927SAndroid Build Coastguard Worker # tags of these forms: 894*61046927SAndroid Build Coastguard Worker # <enable version="VK_API_VERSION_1_0"/> 895*61046927SAndroid Build Coastguard Worker # <enable struct="VkPhysicalDeviceFeatures" feature="geometryShader" requires="VK_VERSION_1_0"/> 896*61046927SAndroid Build Coastguard Worker # <enable extension="VK_KHR_shader_draw_parameters"/> 897*61046927SAndroid Build Coastguard Worker # <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/> 898*61046927SAndroid Build Coastguard Worker 899*61046927SAndroid Build Coastguard Worker # Pass 3: loop over specified API versions and extensions printing 900*61046927SAndroid Build Coastguard Worker # declarations for required things which have not already been 901*61046927SAndroid Build Coastguard Worker # generated. 902*61046927SAndroid Build Coastguard Worker self.gen.beginFile(self.genOpts) 903*61046927SAndroid Build Coastguard Worker for f in features: 904*61046927SAndroid Build Coastguard Worker emit = self.emitFeatures = f.emit 905*61046927SAndroid Build Coastguard Worker # Generate the interface (or just tag its elements as having been 906*61046927SAndroid Build Coastguard Worker # emitted, if they have not been). 907*61046927SAndroid Build Coastguard Worker self.gen.beginFeature(f.elem, emit) 908*61046927SAndroid Build Coastguard Worker self.generateRequiredInterface(f.elem) 909*61046927SAndroid Build Coastguard Worker self.gen.endFeature() 910*61046927SAndroid Build Coastguard Worker self.gen.endFile() 911