1*90277196SAndroid Build Coastguard Worker#!/usr/bin/env python3 -i 2*90277196SAndroid Build Coastguard Worker# 3*90277196SAndroid Build Coastguard Worker# Copyright 2013-2024 The Khronos Group Inc. 4*90277196SAndroid Build Coastguard Worker# 5*90277196SAndroid Build Coastguard Worker# SPDX-License-Identifier: Apache-2.0 6*90277196SAndroid Build Coastguard Worker 7*90277196SAndroid Build Coastguard Worker"""Types and classes for manipulating an API registry.""" 8*90277196SAndroid Build Coastguard Worker 9*90277196SAndroid Build Coastguard Workerimport copy 10*90277196SAndroid Build Coastguard Workerimport re 11*90277196SAndroid Build Coastguard Workerimport sys 12*90277196SAndroid Build Coastguard Workerimport xml.etree.ElementTree as etree 13*90277196SAndroid Build Coastguard Workerfrom collections import defaultdict, deque, namedtuple 14*90277196SAndroid Build Coastguard Worker 15*90277196SAndroid Build Coastguard Workerfrom generator import GeneratorOptions, OutputGenerator, noneStr, write 16*90277196SAndroid Build Coastguard Workerfrom apiconventions import APIConventions 17*90277196SAndroid Build Coastguard Worker 18*90277196SAndroid Build Coastguard Workerdef apiNameMatch(str, supported): 19*90277196SAndroid Build Coastguard Worker """Return whether a required api name matches a pattern specified for an 20*90277196SAndroid Build Coastguard Worker XML <feature> 'api' attribute or <extension> 'supported' attribute. 21*90277196SAndroid Build Coastguard Worker 22*90277196SAndroid Build Coastguard Worker - str - API name such as 'vulkan' or 'openxr'. May be None, in which 23*90277196SAndroid Build Coastguard Worker case it never matches (this should not happen). 24*90277196SAndroid Build Coastguard Worker - supported - comma-separated list of XML API names. May be None, in 25*90277196SAndroid Build Coastguard Worker which case str always matches (this is the usual case).""" 26*90277196SAndroid Build Coastguard Worker 27*90277196SAndroid Build Coastguard Worker if str is not None: 28*90277196SAndroid Build Coastguard Worker return supported is None or str in supported.split(',') 29*90277196SAndroid Build Coastguard Worker 30*90277196SAndroid Build Coastguard Worker # Fallthrough case - either str is None or the test failed 31*90277196SAndroid Build Coastguard Worker return False 32*90277196SAndroid Build Coastguard Worker 33*90277196SAndroid Build Coastguard Workerdef matchAPIProfile(api, profile, elem): 34*90277196SAndroid Build Coastguard Worker """Return whether an API and profile 35*90277196SAndroid Build Coastguard Worker being generated matches an element's profile 36*90277196SAndroid Build Coastguard Worker 37*90277196SAndroid Build Coastguard Worker - api - string naming the API to match 38*90277196SAndroid Build Coastguard Worker - profile - string naming the profile to match 39*90277196SAndroid Build Coastguard Worker - elem - Element which (may) have 'api' and 'profile' 40*90277196SAndroid Build Coastguard Worker attributes to match to. 41*90277196SAndroid Build Coastguard Worker 42*90277196SAndroid Build Coastguard Worker If a tag is not present in the Element, the corresponding API 43*90277196SAndroid Build Coastguard Worker or profile always matches. 44*90277196SAndroid Build Coastguard Worker 45*90277196SAndroid Build Coastguard Worker Otherwise, the tag must exactly match the API or profile. 46*90277196SAndroid Build Coastguard Worker 47*90277196SAndroid Build Coastguard Worker Thus, if 'profile' = core: 48*90277196SAndroid Build Coastguard Worker 49*90277196SAndroid Build Coastguard Worker - `<remove>` with no attribute will match 50*90277196SAndroid Build Coastguard Worker - `<remove profile="core">` will match 51*90277196SAndroid Build Coastguard Worker - `<remove profile="compatibility">` will not match 52*90277196SAndroid Build Coastguard Worker 53*90277196SAndroid Build Coastguard Worker Possible match conditions: 54*90277196SAndroid Build Coastguard Worker 55*90277196SAndroid Build Coastguard Worker ``` 56*90277196SAndroid Build Coastguard Worker Requested Element 57*90277196SAndroid Build Coastguard Worker Profile Profile 58*90277196SAndroid Build Coastguard Worker --------- -------- 59*90277196SAndroid Build Coastguard Worker None None Always matches 60*90277196SAndroid Build Coastguard Worker 'string' None Always matches 61*90277196SAndroid Build Coastguard Worker None 'string' Does not match. Cannot generate multiple APIs 62*90277196SAndroid Build Coastguard Worker or profiles, so if an API/profile constraint 63*90277196SAndroid Build Coastguard Worker is present, it must be asked for explicitly. 64*90277196SAndroid Build Coastguard Worker 'string' 'string' Strings must match 65*90277196SAndroid Build Coastguard Worker ``` 66*90277196SAndroid Build Coastguard Worker 67*90277196SAndroid Build Coastguard Worker ** In the future, we will allow regexes for the attributes, 68*90277196SAndroid Build Coastguard Worker not just strings, so that `api="^(gl|gles2)"` will match. Even 69*90277196SAndroid Build Coastguard Worker this is not really quite enough, we might prefer something 70*90277196SAndroid Build Coastguard Worker like `"gl(core)|gles1(common-lite)"`.""" 71*90277196SAndroid Build Coastguard Worker # Match 'api', if present 72*90277196SAndroid Build Coastguard Worker elem_api = elem.get('api') 73*90277196SAndroid Build Coastguard Worker if elem_api: 74*90277196SAndroid Build Coastguard Worker if api is None: 75*90277196SAndroid Build Coastguard Worker raise UserWarning("No API requested, but 'api' attribute is present with value '" 76*90277196SAndroid Build Coastguard Worker + elem_api + "'") 77*90277196SAndroid Build Coastguard Worker elif api != elem_api: 78*90277196SAndroid Build Coastguard Worker # Requested API does not match attribute 79*90277196SAndroid Build Coastguard Worker return False 80*90277196SAndroid Build Coastguard Worker elem_profile = elem.get('profile') 81*90277196SAndroid Build Coastguard Worker if elem_profile: 82*90277196SAndroid Build Coastguard Worker if profile is None: 83*90277196SAndroid Build Coastguard Worker raise UserWarning("No profile requested, but 'profile' attribute is present with value '" 84*90277196SAndroid Build Coastguard Worker + elem_profile + "'") 85*90277196SAndroid Build Coastguard Worker elif profile != elem_profile: 86*90277196SAndroid Build Coastguard Worker # Requested profile does not match attribute 87*90277196SAndroid Build Coastguard Worker return False 88*90277196SAndroid Build Coastguard Worker return True 89*90277196SAndroid Build Coastguard Worker 90*90277196SAndroid Build Coastguard Worker 91*90277196SAndroid Build Coastguard Workerdef mergeAPIs(tree, fromApiNames, toApiName): 92*90277196SAndroid Build Coastguard Worker """Merge multiple APIs using the precedence order specified in apiNames. 93*90277196SAndroid Build Coastguard Worker Also deletes <remove> elements. 94*90277196SAndroid Build Coastguard Worker 95*90277196SAndroid Build Coastguard Worker tree - Element at the root of the hierarchy to merge. 96*90277196SAndroid Build Coastguard Worker apiNames - list of strings of API names.""" 97*90277196SAndroid Build Coastguard Worker 98*90277196SAndroid Build Coastguard Worker stack = deque() 99*90277196SAndroid Build Coastguard Worker stack.append(tree) 100*90277196SAndroid Build Coastguard Worker 101*90277196SAndroid Build Coastguard Worker while len(stack) > 0: 102*90277196SAndroid Build Coastguard Worker parent = stack.pop() 103*90277196SAndroid Build Coastguard Worker 104*90277196SAndroid Build Coastguard Worker for child in parent.findall('*'): 105*90277196SAndroid Build Coastguard Worker if child.tag == 'remove': 106*90277196SAndroid Build Coastguard Worker # Remove <remove> elements 107*90277196SAndroid Build Coastguard Worker parent.remove(child) 108*90277196SAndroid Build Coastguard Worker else: 109*90277196SAndroid Build Coastguard Worker stack.append(child) 110*90277196SAndroid Build Coastguard Worker 111*90277196SAndroid Build Coastguard Worker supportedList = child.get('supported') 112*90277196SAndroid Build Coastguard Worker if supportedList: 113*90277196SAndroid Build Coastguard Worker supportedList = supportedList.split(',') 114*90277196SAndroid Build Coastguard Worker for apiName in [toApiName] + fromApiNames: 115*90277196SAndroid Build Coastguard Worker if apiName in supportedList: 116*90277196SAndroid Build Coastguard Worker child.set('supported', toApiName) 117*90277196SAndroid Build Coastguard Worker 118*90277196SAndroid Build Coastguard Worker if child.get('api'): 119*90277196SAndroid Build Coastguard Worker definitionName = None 120*90277196SAndroid Build Coastguard Worker definitionVariants = [] 121*90277196SAndroid Build Coastguard Worker 122*90277196SAndroid Build Coastguard Worker # Keep only one definition with the same name if there are multiple definitions 123*90277196SAndroid Build Coastguard Worker if child.tag in ['type']: 124*90277196SAndroid Build Coastguard Worker if child.get('name') is not None: 125*90277196SAndroid Build Coastguard Worker definitionName = child.get('name') 126*90277196SAndroid Build Coastguard Worker definitionVariants = parent.findall(f"{child.tag}[@name='{definitionName}']") 127*90277196SAndroid Build Coastguard Worker else: 128*90277196SAndroid Build Coastguard Worker definitionName = child.find('name').text 129*90277196SAndroid Build Coastguard Worker definitionVariants = parent.findall(f"{child.tag}/name[.='{definitionName}']/..") 130*90277196SAndroid Build Coastguard Worker elif child.tag in ['member', 'param']: 131*90277196SAndroid Build Coastguard Worker definitionName = child.find('name').text 132*90277196SAndroid Build Coastguard Worker definitionVariants = parent.findall(f"{child.tag}/name[.='{definitionName}']/..") 133*90277196SAndroid Build Coastguard Worker elif child.tag in ['enum', 'feature']: 134*90277196SAndroid Build Coastguard Worker definitionName = child.get('name') 135*90277196SAndroid Build Coastguard Worker definitionVariants = parent.findall(f"{child.tag}[@name='{definitionName}']") 136*90277196SAndroid Build Coastguard Worker elif child.tag in ['require']: 137*90277196SAndroid Build Coastguard Worker definitionName = child.get('feature') 138*90277196SAndroid Build Coastguard Worker definitionVariants = parent.findall(f"{child.tag}[@feature='{definitionName}']") 139*90277196SAndroid Build Coastguard Worker elif child.tag in ['command']: 140*90277196SAndroid Build Coastguard Worker definitionName = child.find('proto/name').text 141*90277196SAndroid Build Coastguard Worker definitionVariants = parent.findall(f"{child.tag}/proto/name[.='{definitionName}']/../..") 142*90277196SAndroid Build Coastguard Worker 143*90277196SAndroid Build Coastguard Worker if definitionName: 144*90277196SAndroid Build Coastguard Worker bestMatchApi = None 145*90277196SAndroid Build Coastguard Worker requires = None 146*90277196SAndroid Build Coastguard Worker for apiName in [toApiName] + fromApiNames: 147*90277196SAndroid Build Coastguard Worker for variant in definitionVariants: 148*90277196SAndroid Build Coastguard Worker # Keep any requires attributes from the target API 149*90277196SAndroid Build Coastguard Worker if variant.get('requires') and variant.get('api') == apiName: 150*90277196SAndroid Build Coastguard Worker requires = variant.get('requires') 151*90277196SAndroid Build Coastguard Worker # Find the best matching definition 152*90277196SAndroid Build Coastguard Worker if apiName in variant.get('api').split(',') and bestMatchApi is None: 153*90277196SAndroid Build Coastguard Worker bestMatchApi = variant.get('api') 154*90277196SAndroid Build Coastguard Worker 155*90277196SAndroid Build Coastguard Worker if bestMatchApi: 156*90277196SAndroid Build Coastguard Worker for variant in definitionVariants: 157*90277196SAndroid Build Coastguard Worker if variant.get('api') != bestMatchApi: 158*90277196SAndroid Build Coastguard Worker # Only keep best matching definition 159*90277196SAndroid Build Coastguard Worker parent.remove(variant) 160*90277196SAndroid Build Coastguard Worker else: 161*90277196SAndroid Build Coastguard Worker # Add requires attribute from the target API if it is not overridden 162*90277196SAndroid Build Coastguard Worker if requires is not None and variant.get('requires') is None: 163*90277196SAndroid Build Coastguard Worker variant.set('requires', requires) 164*90277196SAndroid Build Coastguard Worker variant.set('api', toApiName) 165*90277196SAndroid Build Coastguard Worker 166*90277196SAndroid Build Coastguard Worker 167*90277196SAndroid Build Coastguard Workerdef stripNonmatchingAPIs(tree, apiName, actuallyDelete = True): 168*90277196SAndroid Build Coastguard Worker """Remove tree Elements with 'api' attributes matching apiName. 169*90277196SAndroid Build Coastguard Worker 170*90277196SAndroid Build Coastguard Worker tree - Element at the root of the hierarchy to strip. Only its 171*90277196SAndroid Build Coastguard Worker children can actually be removed, not the tree itself. 172*90277196SAndroid Build Coastguard Worker apiName - string which much match a command-separated component of 173*90277196SAndroid Build Coastguard Worker the 'api' attribute. 174*90277196SAndroid Build Coastguard Worker actuallyDelete - only delete matching elements if True.""" 175*90277196SAndroid Build Coastguard Worker 176*90277196SAndroid Build Coastguard Worker stack = deque() 177*90277196SAndroid Build Coastguard Worker stack.append(tree) 178*90277196SAndroid Build Coastguard Worker 179*90277196SAndroid Build Coastguard Worker while len(stack) > 0: 180*90277196SAndroid Build Coastguard Worker parent = stack.pop() 181*90277196SAndroid Build Coastguard Worker 182*90277196SAndroid Build Coastguard Worker for child in parent.findall('*'): 183*90277196SAndroid Build Coastguard Worker api = child.get('api') 184*90277196SAndroid Build Coastguard Worker 185*90277196SAndroid Build Coastguard Worker if apiNameMatch(apiName, api): 186*90277196SAndroid Build Coastguard Worker # Add child to the queue 187*90277196SAndroid Build Coastguard Worker stack.append(child) 188*90277196SAndroid Build Coastguard Worker elif not apiNameMatch(apiName, api): 189*90277196SAndroid Build Coastguard Worker # Child does not match requested api. Remove it. 190*90277196SAndroid Build Coastguard Worker if actuallyDelete: 191*90277196SAndroid Build Coastguard Worker parent.remove(child) 192*90277196SAndroid Build Coastguard Worker 193*90277196SAndroid Build Coastguard Worker 194*90277196SAndroid Build Coastguard Workerclass BaseInfo: 195*90277196SAndroid Build Coastguard Worker """Base class for information about a registry feature 196*90277196SAndroid Build Coastguard Worker (type/group/enum/command/API/extension). 197*90277196SAndroid Build Coastguard Worker 198*90277196SAndroid Build Coastguard Worker Represents the state of a registry feature, used during API generation. 199*90277196SAndroid Build Coastguard Worker """ 200*90277196SAndroid Build Coastguard Worker 201*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 202*90277196SAndroid Build Coastguard Worker self.required = False 203*90277196SAndroid Build Coastguard Worker """should this feature be defined during header generation 204*90277196SAndroid Build Coastguard Worker (has it been removed by a profile or version)?""" 205*90277196SAndroid Build Coastguard Worker 206*90277196SAndroid Build Coastguard Worker self.declared = False 207*90277196SAndroid Build Coastguard Worker "has this feature been defined already?" 208*90277196SAndroid Build Coastguard Worker 209*90277196SAndroid Build Coastguard Worker self.elem = elem 210*90277196SAndroid Build Coastguard Worker "etree Element for this feature" 211*90277196SAndroid Build Coastguard Worker 212*90277196SAndroid Build Coastguard Worker def resetState(self): 213*90277196SAndroid Build Coastguard Worker """Reset required/declared to initial values. Used 214*90277196SAndroid Build Coastguard Worker prior to generating a new API interface.""" 215*90277196SAndroid Build Coastguard Worker self.required = False 216*90277196SAndroid Build Coastguard Worker self.declared = False 217*90277196SAndroid Build Coastguard Worker 218*90277196SAndroid Build Coastguard Worker def compareKeys(self, info, key, required = False): 219*90277196SAndroid Build Coastguard Worker """Return True if self.elem and info.elem have the same attribute 220*90277196SAndroid Build Coastguard Worker value for key. 221*90277196SAndroid Build Coastguard Worker If 'required' is not True, also returns True if neither element 222*90277196SAndroid Build Coastguard Worker has an attribute value for key.""" 223*90277196SAndroid Build Coastguard Worker 224*90277196SAndroid Build Coastguard Worker if required and key not in self.elem.keys(): 225*90277196SAndroid Build Coastguard Worker return False 226*90277196SAndroid Build Coastguard Worker return self.elem.get(key) == info.elem.get(key) 227*90277196SAndroid Build Coastguard Worker 228*90277196SAndroid Build Coastguard Worker def compareElem(self, info, infoName): 229*90277196SAndroid Build Coastguard Worker """Return True if self.elem and info.elem have the same definition. 230*90277196SAndroid Build Coastguard Worker info - the other object 231*90277196SAndroid Build Coastguard Worker infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 232*90277196SAndroid Build Coastguard Worker 'extension'""" 233*90277196SAndroid Build Coastguard Worker 234*90277196SAndroid Build Coastguard Worker if infoName == 'enum': 235*90277196SAndroid Build Coastguard Worker if self.compareKeys(info, 'extends'): 236*90277196SAndroid Build Coastguard Worker # Either both extend the same type, or no type 237*90277196SAndroid Build Coastguard Worker if (self.compareKeys(info, 'value', required = True) or 238*90277196SAndroid Build Coastguard Worker self.compareKeys(info, 'bitpos', required = True)): 239*90277196SAndroid Build Coastguard Worker # If both specify the same value or bit position, 240*90277196SAndroid Build Coastguard Worker # they are equal 241*90277196SAndroid Build Coastguard Worker return True 242*90277196SAndroid Build Coastguard Worker elif (self.compareKeys(info, 'extnumber') and 243*90277196SAndroid Build Coastguard Worker self.compareKeys(info, 'offset') and 244*90277196SAndroid Build Coastguard Worker self.compareKeys(info, 'dir')): 245*90277196SAndroid Build Coastguard Worker # If both specify the same relative offset, they are equal 246*90277196SAndroid Build Coastguard Worker return True 247*90277196SAndroid Build Coastguard Worker elif (self.compareKeys(info, 'alias')): 248*90277196SAndroid Build Coastguard Worker # If both are aliases of the same value 249*90277196SAndroid Build Coastguard Worker return True 250*90277196SAndroid Build Coastguard Worker else: 251*90277196SAndroid Build Coastguard Worker return False 252*90277196SAndroid Build Coastguard Worker else: 253*90277196SAndroid Build Coastguard Worker # The same enum cannot extend two different types 254*90277196SAndroid Build Coastguard Worker return False 255*90277196SAndroid Build Coastguard Worker else: 256*90277196SAndroid Build Coastguard Worker # Non-<enum>s should never be redefined 257*90277196SAndroid Build Coastguard Worker return False 258*90277196SAndroid Build Coastguard Worker 259*90277196SAndroid Build Coastguard Worker 260*90277196SAndroid Build Coastguard Workerclass TypeInfo(BaseInfo): 261*90277196SAndroid Build Coastguard Worker """Registry information about a type. No additional state 262*90277196SAndroid Build Coastguard Worker beyond BaseInfo is required.""" 263*90277196SAndroid Build Coastguard Worker 264*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 265*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 266*90277196SAndroid Build Coastguard Worker self.additionalValidity = [] 267*90277196SAndroid Build Coastguard Worker self.removedValidity = [] 268*90277196SAndroid Build Coastguard Worker 269*90277196SAndroid Build Coastguard Worker def getMembers(self): 270*90277196SAndroid Build Coastguard Worker """Get a collection of all member elements for this type, if any.""" 271*90277196SAndroid Build Coastguard Worker return self.elem.findall('member') 272*90277196SAndroid Build Coastguard Worker 273*90277196SAndroid Build Coastguard Worker def resetState(self): 274*90277196SAndroid Build Coastguard Worker BaseInfo.resetState(self) 275*90277196SAndroid Build Coastguard Worker self.additionalValidity = [] 276*90277196SAndroid Build Coastguard Worker self.removedValidity = [] 277*90277196SAndroid Build Coastguard Worker 278*90277196SAndroid Build Coastguard Worker 279*90277196SAndroid Build Coastguard Workerclass GroupInfo(BaseInfo): 280*90277196SAndroid Build Coastguard Worker """Registry information about a group of related enums 281*90277196SAndroid Build Coastguard Worker in an <enums> block, generally corresponding to a C "enum" type.""" 282*90277196SAndroid Build Coastguard Worker 283*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 284*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 285*90277196SAndroid Build Coastguard Worker 286*90277196SAndroid Build Coastguard Worker 287*90277196SAndroid Build Coastguard Workerclass EnumInfo(BaseInfo): 288*90277196SAndroid Build Coastguard Worker """Registry information about an enum""" 289*90277196SAndroid Build Coastguard Worker 290*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 291*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 292*90277196SAndroid Build Coastguard Worker self.type = elem.get('type') 293*90277196SAndroid Build Coastguard Worker """numeric type of the value of the <enum> tag 294*90277196SAndroid Build Coastguard Worker ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 )""" 295*90277196SAndroid Build Coastguard Worker if self.type is None: 296*90277196SAndroid Build Coastguard Worker self.type = '' 297*90277196SAndroid Build Coastguard Worker 298*90277196SAndroid Build Coastguard Worker 299*90277196SAndroid Build Coastguard Workerclass CmdInfo(BaseInfo): 300*90277196SAndroid Build Coastguard Worker """Registry information about a command""" 301*90277196SAndroid Build Coastguard Worker 302*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 303*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 304*90277196SAndroid Build Coastguard Worker self.additionalValidity = [] 305*90277196SAndroid Build Coastguard Worker self.removedValidity = [] 306*90277196SAndroid Build Coastguard Worker 307*90277196SAndroid Build Coastguard Worker def getParams(self): 308*90277196SAndroid Build Coastguard Worker """Get a collection of all param elements for this command, if any.""" 309*90277196SAndroid Build Coastguard Worker return self.elem.findall('param') 310*90277196SAndroid Build Coastguard Worker 311*90277196SAndroid Build Coastguard Worker def resetState(self): 312*90277196SAndroid Build Coastguard Worker BaseInfo.resetState(self) 313*90277196SAndroid Build Coastguard Worker self.additionalValidity = [] 314*90277196SAndroid Build Coastguard Worker self.removedValidity = [] 315*90277196SAndroid Build Coastguard Worker 316*90277196SAndroid Build Coastguard Worker 317*90277196SAndroid Build Coastguard Workerclass FeatureInfo(BaseInfo): 318*90277196SAndroid Build Coastguard Worker """Registry information about an API <feature> 319*90277196SAndroid Build Coastguard Worker or <extension>.""" 320*90277196SAndroid Build Coastguard Worker 321*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 322*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 323*90277196SAndroid Build Coastguard Worker self.name = elem.get('name') 324*90277196SAndroid Build Coastguard Worker "feature name string (e.g. 'VK_KHR_surface')" 325*90277196SAndroid Build Coastguard Worker 326*90277196SAndroid Build Coastguard Worker self.emit = False 327*90277196SAndroid Build Coastguard Worker "has this feature been defined already?" 328*90277196SAndroid Build Coastguard Worker 329*90277196SAndroid Build Coastguard Worker self.sortorder = int(elem.get('sortorder', 0)) 330*90277196SAndroid Build Coastguard Worker """explicit numeric sort key within feature and extension groups. 331*90277196SAndroid Build Coastguard Worker Defaults to 0.""" 332*90277196SAndroid Build Coastguard Worker 333*90277196SAndroid Build Coastguard Worker # Determine element category (vendor). Only works 334*90277196SAndroid Build Coastguard Worker # for <extension> elements. 335*90277196SAndroid Build Coastguard Worker if elem.tag == 'feature': 336*90277196SAndroid Build Coastguard Worker # Element category (vendor) is meaningless for <feature> 337*90277196SAndroid Build Coastguard Worker self.category = 'VERSION' 338*90277196SAndroid Build Coastguard Worker """category, e.g. VERSION or khr/vendor tag""" 339*90277196SAndroid Build Coastguard Worker 340*90277196SAndroid Build Coastguard Worker self.version = elem.get('name') 341*90277196SAndroid Build Coastguard Worker """feature name string""" 342*90277196SAndroid Build Coastguard Worker 343*90277196SAndroid Build Coastguard Worker self.versionNumber = elem.get('number') 344*90277196SAndroid Build Coastguard Worker """versionNumber - API version number, taken from the 'number' 345*90277196SAndroid Build Coastguard Worker attribute of <feature>. Extensions do not have API version 346*90277196SAndroid Build Coastguard Worker numbers and are assigned number 0.""" 347*90277196SAndroid Build Coastguard Worker 348*90277196SAndroid Build Coastguard Worker self.number = 0 349*90277196SAndroid Build Coastguard Worker self.supported = None 350*90277196SAndroid Build Coastguard Worker else: 351*90277196SAndroid Build Coastguard Worker # Extract vendor portion of <APIprefix>_<vendor>_<name> 352*90277196SAndroid Build Coastguard Worker self.category = self.name.split('_', 2)[1] 353*90277196SAndroid Build Coastguard Worker self.version = "0" 354*90277196SAndroid Build Coastguard Worker self.versionNumber = "0" 355*90277196SAndroid Build Coastguard Worker 356*90277196SAndroid Build Coastguard Worker self.number = int(elem.get('number','0')) 357*90277196SAndroid Build Coastguard Worker """extension number, used for ordering and for assigning 358*90277196SAndroid Build Coastguard Worker enumerant offsets. <feature> features do not have extension 359*90277196SAndroid Build Coastguard Worker numbers and are assigned number 0, as are extensions without 360*90277196SAndroid Build Coastguard Worker numbers, so sorting works.""" 361*90277196SAndroid Build Coastguard Worker 362*90277196SAndroid Build Coastguard Worker self.supported = elem.get('supported', 'disabled') 363*90277196SAndroid Build Coastguard Worker 364*90277196SAndroid Build Coastguard Workerclass SpirvInfo(BaseInfo): 365*90277196SAndroid Build Coastguard Worker """Registry information about an API <spirvextensions> 366*90277196SAndroid Build Coastguard Worker or <spirvcapability>.""" 367*90277196SAndroid Build Coastguard Worker 368*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 369*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 370*90277196SAndroid Build Coastguard Worker 371*90277196SAndroid Build Coastguard Workerclass FormatInfo(BaseInfo): 372*90277196SAndroid Build Coastguard Worker """Registry information about an API <format>.""" 373*90277196SAndroid Build Coastguard Worker 374*90277196SAndroid Build Coastguard Worker def __init__(self, elem, condition): 375*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 376*90277196SAndroid Build Coastguard Worker # Need to save the condition here when it is known 377*90277196SAndroid Build Coastguard Worker self.condition = condition 378*90277196SAndroid Build Coastguard Worker 379*90277196SAndroid Build Coastguard Workerclass SyncStageInfo(BaseInfo): 380*90277196SAndroid Build Coastguard Worker """Registry information about <syncstage>.""" 381*90277196SAndroid Build Coastguard Worker 382*90277196SAndroid Build Coastguard Worker def __init__(self, elem, condition): 383*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 384*90277196SAndroid Build Coastguard Worker # Need to save the condition here when it is known 385*90277196SAndroid Build Coastguard Worker self.condition = condition 386*90277196SAndroid Build Coastguard Worker 387*90277196SAndroid Build Coastguard Workerclass SyncAccessInfo(BaseInfo): 388*90277196SAndroid Build Coastguard Worker """Registry information about <syncaccess>.""" 389*90277196SAndroid Build Coastguard Worker 390*90277196SAndroid Build Coastguard Worker def __init__(self, elem, condition): 391*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 392*90277196SAndroid Build Coastguard Worker # Need to save the condition here when it is known 393*90277196SAndroid Build Coastguard Worker self.condition = condition 394*90277196SAndroid Build Coastguard Worker 395*90277196SAndroid Build Coastguard Workerclass SyncPipelineInfo(BaseInfo): 396*90277196SAndroid Build Coastguard Worker """Registry information about <syncpipeline>.""" 397*90277196SAndroid Build Coastguard Worker 398*90277196SAndroid Build Coastguard Worker def __init__(self, elem): 399*90277196SAndroid Build Coastguard Worker BaseInfo.__init__(self, elem) 400*90277196SAndroid Build Coastguard Worker 401*90277196SAndroid Build Coastguard Workerclass Registry: 402*90277196SAndroid Build Coastguard Worker """Object representing an API registry, loaded from an XML file.""" 403*90277196SAndroid Build Coastguard Worker 404*90277196SAndroid Build Coastguard Worker def __init__(self, gen=None, genOpts=None): 405*90277196SAndroid Build Coastguard Worker if gen is None: 406*90277196SAndroid Build Coastguard Worker # If not specified, give a default object so messaging will work 407*90277196SAndroid Build Coastguard Worker self.gen = OutputGenerator() 408*90277196SAndroid Build Coastguard Worker else: 409*90277196SAndroid Build Coastguard Worker self.gen = gen 410*90277196SAndroid Build Coastguard Worker "Output generator used to write headers / messages" 411*90277196SAndroid Build Coastguard Worker 412*90277196SAndroid Build Coastguard Worker if genOpts is None: 413*90277196SAndroid Build Coastguard Worker # If no generator is provided, we may still need the XML API name 414*90277196SAndroid Build Coastguard Worker # (for example, in genRef.py). 415*90277196SAndroid Build Coastguard Worker self.genOpts = GeneratorOptions(apiname = APIConventions().xml_api_name) 416*90277196SAndroid Build Coastguard Worker else: 417*90277196SAndroid Build Coastguard Worker self.genOpts = genOpts 418*90277196SAndroid Build Coastguard Worker "Options controlling features to write and how to format them" 419*90277196SAndroid Build Coastguard Worker 420*90277196SAndroid Build Coastguard Worker self.gen.registry = self 421*90277196SAndroid Build Coastguard Worker self.gen.genOpts = self.genOpts 422*90277196SAndroid Build Coastguard Worker self.gen.genOpts.registry = self 423*90277196SAndroid Build Coastguard Worker 424*90277196SAndroid Build Coastguard Worker self.tree = None 425*90277196SAndroid Build Coastguard Worker "ElementTree containing the root `<registry>`" 426*90277196SAndroid Build Coastguard Worker 427*90277196SAndroid Build Coastguard Worker self.typedict = {} 428*90277196SAndroid Build Coastguard Worker "dictionary of TypeInfo objects keyed by type name" 429*90277196SAndroid Build Coastguard Worker 430*90277196SAndroid Build Coastguard Worker self.groupdict = {} 431*90277196SAndroid Build Coastguard Worker "dictionary of GroupInfo objects keyed by group name" 432*90277196SAndroid Build Coastguard Worker 433*90277196SAndroid Build Coastguard Worker self.enumdict = {} 434*90277196SAndroid Build Coastguard Worker "dictionary of EnumInfo objects keyed by enum name" 435*90277196SAndroid Build Coastguard Worker 436*90277196SAndroid Build Coastguard Worker self.cmddict = {} 437*90277196SAndroid Build Coastguard Worker "dictionary of CmdInfo objects keyed by command name" 438*90277196SAndroid Build Coastguard Worker 439*90277196SAndroid Build Coastguard Worker self.aliasdict = {} 440*90277196SAndroid Build Coastguard Worker "dictionary of type and command names mapped to their alias, such as VkFooKHR -> VkFoo" 441*90277196SAndroid Build Coastguard Worker 442*90277196SAndroid Build Coastguard Worker self.enumvaluedict = {} 443*90277196SAndroid Build Coastguard Worker "dictionary of enum values mapped to their type, such as VK_FOO_VALUE -> VkFoo" 444*90277196SAndroid Build Coastguard Worker 445*90277196SAndroid Build Coastguard Worker self.apidict = {} 446*90277196SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<feature>` elements keyed by API name" 447*90277196SAndroid Build Coastguard Worker 448*90277196SAndroid Build Coastguard Worker self.extensions = [] 449*90277196SAndroid Build Coastguard Worker "list of `<extension>` Elements" 450*90277196SAndroid Build Coastguard Worker 451*90277196SAndroid Build Coastguard Worker self.extdict = {} 452*90277196SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<extension>` elements keyed by extension name" 453*90277196SAndroid Build Coastguard Worker 454*90277196SAndroid Build Coastguard Worker self.spirvextdict = {} 455*90277196SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<spirvextension>` elements keyed by spirv extension name" 456*90277196SAndroid Build Coastguard Worker 457*90277196SAndroid Build Coastguard Worker self.spirvcapdict = {} 458*90277196SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<spirvcapability>` elements keyed by spirv capability name" 459*90277196SAndroid Build Coastguard Worker 460*90277196SAndroid Build Coastguard Worker self.formatsdict = {} 461*90277196SAndroid Build Coastguard Worker "dictionary of FeatureInfo objects for `<format>` elements keyed by VkFormat name" 462*90277196SAndroid Build Coastguard Worker 463*90277196SAndroid Build Coastguard Worker self.syncstagedict = {} 464*90277196SAndroid Build Coastguard Worker "dictionary of Sync*Info objects for `<syncstage>` elements keyed by VkPipelineStageFlagBits2 name" 465*90277196SAndroid Build Coastguard Worker 466*90277196SAndroid Build Coastguard Worker self.syncaccessdict = {} 467*90277196SAndroid Build Coastguard Worker "dictionary of Sync*Info objects for `<syncaccess>` elements keyed by VkAccessFlagBits2 name" 468*90277196SAndroid Build Coastguard Worker 469*90277196SAndroid Build Coastguard Worker self.syncpipelinedict = {} 470*90277196SAndroid Build Coastguard Worker "dictionary of Sync*Info objects for `<syncpipeline>` elements keyed by pipeline type name" 471*90277196SAndroid Build Coastguard Worker 472*90277196SAndroid Build Coastguard Worker self.emitFeatures = False 473*90277196SAndroid Build Coastguard Worker """True to actually emit features for a version / extension, 474*90277196SAndroid Build Coastguard Worker or False to just treat them as emitted""" 475*90277196SAndroid Build Coastguard Worker 476*90277196SAndroid Build Coastguard Worker self.breakPat = None 477*90277196SAndroid Build Coastguard Worker "regexp pattern to break on when generating names" 478*90277196SAndroid Build Coastguard Worker # self.breakPat = re.compile('VkFenceImportFlagBits.*') 479*90277196SAndroid Build Coastguard Worker 480*90277196SAndroid Build Coastguard Worker self.requiredextensions = [] # Hack - can remove it after validity generator goes away 481*90277196SAndroid Build Coastguard Worker 482*90277196SAndroid Build Coastguard Worker # ** Global types for automatic source generation ** 483*90277196SAndroid Build Coastguard Worker # Length Member data 484*90277196SAndroid Build Coastguard Worker self.commandextensiontuple = namedtuple('commandextensiontuple', 485*90277196SAndroid Build Coastguard Worker ['command', # The name of the command being modified 486*90277196SAndroid Build Coastguard Worker 'value', # The value to append to the command 487*90277196SAndroid Build Coastguard Worker 'extension']) # The name of the extension that added it 488*90277196SAndroid Build Coastguard Worker self.validextensionstructs = defaultdict(list) 489*90277196SAndroid Build Coastguard Worker self.commandextensionsuccesses = [] 490*90277196SAndroid Build Coastguard Worker self.commandextensionerrors = [] 491*90277196SAndroid Build Coastguard Worker 492*90277196SAndroid Build Coastguard Worker self.filename = None 493*90277196SAndroid Build Coastguard Worker 494*90277196SAndroid Build Coastguard Worker def loadElementTree(self, tree): 495*90277196SAndroid Build Coastguard Worker """Load ElementTree into a Registry object and parse it.""" 496*90277196SAndroid Build Coastguard Worker self.tree = tree 497*90277196SAndroid Build Coastguard Worker self.parseTree() 498*90277196SAndroid Build Coastguard Worker 499*90277196SAndroid Build Coastguard Worker def loadFile(self, file): 500*90277196SAndroid Build Coastguard Worker """Load an API registry XML file into a Registry object and parse it""" 501*90277196SAndroid Build Coastguard Worker self.filename = file 502*90277196SAndroid Build Coastguard Worker self.tree = etree.parse(file) 503*90277196SAndroid Build Coastguard Worker self.parseTree() 504*90277196SAndroid Build Coastguard Worker 505*90277196SAndroid Build Coastguard Worker def setGenerator(self, gen): 506*90277196SAndroid Build Coastguard Worker """Specify output generator object. 507*90277196SAndroid Build Coastguard Worker 508*90277196SAndroid Build Coastguard Worker `None` restores the default generator.""" 509*90277196SAndroid Build Coastguard Worker self.gen = gen 510*90277196SAndroid Build Coastguard Worker self.gen.setRegistry(self) 511*90277196SAndroid Build Coastguard Worker 512*90277196SAndroid Build Coastguard Worker def addElementInfo(self, elem, info, infoName, dictionary): 513*90277196SAndroid Build Coastguard Worker """Add information about an element to the corresponding dictionary. 514*90277196SAndroid Build Coastguard Worker 515*90277196SAndroid Build Coastguard Worker Intended for internal use only. 516*90277196SAndroid Build Coastguard Worker 517*90277196SAndroid Build Coastguard Worker - elem - `<type>`/`<enums>`/`<enum>`/`<command>`/`<feature>`/`<extension>`/`<spirvextension>`/`<spirvcapability>`/`<format>`/`<syncstage>`/`<syncaccess>`/`<syncpipeline>` Element 518*90277196SAndroid Build Coastguard Worker - info - corresponding {Type|Group|Enum|Cmd|Feature|Spirv|Format|SyncStage|SyncAccess|SyncPipeline}Info object 519*90277196SAndroid Build Coastguard Worker - infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' / 'spirvextension' / 'spirvcapability' / 'format' / 'syncstage' / 'syncaccess' / 'syncpipeline' 520*90277196SAndroid Build Coastguard Worker - dictionary - self.{type|group|enum|cmd|api|ext|format|spirvext|spirvcap|sync}dict 521*90277196SAndroid Build Coastguard Worker 522*90277196SAndroid Build Coastguard Worker The dictionary key is the element 'name' attribute.""" 523*90277196SAndroid Build Coastguard Worker 524*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Adding ElementInfo.required =', 525*90277196SAndroid Build Coastguard Worker # info.required, 'name =', elem.get('name')) 526*90277196SAndroid Build Coastguard Worker key = elem.get('name') 527*90277196SAndroid Build Coastguard Worker if key in dictionary: 528*90277196SAndroid Build Coastguard Worker if not dictionary[key].compareElem(info, infoName): 529*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'Attempt to redefine', key, 530*90277196SAndroid Build Coastguard Worker '(this should not happen)') 531*90277196SAndroid Build Coastguard Worker else: 532*90277196SAndroid Build Coastguard Worker dictionary[key] = info 533*90277196SAndroid Build Coastguard Worker 534*90277196SAndroid Build Coastguard Worker def lookupElementInfo(self, fname, dictionary): 535*90277196SAndroid Build Coastguard Worker """Find a {Type|Enum|Cmd}Info object by name. 536*90277196SAndroid Build Coastguard Worker 537*90277196SAndroid Build Coastguard Worker Intended for internal use only. 538*90277196SAndroid Build Coastguard Worker 539*90277196SAndroid Build Coastguard Worker If an object qualified by API name exists, use that. 540*90277196SAndroid Build Coastguard Worker 541*90277196SAndroid Build Coastguard Worker - fname - name of type / enum / command 542*90277196SAndroid Build Coastguard Worker - dictionary - self.{type|enum|cmd}dict""" 543*90277196SAndroid Build Coastguard Worker key = (fname, self.genOpts.apiname) 544*90277196SAndroid Build Coastguard Worker if key in dictionary: 545*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Found API-specific element for feature', fname) 546*90277196SAndroid Build Coastguard Worker return dictionary[key] 547*90277196SAndroid Build Coastguard Worker if fname in dictionary: 548*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Found generic element for feature', fname) 549*90277196SAndroid Build Coastguard Worker return dictionary[fname] 550*90277196SAndroid Build Coastguard Worker 551*90277196SAndroid Build Coastguard Worker return None 552*90277196SAndroid Build Coastguard Worker 553*90277196SAndroid Build Coastguard Worker def breakOnName(self, regexp): 554*90277196SAndroid Build Coastguard Worker """Specify a feature name regexp to break on when generating features.""" 555*90277196SAndroid Build Coastguard Worker self.breakPat = re.compile(regexp) 556*90277196SAndroid Build Coastguard Worker 557*90277196SAndroid Build Coastguard Worker def addEnumValue(self, enum, type_name): 558*90277196SAndroid Build Coastguard Worker """Track aliasing and map back from enum values to their type""" 559*90277196SAndroid Build Coastguard Worker # Record alias, if any 560*90277196SAndroid Build Coastguard Worker value = enum.get('name') 561*90277196SAndroid Build Coastguard Worker alias = enum.get('alias') 562*90277196SAndroid Build Coastguard Worker if alias: 563*90277196SAndroid Build Coastguard Worker self.aliasdict[value] = alias 564*90277196SAndroid Build Coastguard Worker # Map the value back to the type 565*90277196SAndroid Build Coastguard Worker if type_name in self.aliasdict: 566*90277196SAndroid Build Coastguard Worker type_name = self.aliasdict[type_name] 567*90277196SAndroid Build Coastguard Worker if value in self.enumvaluedict: 568*90277196SAndroid Build Coastguard Worker # Some times the same enum is defined by multiple extensions 569*90277196SAndroid Build Coastguard Worker assert(type_name == self.enumvaluedict[value]) 570*90277196SAndroid Build Coastguard Worker else: 571*90277196SAndroid Build Coastguard Worker self.enumvaluedict[value] = type_name 572*90277196SAndroid Build Coastguard Worker 573*90277196SAndroid Build Coastguard Worker def parseTree(self): 574*90277196SAndroid Build Coastguard Worker """Parse the registry Element, once created""" 575*90277196SAndroid Build Coastguard Worker # This must be the Element for the root <registry> 576*90277196SAndroid Build Coastguard Worker if self.tree is None: 577*90277196SAndroid Build Coastguard Worker raise RuntimeError("Tree not initialized!") 578*90277196SAndroid Build Coastguard Worker self.reg = self.tree.getroot() 579*90277196SAndroid Build Coastguard Worker 580*90277196SAndroid Build Coastguard Worker # Preprocess the tree in one of the following ways: 581*90277196SAndroid Build Coastguard Worker # - either merge a set of APIs to another API based on their 'api' attributes 582*90277196SAndroid Build Coastguard Worker # - or remove all elements with non-matching 'api' attributes 583*90277196SAndroid Build Coastguard Worker # The preprocessing happens through a breath-first tree traversal. 584*90277196SAndroid Build Coastguard Worker # This is a blunt hammer, but eliminates the need to track and test 585*90277196SAndroid Build Coastguard Worker # the apis deeper in processing to select the correct elements and 586*90277196SAndroid Build Coastguard Worker # avoid duplicates. 587*90277196SAndroid Build Coastguard Worker # Schema validation should prevent duplicate elements with 588*90277196SAndroid Build Coastguard Worker # overlapping api attributes, or where one element has an api 589*90277196SAndroid Build Coastguard Worker # attribute and the other does not. 590*90277196SAndroid Build Coastguard Worker 591*90277196SAndroid Build Coastguard Worker if self.genOpts.mergeApiNames: 592*90277196SAndroid Build Coastguard Worker mergeAPIs(self.reg, self.genOpts.mergeApiNames.split(','), self.genOpts.apiname) 593*90277196SAndroid Build Coastguard Worker else: 594*90277196SAndroid Build Coastguard Worker stripNonmatchingAPIs(self.reg, self.genOpts.apiname, actuallyDelete = True) 595*90277196SAndroid Build Coastguard Worker 596*90277196SAndroid Build Coastguard Worker self.aliasdict = {} 597*90277196SAndroid Build Coastguard Worker self.enumvaluedict = {} 598*90277196SAndroid Build Coastguard Worker 599*90277196SAndroid Build Coastguard Worker # Create dictionary of registry types from toplevel <types> tags 600*90277196SAndroid Build Coastguard Worker # and add 'name' attribute to each <type> tag (where missing) 601*90277196SAndroid Build Coastguard Worker # based on its <name> element. 602*90277196SAndroid Build Coastguard Worker # 603*90277196SAndroid Build Coastguard Worker # There is usually one <types> block; more are OK 604*90277196SAndroid Build Coastguard Worker # Required <type> attributes: 'name' or nested <name> tag contents 605*90277196SAndroid Build Coastguard Worker self.typedict = {} 606*90277196SAndroid Build Coastguard Worker for type_elem in self.reg.findall('types/type'): 607*90277196SAndroid Build Coastguard Worker # If the <type> does not already have a 'name' attribute, set 608*90277196SAndroid Build Coastguard Worker # it from contents of its <name> tag. 609*90277196SAndroid Build Coastguard Worker name = type_elem.get('name') 610*90277196SAndroid Build Coastguard Worker if name is None: 611*90277196SAndroid Build Coastguard Worker name_elem = type_elem.find('name') 612*90277196SAndroid Build Coastguard Worker if name_elem is None or not name_elem.text: 613*90277196SAndroid Build Coastguard Worker raise RuntimeError("Type without a name!") 614*90277196SAndroid Build Coastguard Worker name = name_elem.text 615*90277196SAndroid Build Coastguard Worker type_elem.set('name', name) 616*90277196SAndroid Build Coastguard Worker self.addElementInfo(type_elem, TypeInfo(type_elem), 'type', self.typedict) 617*90277196SAndroid Build Coastguard Worker 618*90277196SAndroid Build Coastguard Worker # Record alias, if any 619*90277196SAndroid Build Coastguard Worker alias = type_elem.get('alias') 620*90277196SAndroid Build Coastguard Worker if alias: 621*90277196SAndroid Build Coastguard Worker self.aliasdict[name] = alias 622*90277196SAndroid Build Coastguard Worker 623*90277196SAndroid Build Coastguard Worker # Create dictionary of registry enum groups from <enums> tags. 624*90277196SAndroid Build Coastguard Worker # 625*90277196SAndroid Build Coastguard Worker # Required <enums> attributes: 'name'. If no name is given, one is 626*90277196SAndroid Build Coastguard Worker # generated, but that group cannot be identified and turned into an 627*90277196SAndroid Build Coastguard Worker # enum type definition - it is just a container for <enum> tags. 628*90277196SAndroid Build Coastguard Worker self.groupdict = {} 629*90277196SAndroid Build Coastguard Worker for group in self.reg.findall('enums'): 630*90277196SAndroid Build Coastguard Worker self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) 631*90277196SAndroid Build Coastguard Worker 632*90277196SAndroid Build Coastguard Worker # Create dictionary of registry enums from <enum> tags 633*90277196SAndroid Build Coastguard Worker # 634*90277196SAndroid Build Coastguard Worker # <enums> tags usually define different namespaces for the values 635*90277196SAndroid Build Coastguard Worker # defined in those tags, but the actual names all share the 636*90277196SAndroid Build Coastguard Worker # same dictionary. 637*90277196SAndroid Build Coastguard Worker # Required <enum> attributes: 'name', 'value' 638*90277196SAndroid Build Coastguard Worker # For containing <enums> which have type="enum" or type="bitmask", 639*90277196SAndroid Build Coastguard Worker # tag all contained <enum>s are required. This is a stopgap until 640*90277196SAndroid Build Coastguard Worker # a better scheme for tagging core and extension enums is created. 641*90277196SAndroid Build Coastguard Worker self.enumdict = {} 642*90277196SAndroid Build Coastguard Worker for enums in self.reg.findall('enums'): 643*90277196SAndroid Build Coastguard Worker required = (enums.get('type') is not None) 644*90277196SAndroid Build Coastguard Worker type_name = enums.get('name') 645*90277196SAndroid Build Coastguard Worker # Enum values are defined only for the type that is not aliased to something else. 646*90277196SAndroid Build Coastguard Worker assert(type_name not in self.aliasdict) 647*90277196SAndroid Build Coastguard Worker for enum in enums.findall('enum'): 648*90277196SAndroid Build Coastguard Worker enumInfo = EnumInfo(enum) 649*90277196SAndroid Build Coastguard Worker enumInfo.required = required 650*90277196SAndroid Build Coastguard Worker self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 651*90277196SAndroid Build Coastguard Worker self.addEnumValue(enum, type_name) 652*90277196SAndroid Build Coastguard Worker 653*90277196SAndroid Build Coastguard Worker # Create dictionary of registry commands from <command> tags 654*90277196SAndroid Build Coastguard Worker # and add 'name' attribute to each <command> tag (where missing) 655*90277196SAndroid Build Coastguard Worker # based on its <proto><name> element. 656*90277196SAndroid Build Coastguard Worker # 657*90277196SAndroid Build Coastguard Worker # There is usually only one <commands> block; more are OK. 658*90277196SAndroid Build Coastguard Worker # Required <command> attributes: 'name' or <proto><name> tag contents 659*90277196SAndroid Build Coastguard Worker self.cmddict = {} 660*90277196SAndroid Build Coastguard Worker # List of commands which alias others. Contains 661*90277196SAndroid Build Coastguard Worker # [ name, aliasName, element ] 662*90277196SAndroid Build Coastguard Worker # for each alias 663*90277196SAndroid Build Coastguard Worker cmdAlias = [] 664*90277196SAndroid Build Coastguard Worker for cmd in self.reg.findall('commands/command'): 665*90277196SAndroid Build Coastguard Worker # If the <command> does not already have a 'name' attribute, set 666*90277196SAndroid Build Coastguard Worker # it from contents of its <proto><name> tag. 667*90277196SAndroid Build Coastguard Worker name = cmd.get('name') 668*90277196SAndroid Build Coastguard Worker if name is None: 669*90277196SAndroid Build Coastguard Worker name_elem = cmd.find('proto/name') 670*90277196SAndroid Build Coastguard Worker if name_elem is None or not name_elem.text: 671*90277196SAndroid Build Coastguard Worker raise RuntimeError("Command without a name!") 672*90277196SAndroid Build Coastguard Worker name = cmd.set('name', name_elem.text) 673*90277196SAndroid Build Coastguard Worker ci = CmdInfo(cmd) 674*90277196SAndroid Build Coastguard Worker self.addElementInfo(cmd, ci, 'command', self.cmddict) 675*90277196SAndroid Build Coastguard Worker alias = cmd.get('alias') 676*90277196SAndroid Build Coastguard Worker if alias: 677*90277196SAndroid Build Coastguard Worker cmdAlias.append([name, alias, cmd]) 678*90277196SAndroid Build Coastguard Worker self.aliasdict[name] = alias 679*90277196SAndroid Build Coastguard Worker 680*90277196SAndroid Build Coastguard Worker # Now loop over aliases, injecting a copy of the aliased command's 681*90277196SAndroid Build Coastguard Worker # Element with the aliased prototype name replaced with the command 682*90277196SAndroid Build Coastguard Worker # name - if it exists. 683*90277196SAndroid Build Coastguard Worker for (name, alias, cmd) in cmdAlias: 684*90277196SAndroid Build Coastguard Worker if alias in self.cmddict: 685*90277196SAndroid Build Coastguard Worker aliasInfo = self.cmddict[alias] 686*90277196SAndroid Build Coastguard Worker cmdElem = copy.deepcopy(aliasInfo.elem) 687*90277196SAndroid Build Coastguard Worker cmdElem.find('proto/name').text = name 688*90277196SAndroid Build Coastguard Worker cmdElem.set('name', name) 689*90277196SAndroid Build Coastguard Worker cmdElem.set('alias', alias) 690*90277196SAndroid Build Coastguard Worker ci = CmdInfo(cmdElem) 691*90277196SAndroid Build Coastguard Worker # Replace the dictionary entry for the CmdInfo element 692*90277196SAndroid Build Coastguard Worker self.cmddict[name] = ci 693*90277196SAndroid Build Coastguard Worker 694*90277196SAndroid Build Coastguard Worker # @ newString = etree.tostring(base, encoding="unicode").replace(aliasValue, aliasName) 695*90277196SAndroid Build Coastguard Worker # @elem.append(etree.fromstring(replacement)) 696*90277196SAndroid Build Coastguard Worker else: 697*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'No matching <command> found for command', 698*90277196SAndroid Build Coastguard Worker cmd.get('name'), 'alias', alias) 699*90277196SAndroid Build Coastguard Worker 700*90277196SAndroid Build Coastguard Worker # Create dictionaries of API and extension interfaces 701*90277196SAndroid Build Coastguard Worker # from toplevel <api> and <extension> tags. 702*90277196SAndroid Build Coastguard Worker self.apidict = {} 703*90277196SAndroid Build Coastguard Worker format_condition = dict() 704*90277196SAndroid Build Coastguard Worker for feature in self.reg.findall('feature'): 705*90277196SAndroid Build Coastguard Worker featureInfo = FeatureInfo(feature) 706*90277196SAndroid Build Coastguard Worker self.addElementInfo(feature, featureInfo, 'feature', self.apidict) 707*90277196SAndroid Build Coastguard Worker 708*90277196SAndroid Build Coastguard Worker # Add additional enums defined only in <feature> tags 709*90277196SAndroid Build Coastguard Worker # to the corresponding enumerated type. 710*90277196SAndroid Build Coastguard Worker # When seen here, the <enum> element, processed to contain the 711*90277196SAndroid Build Coastguard Worker # numeric enum value, is added to the corresponding <enums> 712*90277196SAndroid Build Coastguard Worker # element, as well as adding to the enum dictionary. It is no 713*90277196SAndroid Build Coastguard Worker # longer removed from the <require> element it is introduced in. 714*90277196SAndroid Build Coastguard Worker # Instead, generateRequiredInterface ignores <enum> elements 715*90277196SAndroid Build Coastguard Worker # that extend enumerated types. 716*90277196SAndroid Build Coastguard Worker # 717*90277196SAndroid Build Coastguard Worker # For <enum> tags which are actually just constants, if there is 718*90277196SAndroid Build Coastguard Worker # no 'extends' tag but there is a 'value' or 'bitpos' tag, just 719*90277196SAndroid Build Coastguard Worker # add an EnumInfo record to the dictionary. That works because 720*90277196SAndroid Build Coastguard Worker # output generation of constants is purely dependency-based, and 721*90277196SAndroid Build Coastguard Worker # does not need to iterate through the XML tags. 722*90277196SAndroid Build Coastguard Worker for elem in feature.findall('require'): 723*90277196SAndroid Build Coastguard Worker for enum in elem.findall('enum'): 724*90277196SAndroid Build Coastguard Worker addEnumInfo = False 725*90277196SAndroid Build Coastguard Worker groupName = enum.get('extends') 726*90277196SAndroid Build Coastguard Worker if groupName is not None: 727*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Found extension enum', 728*90277196SAndroid Build Coastguard Worker # enum.get('name')) 729*90277196SAndroid Build Coastguard Worker # Add version number attribute to the <enum> element 730*90277196SAndroid Build Coastguard Worker enum.set('version', featureInfo.version) 731*90277196SAndroid Build Coastguard Worker # Look up the GroupInfo with matching groupName 732*90277196SAndroid Build Coastguard Worker if groupName in self.groupdict: 733*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Matching group', 734*90277196SAndroid Build Coastguard Worker # groupName, 'found, adding element...') 735*90277196SAndroid Build Coastguard Worker gi = self.groupdict[groupName] 736*90277196SAndroid Build Coastguard Worker gi.elem.append(copy.deepcopy(enum)) 737*90277196SAndroid Build Coastguard Worker else: 738*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'NO matching group', 739*90277196SAndroid Build Coastguard Worker groupName, 'for enum', enum.get('name'), 'found.') 740*90277196SAndroid Build Coastguard Worker if groupName == "VkFormat": 741*90277196SAndroid Build Coastguard Worker format_name = enum.get('name') 742*90277196SAndroid Build Coastguard Worker if enum.get('alias'): 743*90277196SAndroid Build Coastguard Worker format_name = enum.get('alias') 744*90277196SAndroid Build Coastguard Worker format_condition[format_name] = featureInfo.name 745*90277196SAndroid Build Coastguard Worker addEnumInfo = True 746*90277196SAndroid Build Coastguard Worker elif enum.get('value') or enum.get('bitpos') or enum.get('alias'): 747*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Adding extension constant "enum"', 748*90277196SAndroid Build Coastguard Worker # enum.get('name')) 749*90277196SAndroid Build Coastguard Worker addEnumInfo = True 750*90277196SAndroid Build Coastguard Worker if addEnumInfo: 751*90277196SAndroid Build Coastguard Worker enumInfo = EnumInfo(enum) 752*90277196SAndroid Build Coastguard Worker self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 753*90277196SAndroid Build Coastguard Worker self.addEnumValue(enum, groupName) 754*90277196SAndroid Build Coastguard Worker 755*90277196SAndroid Build Coastguard Worker sync_pipeline_stage_condition = dict() 756*90277196SAndroid Build Coastguard Worker sync_access_condition = dict() 757*90277196SAndroid Build Coastguard Worker 758*90277196SAndroid Build Coastguard Worker self.extensions = self.reg.findall('extensions/extension') 759*90277196SAndroid Build Coastguard Worker self.extdict = {} 760*90277196SAndroid Build Coastguard Worker for feature in self.extensions: 761*90277196SAndroid Build Coastguard Worker featureInfo = FeatureInfo(feature) 762*90277196SAndroid Build Coastguard Worker self.addElementInfo(feature, featureInfo, 'extension', self.extdict) 763*90277196SAndroid Build Coastguard Worker 764*90277196SAndroid Build Coastguard Worker # Add additional enums defined only in <extension> tags 765*90277196SAndroid Build Coastguard Worker # to the corresponding core type. 766*90277196SAndroid Build Coastguard Worker # Algorithm matches that of enums in a "feature" tag as above. 767*90277196SAndroid Build Coastguard Worker # 768*90277196SAndroid Build Coastguard Worker # This code also adds a 'extnumber' attribute containing the 769*90277196SAndroid Build Coastguard Worker # extension number, used for enumerant value calculation. 770*90277196SAndroid Build Coastguard Worker for elem in feature.findall('require'): 771*90277196SAndroid Build Coastguard Worker for enum in elem.findall('enum'): 772*90277196SAndroid Build Coastguard Worker addEnumInfo = False 773*90277196SAndroid Build Coastguard Worker groupName = enum.get('extends') 774*90277196SAndroid Build Coastguard Worker if groupName is not None: 775*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Found extension enum', 776*90277196SAndroid Build Coastguard Worker # enum.get('name')) 777*90277196SAndroid Build Coastguard Worker 778*90277196SAndroid Build Coastguard Worker # Add <extension> block's extension number attribute to 779*90277196SAndroid Build Coastguard Worker # the <enum> element unless specified explicitly, such 780*90277196SAndroid Build Coastguard Worker # as when redefining an enum in another extension. 781*90277196SAndroid Build Coastguard Worker extnumber = enum.get('extnumber') 782*90277196SAndroid Build Coastguard Worker if not extnumber: 783*90277196SAndroid Build Coastguard Worker enum.set('extnumber', str(featureInfo.number)) 784*90277196SAndroid Build Coastguard Worker 785*90277196SAndroid Build Coastguard Worker enum.set('extname', featureInfo.name) 786*90277196SAndroid Build Coastguard Worker enum.set('supported', noneStr(featureInfo.supported)) 787*90277196SAndroid Build Coastguard Worker # Look up the GroupInfo with matching groupName 788*90277196SAndroid Build Coastguard Worker if groupName in self.groupdict: 789*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Matching group', 790*90277196SAndroid Build Coastguard Worker # groupName, 'found, adding element...') 791*90277196SAndroid Build Coastguard Worker gi = self.groupdict[groupName] 792*90277196SAndroid Build Coastguard Worker gi.elem.append(copy.deepcopy(enum)) 793*90277196SAndroid Build Coastguard Worker else: 794*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'NO matching group', 795*90277196SAndroid Build Coastguard Worker groupName, 'for enum', enum.get('name'), 'found.') 796*90277196SAndroid Build Coastguard Worker # This is Vulkan-specific 797*90277196SAndroid Build Coastguard Worker if groupName == "VkFormat": 798*90277196SAndroid Build Coastguard Worker format_name = enum.get('name') 799*90277196SAndroid Build Coastguard Worker if enum.get('alias'): 800*90277196SAndroid Build Coastguard Worker format_name = enum.get('alias') 801*90277196SAndroid Build Coastguard Worker if format_name in format_condition: 802*90277196SAndroid Build Coastguard Worker format_condition[format_name] += "," + featureInfo.name 803*90277196SAndroid Build Coastguard Worker else: 804*90277196SAndroid Build Coastguard Worker format_condition[format_name] = featureInfo.name 805*90277196SAndroid Build Coastguard Worker elif groupName == "VkPipelineStageFlagBits2": 806*90277196SAndroid Build Coastguard Worker stage_flag = enum.get('name') 807*90277196SAndroid Build Coastguard Worker if enum.get('alias'): 808*90277196SAndroid Build Coastguard Worker stage_flag = enum.get('alias') 809*90277196SAndroid Build Coastguard Worker featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name 810*90277196SAndroid Build Coastguard Worker if stage_flag in sync_pipeline_stage_condition: 811*90277196SAndroid Build Coastguard Worker sync_pipeline_stage_condition[stage_flag] += "," + featureName 812*90277196SAndroid Build Coastguard Worker else: 813*90277196SAndroid Build Coastguard Worker sync_pipeline_stage_condition[stage_flag] = featureName 814*90277196SAndroid Build Coastguard Worker elif groupName == "VkAccessFlagBits2": 815*90277196SAndroid Build Coastguard Worker access_flag = enum.get('name') 816*90277196SAndroid Build Coastguard Worker if enum.get('alias'): 817*90277196SAndroid Build Coastguard Worker access_flag = enum.get('alias') 818*90277196SAndroid Build Coastguard Worker featureName = elem.get('depends') if elem.get('depends') is not None else featureInfo.name 819*90277196SAndroid Build Coastguard Worker if access_flag in sync_access_condition: 820*90277196SAndroid Build Coastguard Worker sync_access_condition[access_flag] += "," + featureName 821*90277196SAndroid Build Coastguard Worker else: 822*90277196SAndroid Build Coastguard Worker sync_access_condition[access_flag] = featureName 823*90277196SAndroid Build Coastguard Worker 824*90277196SAndroid Build Coastguard Worker addEnumInfo = True 825*90277196SAndroid Build Coastguard Worker elif enum.get('value') or enum.get('bitpos') or enum.get('alias'): 826*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', 'Adding extension constant "enum"', 827*90277196SAndroid Build Coastguard Worker # enum.get('name')) 828*90277196SAndroid Build Coastguard Worker addEnumInfo = True 829*90277196SAndroid Build Coastguard Worker if addEnumInfo: 830*90277196SAndroid Build Coastguard Worker enumInfo = EnumInfo(enum) 831*90277196SAndroid Build Coastguard Worker self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 832*90277196SAndroid Build Coastguard Worker self.addEnumValue(enum, groupName) 833*90277196SAndroid Build Coastguard Worker 834*90277196SAndroid Build Coastguard Worker # Parse out all spirv tags in dictionaries 835*90277196SAndroid Build Coastguard Worker # Use addElementInfo to catch duplicates 836*90277196SAndroid Build Coastguard Worker for spirv in self.reg.findall('spirvextensions/spirvextension'): 837*90277196SAndroid Build Coastguard Worker spirvInfo = SpirvInfo(spirv) 838*90277196SAndroid Build Coastguard Worker self.addElementInfo(spirv, spirvInfo, 'spirvextension', self.spirvextdict) 839*90277196SAndroid Build Coastguard Worker for spirv in self.reg.findall('spirvcapabilities/spirvcapability'): 840*90277196SAndroid Build Coastguard Worker spirvInfo = SpirvInfo(spirv) 841*90277196SAndroid Build Coastguard Worker self.addElementInfo(spirv, spirvInfo, 'spirvcapability', self.spirvcapdict) 842*90277196SAndroid Build Coastguard Worker 843*90277196SAndroid Build Coastguard Worker for format in self.reg.findall('formats/format'): 844*90277196SAndroid Build Coastguard Worker condition = None 845*90277196SAndroid Build Coastguard Worker format_name = format.get('name') 846*90277196SAndroid Build Coastguard Worker if format_name in format_condition: 847*90277196SAndroid Build Coastguard Worker condition = format_condition[format_name] 848*90277196SAndroid Build Coastguard Worker formatInfo = FormatInfo(format, condition) 849*90277196SAndroid Build Coastguard Worker self.addElementInfo(format, formatInfo, 'format', self.formatsdict) 850*90277196SAndroid Build Coastguard Worker 851*90277196SAndroid Build Coastguard Worker for stage in self.reg.findall('sync/syncstage'): 852*90277196SAndroid Build Coastguard Worker condition = None 853*90277196SAndroid Build Coastguard Worker stage_flag = stage.get('name') 854*90277196SAndroid Build Coastguard Worker if stage_flag in sync_pipeline_stage_condition: 855*90277196SAndroid Build Coastguard Worker condition = sync_pipeline_stage_condition[stage_flag] 856*90277196SAndroid Build Coastguard Worker syncInfo = SyncStageInfo(stage, condition) 857*90277196SAndroid Build Coastguard Worker self.addElementInfo(stage, syncInfo, 'syncstage', self.syncstagedict) 858*90277196SAndroid Build Coastguard Worker 859*90277196SAndroid Build Coastguard Worker for access in self.reg.findall('sync/syncaccess'): 860*90277196SAndroid Build Coastguard Worker condition = None 861*90277196SAndroid Build Coastguard Worker access_flag = access.get('name') 862*90277196SAndroid Build Coastguard Worker if access_flag in sync_access_condition: 863*90277196SAndroid Build Coastguard Worker condition = sync_access_condition[access_flag] 864*90277196SAndroid Build Coastguard Worker syncInfo = SyncAccessInfo(access, condition) 865*90277196SAndroid Build Coastguard Worker self.addElementInfo(access, syncInfo, 'syncaccess', self.syncaccessdict) 866*90277196SAndroid Build Coastguard Worker 867*90277196SAndroid Build Coastguard Worker for pipeline in self.reg.findall('sync/syncpipeline'): 868*90277196SAndroid Build Coastguard Worker syncInfo = SyncPipelineInfo(pipeline) 869*90277196SAndroid Build Coastguard Worker self.addElementInfo(pipeline, syncInfo, 'syncpipeline', self.syncpipelinedict) 870*90277196SAndroid Build Coastguard Worker 871*90277196SAndroid Build Coastguard Worker def dumpReg(self, maxlen=120, filehandle=sys.stdout): 872*90277196SAndroid Build Coastguard Worker """Dump all the dictionaries constructed from the Registry object. 873*90277196SAndroid Build Coastguard Worker 874*90277196SAndroid Build Coastguard Worker Diagnostic to dump the dictionaries to specified file handle (default stdout). 875*90277196SAndroid Build Coastguard Worker Truncates type / enum / command elements to maxlen characters (default 120)""" 876*90277196SAndroid Build Coastguard Worker write('***************************************', file=filehandle) 877*90277196SAndroid Build Coastguard Worker write(' ** Dumping Registry contents **', file=filehandle) 878*90277196SAndroid Build Coastguard Worker write('***************************************', file=filehandle) 879*90277196SAndroid Build Coastguard Worker write('// Types', file=filehandle) 880*90277196SAndroid Build Coastguard Worker for name in self.typedict: 881*90277196SAndroid Build Coastguard Worker tobj = self.typedict[name] 882*90277196SAndroid Build Coastguard Worker write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle) 883*90277196SAndroid Build Coastguard Worker write('// Groups', file=filehandle) 884*90277196SAndroid Build Coastguard Worker for name in self.groupdict: 885*90277196SAndroid Build Coastguard Worker gobj = self.groupdict[name] 886*90277196SAndroid Build Coastguard Worker write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle) 887*90277196SAndroid Build Coastguard Worker write('// Enums', file=filehandle) 888*90277196SAndroid Build Coastguard Worker for name in self.enumdict: 889*90277196SAndroid Build Coastguard Worker eobj = self.enumdict[name] 890*90277196SAndroid Build Coastguard Worker write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle) 891*90277196SAndroid Build Coastguard Worker write('// Commands', file=filehandle) 892*90277196SAndroid Build Coastguard Worker for name in self.cmddict: 893*90277196SAndroid Build Coastguard Worker cobj = self.cmddict[name] 894*90277196SAndroid Build Coastguard Worker write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle) 895*90277196SAndroid Build Coastguard Worker write('// APIs', file=filehandle) 896*90277196SAndroid Build Coastguard Worker for key in self.apidict: 897*90277196SAndroid Build Coastguard Worker write(' API Version ', key, '->', 898*90277196SAndroid Build Coastguard Worker etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle) 899*90277196SAndroid Build Coastguard Worker write('// Extensions', file=filehandle) 900*90277196SAndroid Build Coastguard Worker for key in self.extdict: 901*90277196SAndroid Build Coastguard Worker write(' Extension', key, '->', 902*90277196SAndroid Build Coastguard Worker etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle) 903*90277196SAndroid Build Coastguard Worker write('// SPIR-V', file=filehandle) 904*90277196SAndroid Build Coastguard Worker for key in self.spirvextdict: 905*90277196SAndroid Build Coastguard Worker write(' SPIR-V Extension', key, '->', 906*90277196SAndroid Build Coastguard Worker etree.tostring(self.spirvextdict[key].elem)[0:maxlen], file=filehandle) 907*90277196SAndroid Build Coastguard Worker for key in self.spirvcapdict: 908*90277196SAndroid Build Coastguard Worker write(' SPIR-V Capability', key, '->', 909*90277196SAndroid Build Coastguard Worker etree.tostring(self.spirvcapdict[key].elem)[0:maxlen], file=filehandle) 910*90277196SAndroid Build Coastguard Worker write('// VkFormat', file=filehandle) 911*90277196SAndroid Build Coastguard Worker for key in self.formatsdict: 912*90277196SAndroid Build Coastguard Worker write(' VkFormat', key, '->', 913*90277196SAndroid Build Coastguard Worker etree.tostring(self.formatsdict[key].elem)[0:maxlen], file=filehandle) 914*90277196SAndroid Build Coastguard Worker 915*90277196SAndroid Build Coastguard Worker def markTypeRequired(self, typename, required): 916*90277196SAndroid Build Coastguard Worker """Require (along with its dependencies) or remove (but not its dependencies) a type. 917*90277196SAndroid Build Coastguard Worker 918*90277196SAndroid Build Coastguard Worker - typename - name of type 919*90277196SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not) 920*90277196SAndroid Build Coastguard Worker """ 921*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'tagging type:', typename, '-> required =', required) 922*90277196SAndroid Build Coastguard Worker 923*90277196SAndroid Build Coastguard Worker # Get TypeInfo object for <type> tag corresponding to typename 924*90277196SAndroid Build Coastguard Worker typeinfo = self.lookupElementInfo(typename, self.typedict) 925*90277196SAndroid Build Coastguard Worker if typeinfo is not None: 926*90277196SAndroid Build Coastguard Worker if required: 927*90277196SAndroid Build Coastguard Worker # Tag type dependencies in 'alias' and 'required' attributes as 928*90277196SAndroid Build Coastguard Worker # required. This does not un-tag dependencies in a <remove> 929*90277196SAndroid Build Coastguard Worker # tag. See comments in markRequired() below for the reason. 930*90277196SAndroid Build Coastguard Worker for attrib_name in ['requires', 'alias']: 931*90277196SAndroid Build Coastguard Worker depname = typeinfo.elem.get(attrib_name) 932*90277196SAndroid Build Coastguard Worker if depname: 933*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating dependent type', 934*90277196SAndroid Build Coastguard Worker depname, 'for', attrib_name, 'type', typename) 935*90277196SAndroid Build Coastguard Worker # Do not recurse on self-referential structures. 936*90277196SAndroid Build Coastguard Worker if typename != depname: 937*90277196SAndroid Build Coastguard Worker self.markTypeRequired(depname, required) 938*90277196SAndroid Build Coastguard Worker else: 939*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'type', typename, 'is self-referential') 940*90277196SAndroid Build Coastguard Worker # Tag types used in defining this type (e.g. in nested 941*90277196SAndroid Build Coastguard Worker # <type> tags) 942*90277196SAndroid Build Coastguard Worker # Look for <type> in entire <command> tree, 943*90277196SAndroid Build Coastguard Worker # not just immediate children 944*90277196SAndroid Build Coastguard Worker for subtype in typeinfo.elem.findall('.//type'): 945*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'markRequired: type requires dependent <type>', subtype.text) 946*90277196SAndroid Build Coastguard Worker if typename != subtype.text: 947*90277196SAndroid Build Coastguard Worker self.markTypeRequired(subtype.text, required) 948*90277196SAndroid Build Coastguard Worker else: 949*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'type', typename, 'is self-referential') 950*90277196SAndroid Build Coastguard Worker # Tag enums used in defining this type, for example in 951*90277196SAndroid Build Coastguard Worker # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member> 952*90277196SAndroid Build Coastguard Worker for subenum in typeinfo.elem.findall('.//enum'): 953*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'markRequired: type requires dependent <enum>', subenum.text) 954*90277196SAndroid Build Coastguard Worker self.markEnumRequired(subenum.text, required) 955*90277196SAndroid Build Coastguard Worker # Tag type dependency in 'bitvalues' attributes as 956*90277196SAndroid Build Coastguard Worker # required. This ensures that the bit values for a flag 957*90277196SAndroid Build Coastguard Worker # are emitted 958*90277196SAndroid Build Coastguard Worker depType = typeinfo.elem.get('bitvalues') 959*90277196SAndroid Build Coastguard Worker if depType: 960*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating bitflag type', 961*90277196SAndroid Build Coastguard Worker depType, 'for type', typename) 962*90277196SAndroid Build Coastguard Worker self.markTypeRequired(depType, required) 963*90277196SAndroid Build Coastguard Worker group = self.lookupElementInfo(depType, self.groupdict) 964*90277196SAndroid Build Coastguard Worker if group is not None: 965*90277196SAndroid Build Coastguard Worker group.flagType = typeinfo 966*90277196SAndroid Build Coastguard Worker 967*90277196SAndroid Build Coastguard Worker typeinfo.required = required 968*90277196SAndroid Build Coastguard Worker elif '.h' not in typename: 969*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'type:', typename, 'IS NOT DEFINED') 970*90277196SAndroid Build Coastguard Worker 971*90277196SAndroid Build Coastguard Worker def markEnumRequired(self, enumname, required): 972*90277196SAndroid Build Coastguard Worker """Mark an enum as required or not. 973*90277196SAndroid Build Coastguard Worker 974*90277196SAndroid Build Coastguard Worker - enumname - name of enum 975*90277196SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not)""" 976*90277196SAndroid Build Coastguard Worker 977*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'markEnumRequired: tagging enum:', enumname, '-> required =', required) 978*90277196SAndroid Build Coastguard Worker enum = self.lookupElementInfo(enumname, self.enumdict) 979*90277196SAndroid Build Coastguard Worker if enum is not None: 980*90277196SAndroid Build Coastguard Worker # If the enum is part of a group, and is being removed, then 981*90277196SAndroid Build Coastguard Worker # look it up in that <enums> tag and remove the Element there, 982*90277196SAndroid Build Coastguard Worker # so that it is not visible to generators (which traverse the 983*90277196SAndroid Build Coastguard Worker # <enums> tag elements rather than using the dictionaries). 984*90277196SAndroid Build Coastguard Worker if not required: 985*90277196SAndroid Build Coastguard Worker groupName = enum.elem.get('extends') 986*90277196SAndroid Build Coastguard Worker if groupName is not None: 987*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', f'markEnumRequired: Removing extending enum {enum.elem.get("name")}') 988*90277196SAndroid Build Coastguard Worker 989*90277196SAndroid Build Coastguard Worker # Look up the Info with matching groupName 990*90277196SAndroid Build Coastguard Worker if groupName in self.groupdict: 991*90277196SAndroid Build Coastguard Worker gi = self.groupdict[groupName] 992*90277196SAndroid Build Coastguard Worker gienum = gi.elem.find("enum[@name='" + enumname + "']") 993*90277196SAndroid Build Coastguard Worker if gienum is not None: 994*90277196SAndroid Build Coastguard Worker # Remove copy of this enum from the group 995*90277196SAndroid Build Coastguard Worker gi.elem.remove(gienum) 996*90277196SAndroid Build Coastguard Worker else: 997*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'markEnumRequired: Cannot remove enum', 998*90277196SAndroid Build Coastguard Worker enumname, 'not found in group', 999*90277196SAndroid Build Coastguard Worker groupName) 1000*90277196SAndroid Build Coastguard Worker else: 1001*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'markEnumRequired: Cannot remove enum', 1002*90277196SAndroid Build Coastguard Worker enumname, 'from nonexistent group', 1003*90277196SAndroid Build Coastguard Worker groupName) 1004*90277196SAndroid Build Coastguard Worker else: 1005*90277196SAndroid Build Coastguard Worker # This enum is not an extending enum. 1006*90277196SAndroid Build Coastguard Worker # The XML tree must be searched for all <enums> that 1007*90277196SAndroid Build Coastguard Worker # might have it, so we know the parent to delete from. 1008*90277196SAndroid Build Coastguard Worker 1009*90277196SAndroid Build Coastguard Worker enumName = enum.elem.get('name') 1010*90277196SAndroid Build Coastguard Worker 1011*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', f'markEnumRequired: Removing non-extending enum {enumName}') 1012*90277196SAndroid Build Coastguard Worker 1013*90277196SAndroid Build Coastguard Worker count = 0 1014*90277196SAndroid Build Coastguard Worker for enums in self.reg.findall('enums'): 1015*90277196SAndroid Build Coastguard Worker for thisEnum in enums.findall('enum'): 1016*90277196SAndroid Build Coastguard Worker if thisEnum.get('name') == enumName: 1017*90277196SAndroid Build Coastguard Worker # Actually remove it 1018*90277196SAndroid Build Coastguard Worker count = count + 1 1019*90277196SAndroid Build Coastguard Worker enums.remove(thisEnum) 1020*90277196SAndroid Build Coastguard Worker 1021*90277196SAndroid Build Coastguard Worker if count == 0: 1022*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', f'markEnumRequired: {enumName}) not found in any <enums> tag') 1023*90277196SAndroid Build Coastguard Worker 1024*90277196SAndroid Build Coastguard Worker enum.required = required 1025*90277196SAndroid Build Coastguard Worker # Tag enum dependencies in 'alias' attribute as required 1026*90277196SAndroid Build Coastguard Worker depname = enum.elem.get('alias') 1027*90277196SAndroid Build Coastguard Worker if depname: 1028*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'markEnumRequired: Generating dependent enum', 1029*90277196SAndroid Build Coastguard Worker depname, 'for alias', enumname, 'required =', enum.required) 1030*90277196SAndroid Build Coastguard Worker self.markEnumRequired(depname, required) 1031*90277196SAndroid Build Coastguard Worker else: 1032*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', f'markEnumRequired: {enumname} IS NOT DEFINED') 1033*90277196SAndroid Build Coastguard Worker 1034*90277196SAndroid Build Coastguard Worker def markCmdRequired(self, cmdname, required): 1035*90277196SAndroid Build Coastguard Worker """Mark a command as required or not. 1036*90277196SAndroid Build Coastguard Worker 1037*90277196SAndroid Build Coastguard Worker - cmdname - name of command 1038*90277196SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not)""" 1039*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'tagging command:', cmdname, '-> required =', required) 1040*90277196SAndroid Build Coastguard Worker cmd = self.lookupElementInfo(cmdname, self.cmddict) 1041*90277196SAndroid Build Coastguard Worker if cmd is not None: 1042*90277196SAndroid Build Coastguard Worker cmd.required = required 1043*90277196SAndroid Build Coastguard Worker 1044*90277196SAndroid Build Coastguard Worker # Tag command dependencies in 'alias' attribute as required 1045*90277196SAndroid Build Coastguard Worker # 1046*90277196SAndroid Build Coastguard Worker # This is usually not done, because command 'aliases' are not 1047*90277196SAndroid Build Coastguard Worker # actual C language aliases like type and enum aliases. Instead 1048*90277196SAndroid Build Coastguard Worker # they are just duplicates of the function signature of the 1049*90277196SAndroid Build Coastguard Worker # alias. This means that there is no dependency of a command 1050*90277196SAndroid Build Coastguard Worker # alias on what it aliases. One exception is validity includes, 1051*90277196SAndroid Build Coastguard Worker # where the spec markup needs the promoted-to validity include 1052*90277196SAndroid Build Coastguard Worker # even if only the promoted-from command is being built. 1053*90277196SAndroid Build Coastguard Worker if self.genOpts.requireCommandAliases: 1054*90277196SAndroid Build Coastguard Worker depname = cmd.elem.get('alias') 1055*90277196SAndroid Build Coastguard Worker if depname: 1056*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating dependent command', 1057*90277196SAndroid Build Coastguard Worker depname, 'for alias', cmdname) 1058*90277196SAndroid Build Coastguard Worker self.markCmdRequired(depname, required) 1059*90277196SAndroid Build Coastguard Worker 1060*90277196SAndroid Build Coastguard Worker # Tag all parameter types of this command as required. 1061*90277196SAndroid Build Coastguard Worker # This does not remove types of commands in a <remove> 1062*90277196SAndroid Build Coastguard Worker # tag, because many other commands may use the same type. 1063*90277196SAndroid Build Coastguard Worker # We could be more clever and reference count types, 1064*90277196SAndroid Build Coastguard Worker # instead of using a boolean. 1065*90277196SAndroid Build Coastguard Worker if required: 1066*90277196SAndroid Build Coastguard Worker # Look for <type> in entire <command> tree, 1067*90277196SAndroid Build Coastguard Worker # not just immediate children 1068*90277196SAndroid Build Coastguard Worker for type_elem in cmd.elem.findall('.//type'): 1069*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'markRequired: command implicitly requires dependent type', type_elem.text) 1070*90277196SAndroid Build Coastguard Worker self.markTypeRequired(type_elem.text, required) 1071*90277196SAndroid Build Coastguard Worker else: 1072*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'command:', cmdname, 'IS NOT DEFINED') 1073*90277196SAndroid Build Coastguard Worker 1074*90277196SAndroid Build Coastguard Worker def markRequired(self, featurename, feature, required): 1075*90277196SAndroid Build Coastguard Worker """Require or remove features specified in the Element. 1076*90277196SAndroid Build Coastguard Worker 1077*90277196SAndroid Build Coastguard Worker - featurename - name of the feature 1078*90277196SAndroid Build Coastguard Worker - feature - Element for `<require>` or `<remove>` tag 1079*90277196SAndroid Build Coastguard Worker - required - boolean (to tag features as required or not)""" 1080*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'markRequired (feature = <too long to print>, required =', required, ')') 1081*90277196SAndroid Build Coastguard Worker 1082*90277196SAndroid Build Coastguard Worker # Loop over types, enums, and commands in the tag 1083*90277196SAndroid Build Coastguard Worker # @@ It would be possible to respect 'api' and 'profile' attributes 1084*90277196SAndroid Build Coastguard Worker # in individual features, but that is not done yet. 1085*90277196SAndroid Build Coastguard Worker for typeElem in feature.findall('type'): 1086*90277196SAndroid Build Coastguard Worker self.markTypeRequired(typeElem.get('name'), required) 1087*90277196SAndroid Build Coastguard Worker for enumElem in feature.findall('enum'): 1088*90277196SAndroid Build Coastguard Worker self.markEnumRequired(enumElem.get('name'), required) 1089*90277196SAndroid Build Coastguard Worker 1090*90277196SAndroid Build Coastguard Worker for cmdElem in feature.findall('command'): 1091*90277196SAndroid Build Coastguard Worker self.markCmdRequired(cmdElem.get('name'), required) 1092*90277196SAndroid Build Coastguard Worker 1093*90277196SAndroid Build Coastguard Worker # Extensions may need to extend existing commands or other items in the future. 1094*90277196SAndroid Build Coastguard Worker # So, look for extend tags. 1095*90277196SAndroid Build Coastguard Worker for extendElem in feature.findall('extend'): 1096*90277196SAndroid Build Coastguard Worker extendType = extendElem.get('type') 1097*90277196SAndroid Build Coastguard Worker if extendType == 'command': 1098*90277196SAndroid Build Coastguard Worker commandName = extendElem.get('name') 1099*90277196SAndroid Build Coastguard Worker successExtends = extendElem.get('successcodes') 1100*90277196SAndroid Build Coastguard Worker if successExtends is not None: 1101*90277196SAndroid Build Coastguard Worker for success in successExtends.split(','): 1102*90277196SAndroid Build Coastguard Worker self.commandextensionsuccesses.append(self.commandextensiontuple(command=commandName, 1103*90277196SAndroid Build Coastguard Worker value=success, 1104*90277196SAndroid Build Coastguard Worker extension=featurename)) 1105*90277196SAndroid Build Coastguard Worker errorExtends = extendElem.get('errorcodes') 1106*90277196SAndroid Build Coastguard Worker if errorExtends is not None: 1107*90277196SAndroid Build Coastguard Worker for error in errorExtends.split(','): 1108*90277196SAndroid Build Coastguard Worker self.commandextensionerrors.append(self.commandextensiontuple(command=commandName, 1109*90277196SAndroid Build Coastguard Worker value=error, 1110*90277196SAndroid Build Coastguard Worker extension=featurename)) 1111*90277196SAndroid Build Coastguard Worker else: 1112*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'extend type:', extendType, 'IS NOT SUPPORTED') 1113*90277196SAndroid Build Coastguard Worker 1114*90277196SAndroid Build Coastguard Worker def getAlias(self, elem, dict): 1115*90277196SAndroid Build Coastguard Worker """Check for an alias in the same require block. 1116*90277196SAndroid Build Coastguard Worker 1117*90277196SAndroid Build Coastguard Worker - elem - Element to check for an alias""" 1118*90277196SAndroid Build Coastguard Worker 1119*90277196SAndroid Build Coastguard Worker # Try to find an alias 1120*90277196SAndroid Build Coastguard Worker alias = elem.get('alias') 1121*90277196SAndroid Build Coastguard Worker if alias is None: 1122*90277196SAndroid Build Coastguard Worker name = elem.get('name') 1123*90277196SAndroid Build Coastguard Worker typeinfo = self.lookupElementInfo(name, dict) 1124*90277196SAndroid Build Coastguard Worker if not typeinfo: 1125*90277196SAndroid Build Coastguard Worker self.gen.logMsg('error', name, 'is not a known name') 1126*90277196SAndroid Build Coastguard Worker alias = typeinfo.elem.get('alias') 1127*90277196SAndroid Build Coastguard Worker 1128*90277196SAndroid Build Coastguard Worker return alias 1129*90277196SAndroid Build Coastguard Worker 1130*90277196SAndroid Build Coastguard Worker def checkForCorrectionAliases(self, alias, require, tag): 1131*90277196SAndroid Build Coastguard Worker """Check for an alias in the same require block. 1132*90277196SAndroid Build Coastguard Worker 1133*90277196SAndroid Build Coastguard Worker - alias - String name of the alias 1134*90277196SAndroid Build Coastguard Worker - require - `<require>` block from the registry 1135*90277196SAndroid Build Coastguard Worker - tag - tag to look for in the require block""" 1136*90277196SAndroid Build Coastguard Worker 1137*90277196SAndroid Build Coastguard Worker # For the time being, the code below is bypassed. It has the effect 1138*90277196SAndroid Build Coastguard Worker # of excluding "spelling aliases" created to comply with the style 1139*90277196SAndroid Build Coastguard Worker # guide, but this leaves references out of the specification and 1140*90277196SAndroid Build Coastguard Worker # causes broken internal links. 1141*90277196SAndroid Build Coastguard Worker # 1142*90277196SAndroid Build Coastguard Worker # if alias and require.findall(tag + "[@name='" + alias + "']"): 1143*90277196SAndroid Build Coastguard Worker # return True 1144*90277196SAndroid Build Coastguard Worker 1145*90277196SAndroid Build Coastguard Worker return False 1146*90277196SAndroid Build Coastguard Worker 1147*90277196SAndroid Build Coastguard Worker def fillFeatureDictionary(self, interface, featurename, api, profile): 1148*90277196SAndroid Build Coastguard Worker """Capture added interfaces for a `<version>` or `<extension>`. 1149*90277196SAndroid Build Coastguard Worker 1150*90277196SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`, containing 1151*90277196SAndroid Build Coastguard Worker `<require>` and `<remove>` tags 1152*90277196SAndroid Build Coastguard Worker - featurename - name of the feature 1153*90277196SAndroid Build Coastguard Worker - api - string specifying API name being generated 1154*90277196SAndroid Build Coastguard Worker - profile - string specifying API profile being generated""" 1155*90277196SAndroid Build Coastguard Worker 1156*90277196SAndroid Build Coastguard Worker # Explicitly initialize known types - errors for unhandled categories 1157*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename] = { 1158*90277196SAndroid Build Coastguard Worker "enumconstant": {}, 1159*90277196SAndroid Build Coastguard Worker "command": {}, 1160*90277196SAndroid Build Coastguard Worker "enum": {}, 1161*90277196SAndroid Build Coastguard Worker "struct": {}, 1162*90277196SAndroid Build Coastguard Worker "handle": {}, 1163*90277196SAndroid Build Coastguard Worker "basetype": {}, 1164*90277196SAndroid Build Coastguard Worker "include": {}, 1165*90277196SAndroid Build Coastguard Worker "define": {}, 1166*90277196SAndroid Build Coastguard Worker "bitmask": {}, 1167*90277196SAndroid Build Coastguard Worker "union": {}, 1168*90277196SAndroid Build Coastguard Worker "funcpointer": {}, 1169*90277196SAndroid Build Coastguard Worker } 1170*90277196SAndroid Build Coastguard Worker 1171*90277196SAndroid Build Coastguard Worker # <require> marks things that are required by this version/profile 1172*90277196SAndroid Build Coastguard Worker for require in interface.findall('require'): 1173*90277196SAndroid Build Coastguard Worker if matchAPIProfile(api, profile, require): 1174*90277196SAndroid Build Coastguard Worker 1175*90277196SAndroid Build Coastguard Worker # Determine the required extension or version needed for a require block 1176*90277196SAndroid Build Coastguard Worker # Assumes that only one of these is specified 1177*90277196SAndroid Build Coastguard Worker # 'extension', and therefore 'required_key', may be a boolean 1178*90277196SAndroid Build Coastguard Worker # expression of extension names. 1179*90277196SAndroid Build Coastguard Worker # 'required_key' is used only as a dictionary key at 1180*90277196SAndroid Build Coastguard Worker # present, and passed through to the script generators, so 1181*90277196SAndroid Build Coastguard Worker # they must be prepared to parse that boolean expression. 1182*90277196SAndroid Build Coastguard Worker required_key = require.get('depends') 1183*90277196SAndroid Build Coastguard Worker 1184*90277196SAndroid Build Coastguard Worker # Loop over types, enums, and commands in the tag 1185*90277196SAndroid Build Coastguard Worker for typeElem in require.findall('type'): 1186*90277196SAndroid Build Coastguard Worker typename = typeElem.get('name') 1187*90277196SAndroid Build Coastguard Worker typeinfo = self.lookupElementInfo(typename, self.typedict) 1188*90277196SAndroid Build Coastguard Worker 1189*90277196SAndroid Build Coastguard Worker if typeinfo: 1190*90277196SAndroid Build Coastguard Worker # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible. 1191*90277196SAndroid Build Coastguard Worker alias = self.getAlias(typeElem, self.typedict) 1192*90277196SAndroid Build Coastguard Worker if not self.checkForCorrectionAliases(alias, require, 'type'): 1193*90277196SAndroid Build Coastguard Worker # Resolve the type info to the actual type, so we get an accurate read for 'structextends' 1194*90277196SAndroid Build Coastguard Worker while alias: 1195*90277196SAndroid Build Coastguard Worker typeinfo = self.lookupElementInfo(alias, self.typedict) 1196*90277196SAndroid Build Coastguard Worker if not typeinfo: 1197*90277196SAndroid Build Coastguard Worker raise RuntimeError(f"Missing alias {alias}") 1198*90277196SAndroid Build Coastguard Worker alias = typeinfo.elem.get('alias') 1199*90277196SAndroid Build Coastguard Worker 1200*90277196SAndroid Build Coastguard Worker typecat = typeinfo.elem.get('category') 1201*90277196SAndroid Build Coastguard Worker typeextends = typeinfo.elem.get('structextends') 1202*90277196SAndroid Build Coastguard Worker if not required_key in self.gen.featureDictionary[featurename][typecat]: 1203*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename][typecat][required_key] = {} 1204*90277196SAndroid Build Coastguard Worker if not typeextends in self.gen.featureDictionary[featurename][typecat][required_key]: 1205*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename][typecat][required_key][typeextends] = [] 1206*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename][typecat][required_key][typeextends].append(typename) 1207*90277196SAndroid Build Coastguard Worker else: 1208*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename)) 1209*90277196SAndroid Build Coastguard Worker 1210*90277196SAndroid Build Coastguard Worker 1211*90277196SAndroid Build Coastguard Worker for enumElem in require.findall('enum'): 1212*90277196SAndroid Build Coastguard Worker enumname = enumElem.get('name') 1213*90277196SAndroid Build Coastguard Worker typeinfo = self.lookupElementInfo(enumname, self.enumdict) 1214*90277196SAndroid Build Coastguard Worker 1215*90277196SAndroid Build Coastguard Worker # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible. 1216*90277196SAndroid Build Coastguard Worker alias = self.getAlias(enumElem, self.enumdict) 1217*90277196SAndroid Build Coastguard Worker if not self.checkForCorrectionAliases(alias, require, 'enum'): 1218*90277196SAndroid Build Coastguard Worker enumextends = enumElem.get('extends') 1219*90277196SAndroid Build Coastguard Worker if not required_key in self.gen.featureDictionary[featurename]['enumconstant']: 1220*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename]['enumconstant'][required_key] = {} 1221*90277196SAndroid Build Coastguard Worker if not enumextends in self.gen.featureDictionary[featurename]['enumconstant'][required_key]: 1222*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends] = [] 1223*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename]['enumconstant'][required_key][enumextends].append(enumname) 1224*90277196SAndroid Build Coastguard Worker else: 1225*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename)) 1226*90277196SAndroid Build Coastguard Worker 1227*90277196SAndroid Build Coastguard Worker for cmdElem in require.findall('command'): 1228*90277196SAndroid Build Coastguard Worker # Remove aliases in the same extension/feature; these are always added as a correction. Do not need the original to be visible. 1229*90277196SAndroid Build Coastguard Worker alias = self.getAlias(cmdElem, self.cmddict) 1230*90277196SAndroid Build Coastguard Worker if not self.checkForCorrectionAliases(alias, require, 'command'): 1231*90277196SAndroid Build Coastguard Worker if not required_key in self.gen.featureDictionary[featurename]['command']: 1232*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename]['command'][required_key] = [] 1233*90277196SAndroid Build Coastguard Worker self.gen.featureDictionary[featurename]['command'][required_key].append(cmdElem.get('name')) 1234*90277196SAndroid Build Coastguard Worker else: 1235*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'fillFeatureDictionary: NOT filling for {}'.format(typename)) 1236*90277196SAndroid Build Coastguard Worker 1237*90277196SAndroid Build Coastguard Worker def requireFeatures(self, interface, featurename, api, profile): 1238*90277196SAndroid Build Coastguard Worker """Process `<require>` tags for a `<version>` or `<extension>`. 1239*90277196SAndroid Build Coastguard Worker 1240*90277196SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`, containing 1241*90277196SAndroid Build Coastguard Worker `<require>` tags 1242*90277196SAndroid Build Coastguard Worker - featurename - name of the feature 1243*90277196SAndroid Build Coastguard Worker - api - string specifying API name being generated 1244*90277196SAndroid Build Coastguard Worker - profile - string specifying API profile being generated""" 1245*90277196SAndroid Build Coastguard Worker 1246*90277196SAndroid Build Coastguard Worker # <require> marks things that are required by this version/profile 1247*90277196SAndroid Build Coastguard Worker for feature in interface.findall('require'): 1248*90277196SAndroid Build Coastguard Worker if matchAPIProfile(api, profile, feature): 1249*90277196SAndroid Build Coastguard Worker self.markRequired(featurename, feature, True) 1250*90277196SAndroid Build Coastguard Worker 1251*90277196SAndroid Build Coastguard Worker def removeFeatures(self, interface, featurename, api, profile): 1252*90277196SAndroid Build Coastguard Worker """Process `<remove>` tags for a `<version>` or `<extension>`. 1253*90277196SAndroid Build Coastguard Worker 1254*90277196SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`, containing 1255*90277196SAndroid Build Coastguard Worker `<remove>` tags 1256*90277196SAndroid Build Coastguard Worker - featurename - name of the feature 1257*90277196SAndroid Build Coastguard Worker - api - string specifying API name being generated 1258*90277196SAndroid Build Coastguard Worker - profile - string specifying API profile being generated""" 1259*90277196SAndroid Build Coastguard Worker 1260*90277196SAndroid Build Coastguard Worker # <remove> marks things that are removed by this version/profile 1261*90277196SAndroid Build Coastguard Worker for feature in interface.findall('remove'): 1262*90277196SAndroid Build Coastguard Worker if matchAPIProfile(api, profile, feature): 1263*90277196SAndroid Build Coastguard Worker self.markRequired(featurename, feature, False) 1264*90277196SAndroid Build Coastguard Worker 1265*90277196SAndroid Build Coastguard Worker def assignAdditionalValidity(self, interface, api, profile): 1266*90277196SAndroid Build Coastguard Worker # Loop over all usage inside all <require> tags. 1267*90277196SAndroid Build Coastguard Worker for feature in interface.findall('require'): 1268*90277196SAndroid Build Coastguard Worker if matchAPIProfile(api, profile, feature): 1269*90277196SAndroid Build Coastguard Worker for v in feature.findall('usage'): 1270*90277196SAndroid Build Coastguard Worker if v.get('command'): 1271*90277196SAndroid Build Coastguard Worker self.cmddict[v.get('command')].additionalValidity.append(copy.deepcopy(v)) 1272*90277196SAndroid Build Coastguard Worker if v.get('struct'): 1273*90277196SAndroid Build Coastguard Worker self.typedict[v.get('struct')].additionalValidity.append(copy.deepcopy(v)) 1274*90277196SAndroid Build Coastguard Worker 1275*90277196SAndroid Build Coastguard Worker def removeAdditionalValidity(self, interface, api, profile): 1276*90277196SAndroid Build Coastguard Worker # Loop over all usage inside all <remove> tags. 1277*90277196SAndroid Build Coastguard Worker for feature in interface.findall('remove'): 1278*90277196SAndroid Build Coastguard Worker if matchAPIProfile(api, profile, feature): 1279*90277196SAndroid Build Coastguard Worker for v in feature.findall('usage'): 1280*90277196SAndroid Build Coastguard Worker if v.get('command'): 1281*90277196SAndroid Build Coastguard Worker self.cmddict[v.get('command')].removedValidity.append(copy.deepcopy(v)) 1282*90277196SAndroid Build Coastguard Worker if v.get('struct'): 1283*90277196SAndroid Build Coastguard Worker self.typedict[v.get('struct')].removedValidity.append(copy.deepcopy(v)) 1284*90277196SAndroid Build Coastguard Worker 1285*90277196SAndroid Build Coastguard Worker def generateFeature(self, fname, ftype, dictionary, explicit=False): 1286*90277196SAndroid Build Coastguard Worker """Generate a single type / enum group / enum / command, 1287*90277196SAndroid Build Coastguard Worker and all its dependencies as needed. 1288*90277196SAndroid Build Coastguard Worker 1289*90277196SAndroid Build Coastguard Worker - fname - name of feature (`<type>`/`<enum>`/`<command>`) 1290*90277196SAndroid Build Coastguard Worker - ftype - type of feature, 'type' | 'enum' | 'command' 1291*90277196SAndroid Build Coastguard Worker - dictionary - of *Info objects - self.{type|enum|cmd}dict 1292*90277196SAndroid Build Coastguard Worker - explicit - True if this is explicitly required by the top-level 1293*90277196SAndroid Build Coastguard Worker XML <require> tag, False if it is a dependency of an explicit 1294*90277196SAndroid Build Coastguard Worker requirement.""" 1295*90277196SAndroid Build Coastguard Worker 1296*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'generateFeature: generating', ftype, fname) 1297*90277196SAndroid Build Coastguard Worker 1298*90277196SAndroid Build Coastguard Worker if not (explicit or self.genOpts.requireDepends): 1299*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'generateFeature: NOT generating', ftype, fname, 'because generator does not require dependencies') 1300*90277196SAndroid Build Coastguard Worker return 1301*90277196SAndroid Build Coastguard Worker 1302*90277196SAndroid Build Coastguard Worker f = self.lookupElementInfo(fname, dictionary) 1303*90277196SAndroid Build Coastguard Worker if f is None: 1304*90277196SAndroid Build Coastguard Worker # No such feature. This is an error, but reported earlier 1305*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'No entry found for feature', fname, 1306*90277196SAndroid Build Coastguard Worker 'returning!') 1307*90277196SAndroid Build Coastguard Worker return 1308*90277196SAndroid Build Coastguard Worker 1309*90277196SAndroid Build Coastguard Worker # If feature is not required, or has already been declared, return 1310*90277196SAndroid Build Coastguard Worker if not f.required: 1311*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Skipping', ftype, fname, '(not required)') 1312*90277196SAndroid Build Coastguard Worker return 1313*90277196SAndroid Build Coastguard Worker if f.declared: 1314*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Skipping', ftype, fname, '(already declared)') 1315*90277196SAndroid Build Coastguard Worker return 1316*90277196SAndroid Build Coastguard Worker # Always mark feature declared, as though actually emitted 1317*90277196SAndroid Build Coastguard Worker f.declared = True 1318*90277196SAndroid Build Coastguard Worker 1319*90277196SAndroid Build Coastguard Worker # Determine if this is an alias, and of what, if so 1320*90277196SAndroid Build Coastguard Worker alias = f.elem.get('alias') 1321*90277196SAndroid Build Coastguard Worker if alias: 1322*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', fname, 'is an alias of', alias) 1323*90277196SAndroid Build Coastguard Worker 1324*90277196SAndroid Build Coastguard Worker # Pull in dependent declaration(s) of the feature. 1325*90277196SAndroid Build Coastguard Worker # For types, there may be one type in the 'requires' attribute of 1326*90277196SAndroid Build Coastguard Worker # the element, one in the 'alias' attribute, and many in 1327*90277196SAndroid Build Coastguard Worker # embedded <type> and <enum> tags within the element. 1328*90277196SAndroid Build Coastguard Worker # For commands, there may be many in <type> tags within the element. 1329*90277196SAndroid Build Coastguard Worker # For enums, no dependencies are allowed (though perhaps if you 1330*90277196SAndroid Build Coastguard Worker # have a uint64 enum, it should require that type). 1331*90277196SAndroid Build Coastguard Worker genProc = None 1332*90277196SAndroid Build Coastguard Worker followupFeature = None 1333*90277196SAndroid Build Coastguard Worker if ftype == 'type': 1334*90277196SAndroid Build Coastguard Worker genProc = self.gen.genType 1335*90277196SAndroid Build Coastguard Worker 1336*90277196SAndroid Build Coastguard Worker # Generate type dependencies in 'alias' and 'requires' attributes 1337*90277196SAndroid Build Coastguard Worker if alias: 1338*90277196SAndroid Build Coastguard Worker self.generateFeature(alias, 'type', self.typedict) 1339*90277196SAndroid Build Coastguard Worker requires = f.elem.get('requires') 1340*90277196SAndroid Build Coastguard Worker if requires: 1341*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating required dependent type', 1342*90277196SAndroid Build Coastguard Worker requires) 1343*90277196SAndroid Build Coastguard Worker self.generateFeature(requires, 'type', self.typedict) 1344*90277196SAndroid Build Coastguard Worker 1345*90277196SAndroid Build Coastguard Worker # Generate types used in defining this type (e.g. in nested 1346*90277196SAndroid Build Coastguard Worker # <type> tags) 1347*90277196SAndroid Build Coastguard Worker # Look for <type> in entire <command> tree, 1348*90277196SAndroid Build Coastguard Worker # not just immediate children 1349*90277196SAndroid Build Coastguard Worker for subtype in f.elem.findall('.//type'): 1350*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating required dependent <type>', 1351*90277196SAndroid Build Coastguard Worker subtype.text) 1352*90277196SAndroid Build Coastguard Worker self.generateFeature(subtype.text, 'type', self.typedict) 1353*90277196SAndroid Build Coastguard Worker 1354*90277196SAndroid Build Coastguard Worker # Generate enums used in defining this type, for example in 1355*90277196SAndroid Build Coastguard Worker # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member> 1356*90277196SAndroid Build Coastguard Worker for subtype in f.elem.findall('.//enum'): 1357*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating required dependent <enum>', 1358*90277196SAndroid Build Coastguard Worker subtype.text) 1359*90277196SAndroid Build Coastguard Worker self.generateFeature(subtype.text, 'enum', self.enumdict) 1360*90277196SAndroid Build Coastguard Worker 1361*90277196SAndroid Build Coastguard Worker # If the type is an enum group, look up the corresponding 1362*90277196SAndroid Build Coastguard Worker # group in the group dictionary and generate that instead. 1363*90277196SAndroid Build Coastguard Worker if f.elem.get('category') == 'enum': 1364*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Type', fname, 'is an enum group, so generate that instead') 1365*90277196SAndroid Build Coastguard Worker group = self.lookupElementInfo(fname, self.groupdict) 1366*90277196SAndroid Build Coastguard Worker if alias is not None: 1367*90277196SAndroid Build Coastguard Worker # An alias of another group name. 1368*90277196SAndroid Build Coastguard Worker # Pass to genGroup with 'alias' parameter = aliased name 1369*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating alias', fname, 1370*90277196SAndroid Build Coastguard Worker 'for enumerated type', alias) 1371*90277196SAndroid Build Coastguard Worker # Now, pass the *aliased* GroupInfo to the genGroup, but 1372*90277196SAndroid Build Coastguard Worker # with an additional parameter which is the alias name. 1373*90277196SAndroid Build Coastguard Worker genProc = self.gen.genGroup 1374*90277196SAndroid Build Coastguard Worker f = self.lookupElementInfo(alias, self.groupdict) 1375*90277196SAndroid Build Coastguard Worker elif group is None: 1376*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'Skipping enum type', fname, 1377*90277196SAndroid Build Coastguard Worker ': No matching enumerant group') 1378*90277196SAndroid Build Coastguard Worker return 1379*90277196SAndroid Build Coastguard Worker else: 1380*90277196SAndroid Build Coastguard Worker genProc = self.gen.genGroup 1381*90277196SAndroid Build Coastguard Worker f = group 1382*90277196SAndroid Build Coastguard Worker 1383*90277196SAndroid Build Coastguard Worker # @ The enum group is not ready for generation. At this 1384*90277196SAndroid Build Coastguard Worker # @ point, it contains all <enum> tags injected by 1385*90277196SAndroid Build Coastguard Worker # @ <extension> tags without any verification of whether 1386*90277196SAndroid Build Coastguard Worker # @ they are required or not. It may also contain 1387*90277196SAndroid Build Coastguard Worker # @ duplicates injected by multiple consistent 1388*90277196SAndroid Build Coastguard Worker # @ definitions of an <enum>. 1389*90277196SAndroid Build Coastguard Worker 1390*90277196SAndroid Build Coastguard Worker # @ Pass over each enum, marking its enumdict[] entry as 1391*90277196SAndroid Build Coastguard Worker # @ required or not. Mark aliases of enums as required, 1392*90277196SAndroid Build Coastguard Worker # @ too. 1393*90277196SAndroid Build Coastguard Worker 1394*90277196SAndroid Build Coastguard Worker enums = group.elem.findall('enum') 1395*90277196SAndroid Build Coastguard Worker 1396*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'generateFeature: checking enums for group', fname) 1397*90277196SAndroid Build Coastguard Worker 1398*90277196SAndroid Build Coastguard Worker # Check for required enums, including aliases 1399*90277196SAndroid Build Coastguard Worker # LATER - Check for, report, and remove duplicates? 1400*90277196SAndroid Build Coastguard Worker enumAliases = [] 1401*90277196SAndroid Build Coastguard Worker for elem in enums: 1402*90277196SAndroid Build Coastguard Worker name = elem.get('name') 1403*90277196SAndroid Build Coastguard Worker 1404*90277196SAndroid Build Coastguard Worker required = False 1405*90277196SAndroid Build Coastguard Worker 1406*90277196SAndroid Build Coastguard Worker extname = elem.get('extname') 1407*90277196SAndroid Build Coastguard Worker version = elem.get('version') 1408*90277196SAndroid Build Coastguard Worker if extname is not None: 1409*90277196SAndroid Build Coastguard Worker # 'supported' attribute was injected when the <enum> element was 1410*90277196SAndroid Build Coastguard Worker # moved into the <enums> group in Registry.parseTree() 1411*90277196SAndroid Build Coastguard Worker supported_list = elem.get('supported').split(",") 1412*90277196SAndroid Build Coastguard Worker if self.genOpts.defaultExtensions in supported_list: 1413*90277196SAndroid Build Coastguard Worker required = True 1414*90277196SAndroid Build Coastguard Worker elif re.match(self.genOpts.addExtensions, extname) is not None: 1415*90277196SAndroid Build Coastguard Worker required = True 1416*90277196SAndroid Build Coastguard Worker elif version is not None: 1417*90277196SAndroid Build Coastguard Worker required = re.match(self.genOpts.emitversions, version) is not None 1418*90277196SAndroid Build Coastguard Worker else: 1419*90277196SAndroid Build Coastguard Worker required = True 1420*90277196SAndroid Build Coastguard Worker 1421*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', '* required =', required, 'for', name) 1422*90277196SAndroid Build Coastguard Worker if required: 1423*90277196SAndroid Build Coastguard Worker # Mark this element as required (in the element, not the EnumInfo) 1424*90277196SAndroid Build Coastguard Worker elem.set('required', 'true') 1425*90277196SAndroid Build Coastguard Worker # If it is an alias, track that for later use 1426*90277196SAndroid Build Coastguard Worker enumAlias = elem.get('alias') 1427*90277196SAndroid Build Coastguard Worker if enumAlias: 1428*90277196SAndroid Build Coastguard Worker enumAliases.append(enumAlias) 1429*90277196SAndroid Build Coastguard Worker for elem in enums: 1430*90277196SAndroid Build Coastguard Worker name = elem.get('name') 1431*90277196SAndroid Build Coastguard Worker if name in enumAliases: 1432*90277196SAndroid Build Coastguard Worker elem.set('required', 'true') 1433*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', '* also need to require alias', name) 1434*90277196SAndroid Build Coastguard Worker if f is None: 1435*90277196SAndroid Build Coastguard Worker raise RuntimeError("Should not get here") 1436*90277196SAndroid Build Coastguard Worker if f.elem.get('category') == 'bitmask': 1437*90277196SAndroid Build Coastguard Worker followupFeature = f.elem.get('bitvalues') 1438*90277196SAndroid Build Coastguard Worker elif ftype == 'command': 1439*90277196SAndroid Build Coastguard Worker # Generate command dependencies in 'alias' attribute 1440*90277196SAndroid Build Coastguard Worker if alias: 1441*90277196SAndroid Build Coastguard Worker self.generateFeature(alias, 'command', self.cmddict) 1442*90277196SAndroid Build Coastguard Worker 1443*90277196SAndroid Build Coastguard Worker genProc = self.gen.genCmd 1444*90277196SAndroid Build Coastguard Worker for type_elem in f.elem.findall('.//type'): 1445*90277196SAndroid Build Coastguard Worker depname = type_elem.text 1446*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating required parameter type', 1447*90277196SAndroid Build Coastguard Worker depname) 1448*90277196SAndroid Build Coastguard Worker self.generateFeature(depname, 'type', self.typedict) 1449*90277196SAndroid Build Coastguard Worker elif ftype == 'enum': 1450*90277196SAndroid Build Coastguard Worker # Generate enum dependencies in 'alias' attribute 1451*90277196SAndroid Build Coastguard Worker if alias: 1452*90277196SAndroid Build Coastguard Worker self.generateFeature(alias, 'enum', self.enumdict) 1453*90277196SAndroid Build Coastguard Worker genProc = self.gen.genEnum 1454*90277196SAndroid Build Coastguard Worker 1455*90277196SAndroid Build Coastguard Worker # Actually generate the type only if emitting declarations 1456*90277196SAndroid Build Coastguard Worker if self.emitFeatures: 1457*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Emitting', ftype, 'decl for', fname) 1458*90277196SAndroid Build Coastguard Worker if genProc is None: 1459*90277196SAndroid Build Coastguard Worker raise RuntimeError("genProc is None when we should be emitting") 1460*90277196SAndroid Build Coastguard Worker genProc(f, fname, alias) 1461*90277196SAndroid Build Coastguard Worker else: 1462*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Skipping', ftype, fname, 1463*90277196SAndroid Build Coastguard Worker '(should not be emitted)') 1464*90277196SAndroid Build Coastguard Worker 1465*90277196SAndroid Build Coastguard Worker if followupFeature: 1466*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Generating required bitvalues <enum>', 1467*90277196SAndroid Build Coastguard Worker followupFeature) 1468*90277196SAndroid Build Coastguard Worker self.generateFeature(followupFeature, "type", self.typedict) 1469*90277196SAndroid Build Coastguard Worker 1470*90277196SAndroid Build Coastguard Worker def generateRequiredInterface(self, interface): 1471*90277196SAndroid Build Coastguard Worker """Generate all interfaces required by an API version or extension. 1472*90277196SAndroid Build Coastguard Worker 1473*90277196SAndroid Build Coastguard Worker - interface - Element for `<version>` or `<extension>`""" 1474*90277196SAndroid Build Coastguard Worker 1475*90277196SAndroid Build Coastguard Worker # Loop over all features inside all <require> tags. 1476*90277196SAndroid Build Coastguard Worker for features in interface.findall('require'): 1477*90277196SAndroid Build Coastguard Worker for t in features.findall('type'): 1478*90277196SAndroid Build Coastguard Worker self.generateFeature(t.get('name'), 'type', self.typedict, explicit=True) 1479*90277196SAndroid Build Coastguard Worker for e in features.findall('enum'): 1480*90277196SAndroid Build Coastguard Worker # If this is an enum extending an enumerated type, do not 1481*90277196SAndroid Build Coastguard Worker # generate it - this has already been done in reg.parseTree, 1482*90277196SAndroid Build Coastguard Worker # by copying this element into the enumerated type. 1483*90277196SAndroid Build Coastguard Worker enumextends = e.get('extends') 1484*90277196SAndroid Build Coastguard Worker if not enumextends: 1485*90277196SAndroid Build Coastguard Worker self.generateFeature(e.get('name'), 'enum', self.enumdict, explicit=True) 1486*90277196SAndroid Build Coastguard Worker for c in features.findall('command'): 1487*90277196SAndroid Build Coastguard Worker self.generateFeature(c.get('name'), 'command', self.cmddict, explicit=True) 1488*90277196SAndroid Build Coastguard Worker 1489*90277196SAndroid Build Coastguard Worker def generateSpirv(self, spirv, dictionary): 1490*90277196SAndroid Build Coastguard Worker if spirv is None: 1491*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'No entry found for element', name, 1492*90277196SAndroid Build Coastguard Worker 'returning!') 1493*90277196SAndroid Build Coastguard Worker return 1494*90277196SAndroid Build Coastguard Worker 1495*90277196SAndroid Build Coastguard Worker name = spirv.elem.get('name') 1496*90277196SAndroid Build Coastguard Worker # No known alias for spirv elements 1497*90277196SAndroid Build Coastguard Worker alias = None 1498*90277196SAndroid Build Coastguard Worker if spirv.emit: 1499*90277196SAndroid Build Coastguard Worker genProc = self.gen.genSpirv 1500*90277196SAndroid Build Coastguard Worker genProc(spirv, name, alias) 1501*90277196SAndroid Build Coastguard Worker 1502*90277196SAndroid Build Coastguard Worker def stripUnsupportedAPIs(self, dictionary, attribute, supportedDictionary): 1503*90277196SAndroid Build Coastguard Worker """Strip unsupported APIs from attributes of APIs. 1504*90277196SAndroid Build Coastguard Worker dictionary - *Info dictionary of APIs to be updated 1505*90277196SAndroid Build Coastguard Worker attribute - attribute name to look for in each API 1506*90277196SAndroid Build Coastguard Worker supportedDictionary - dictionary in which to look for supported 1507*90277196SAndroid Build Coastguard Worker API elements in the attribute""" 1508*90277196SAndroid Build Coastguard Worker 1509*90277196SAndroid Build Coastguard Worker for key in dictionary: 1510*90277196SAndroid Build Coastguard Worker eleminfo = dictionary[key] 1511*90277196SAndroid Build Coastguard Worker attribstring = eleminfo.elem.get(attribute) 1512*90277196SAndroid Build Coastguard Worker if attribstring is not None: 1513*90277196SAndroid Build Coastguard Worker apis = [] 1514*90277196SAndroid Build Coastguard Worker stripped = False 1515*90277196SAndroid Build Coastguard Worker for api in attribstring.split(','): 1516*90277196SAndroid Build Coastguard Worker ##print('Checking API {} referenced by {}'.format(api, key)) 1517*90277196SAndroid Build Coastguard Worker if api in supportedDictionary and supportedDictionary[api].required: 1518*90277196SAndroid Build Coastguard Worker apis.append(api) 1519*90277196SAndroid Build Coastguard Worker else: 1520*90277196SAndroid Build Coastguard Worker stripped = True 1521*90277196SAndroid Build Coastguard Worker ##print('\t**STRIPPING API {} from {}'.format(api, key)) 1522*90277196SAndroid Build Coastguard Worker 1523*90277196SAndroid Build Coastguard Worker # Update the attribute after stripping stuff. 1524*90277196SAndroid Build Coastguard Worker # Could sort apis before joining, but it is not a clear win 1525*90277196SAndroid Build Coastguard Worker if stripped: 1526*90277196SAndroid Build Coastguard Worker eleminfo.elem.set(attribute, ','.join(apis)) 1527*90277196SAndroid Build Coastguard Worker 1528*90277196SAndroid Build Coastguard Worker def stripUnsupportedAPIsFromList(self, dictionary, supportedDictionary): 1529*90277196SAndroid Build Coastguard Worker """Strip unsupported APIs from attributes of APIs. 1530*90277196SAndroid Build Coastguard Worker dictionary - dictionary of list of structure name strings 1531*90277196SAndroid Build Coastguard Worker supportedDictionary - dictionary in which to look for supported 1532*90277196SAndroid Build Coastguard Worker API elements in the attribute""" 1533*90277196SAndroid Build Coastguard Worker 1534*90277196SAndroid Build Coastguard Worker for key in dictionary: 1535*90277196SAndroid Build Coastguard Worker attribstring = dictionary[key] 1536*90277196SAndroid Build Coastguard Worker if attribstring is not None: 1537*90277196SAndroid Build Coastguard Worker apis = [] 1538*90277196SAndroid Build Coastguard Worker stripped = False 1539*90277196SAndroid Build Coastguard Worker for api in attribstring: 1540*90277196SAndroid Build Coastguard Worker ##print('Checking API {} referenced by {}'.format(api, key)) 1541*90277196SAndroid Build Coastguard Worker if supportedDictionary[api].required: 1542*90277196SAndroid Build Coastguard Worker apis.append(api) 1543*90277196SAndroid Build Coastguard Worker else: 1544*90277196SAndroid Build Coastguard Worker stripped = True 1545*90277196SAndroid Build Coastguard Worker ##print('\t**STRIPPING API {} from {}'.format(api, key)) 1546*90277196SAndroid Build Coastguard Worker 1547*90277196SAndroid Build Coastguard Worker # Update the attribute after stripping stuff. 1548*90277196SAndroid Build Coastguard Worker # Could sort apis before joining, but it is not a clear win 1549*90277196SAndroid Build Coastguard Worker if stripped: 1550*90277196SAndroid Build Coastguard Worker dictionary[key] = apis 1551*90277196SAndroid Build Coastguard Worker 1552*90277196SAndroid Build Coastguard Worker def generateFormat(self, format, dictionary): 1553*90277196SAndroid Build Coastguard Worker if format is None: 1554*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'No entry found for format element', 1555*90277196SAndroid Build Coastguard Worker 'returning!') 1556*90277196SAndroid Build Coastguard Worker return 1557*90277196SAndroid Build Coastguard Worker 1558*90277196SAndroid Build Coastguard Worker name = format.elem.get('name') 1559*90277196SAndroid Build Coastguard Worker # No known alias for VkFormat elements 1560*90277196SAndroid Build Coastguard Worker alias = None 1561*90277196SAndroid Build Coastguard Worker if format.emit: 1562*90277196SAndroid Build Coastguard Worker genProc = self.gen.genFormat 1563*90277196SAndroid Build Coastguard Worker genProc(format, name, alias) 1564*90277196SAndroid Build Coastguard Worker 1565*90277196SAndroid Build Coastguard Worker def generateSyncStage(self, sync): 1566*90277196SAndroid Build Coastguard Worker genProc = self.gen.genSyncStage 1567*90277196SAndroid Build Coastguard Worker genProc(sync) 1568*90277196SAndroid Build Coastguard Worker 1569*90277196SAndroid Build Coastguard Worker def generateSyncAccess(self, sync): 1570*90277196SAndroid Build Coastguard Worker genProc = self.gen.genSyncAccess 1571*90277196SAndroid Build Coastguard Worker genProc(sync) 1572*90277196SAndroid Build Coastguard Worker 1573*90277196SAndroid Build Coastguard Worker def generateSyncPipeline(self, sync): 1574*90277196SAndroid Build Coastguard Worker genProc = self.gen.genSyncPipeline 1575*90277196SAndroid Build Coastguard Worker genProc(sync) 1576*90277196SAndroid Build Coastguard Worker 1577*90277196SAndroid Build Coastguard Worker def tagValidExtensionStructs(self): 1578*90277196SAndroid Build Coastguard Worker """Construct a "validextensionstructs" list for parent structures 1579*90277196SAndroid Build Coastguard Worker based on "structextends" tags in child structures. 1580*90277196SAndroid Build Coastguard Worker Only do this for structures tagged as required.""" 1581*90277196SAndroid Build Coastguard Worker 1582*90277196SAndroid Build Coastguard Worker for typeinfo in self.typedict.values(): 1583*90277196SAndroid Build Coastguard Worker type_elem = typeinfo.elem 1584*90277196SAndroid Build Coastguard Worker if typeinfo.required and type_elem.get('category') == 'struct': 1585*90277196SAndroid Build Coastguard Worker struct_extends = type_elem.get('structextends') 1586*90277196SAndroid Build Coastguard Worker if struct_extends is not None: 1587*90277196SAndroid Build Coastguard Worker for parent in struct_extends.split(','): 1588*90277196SAndroid Build Coastguard Worker # self.gen.logMsg('diag', type_elem.get('name'), 'extends', parent) 1589*90277196SAndroid Build Coastguard Worker self.validextensionstructs[parent].append(type_elem.get('name')) 1590*90277196SAndroid Build Coastguard Worker 1591*90277196SAndroid Build Coastguard Worker # Sort the lists so they do not depend on the XML order 1592*90277196SAndroid Build Coastguard Worker for parent in self.validextensionstructs: 1593*90277196SAndroid Build Coastguard Worker self.validextensionstructs[parent].sort() 1594*90277196SAndroid Build Coastguard Worker 1595*90277196SAndroid Build Coastguard Worker def apiGen(self): 1596*90277196SAndroid Build Coastguard Worker """Generate interface for specified versions using the current 1597*90277196SAndroid Build Coastguard Worker generator and generator options""" 1598*90277196SAndroid Build Coastguard Worker 1599*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', '*******************************************') 1600*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', ' Registry.apiGen file:', self.genOpts.filename, 1601*90277196SAndroid Build Coastguard Worker 'api:', self.genOpts.apiname, 1602*90277196SAndroid Build Coastguard Worker 'profile:', self.genOpts.profile) 1603*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', '*******************************************') 1604*90277196SAndroid Build Coastguard Worker 1605*90277196SAndroid Build Coastguard Worker # Could reset required/declared flags for all features here. 1606*90277196SAndroid Build Coastguard Worker # This has been removed as never used. The initial motivation was 1607*90277196SAndroid Build Coastguard Worker # the idea of calling apiGen() repeatedly for different targets, but 1608*90277196SAndroid Build Coastguard Worker # this has never been done. The 20% or so build-time speedup that 1609*90277196SAndroid Build Coastguard Worker # might result is not worth the effort to make it actually work. 1610*90277196SAndroid Build Coastguard Worker # 1611*90277196SAndroid Build Coastguard Worker # self.apiReset() 1612*90277196SAndroid Build Coastguard Worker 1613*90277196SAndroid Build Coastguard Worker # Compile regexps used to select versions & extensions 1614*90277196SAndroid Build Coastguard Worker regVersions = re.compile(self.genOpts.versions) 1615*90277196SAndroid Build Coastguard Worker regEmitVersions = re.compile(self.genOpts.emitversions) 1616*90277196SAndroid Build Coastguard Worker regAddExtensions = re.compile(self.genOpts.addExtensions) 1617*90277196SAndroid Build Coastguard Worker regRemoveExtensions = re.compile(self.genOpts.removeExtensions) 1618*90277196SAndroid Build Coastguard Worker regEmitExtensions = re.compile(self.genOpts.emitExtensions) 1619*90277196SAndroid Build Coastguard Worker regEmitSpirv = re.compile(self.genOpts.emitSpirv) 1620*90277196SAndroid Build Coastguard Worker regEmitFormats = re.compile(self.genOpts.emitFormats) 1621*90277196SAndroid Build Coastguard Worker 1622*90277196SAndroid Build Coastguard Worker # Get all matching API feature names & add to list of FeatureInfo 1623*90277196SAndroid Build Coastguard Worker # Note we used to select on feature version attributes, not names. 1624*90277196SAndroid Build Coastguard Worker features = [] 1625*90277196SAndroid Build Coastguard Worker apiMatch = False 1626*90277196SAndroid Build Coastguard Worker for key in self.apidict: 1627*90277196SAndroid Build Coastguard Worker fi = self.apidict[key] 1628*90277196SAndroid Build Coastguard Worker api = fi.elem.get('api') 1629*90277196SAndroid Build Coastguard Worker if apiNameMatch(self.genOpts.apiname, api): 1630*90277196SAndroid Build Coastguard Worker apiMatch = True 1631*90277196SAndroid Build Coastguard Worker if regVersions.match(fi.name): 1632*90277196SAndroid Build Coastguard Worker # Matches API & version #s being generated. Mark for 1633*90277196SAndroid Build Coastguard Worker # emission and add to the features[] list . 1634*90277196SAndroid Build Coastguard Worker # @@ Could use 'declared' instead of 'emit'? 1635*90277196SAndroid Build Coastguard Worker fi.emit = (regEmitVersions.match(fi.name) is not None) 1636*90277196SAndroid Build Coastguard Worker features.append(fi) 1637*90277196SAndroid Build Coastguard Worker if not fi.emit: 1638*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'NOT tagging feature api =', api, 1639*90277196SAndroid Build Coastguard Worker 'name =', fi.name, 'version =', fi.version, 1640*90277196SAndroid Build Coastguard Worker 'for emission (does not match emitversions pattern)') 1641*90277196SAndroid Build Coastguard Worker else: 1642*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Including feature api =', api, 1643*90277196SAndroid Build Coastguard Worker 'name =', fi.name, 'version =', fi.version, 1644*90277196SAndroid Build Coastguard Worker 'for emission (matches emitversions pattern)') 1645*90277196SAndroid Build Coastguard Worker else: 1646*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'NOT including feature api =', api, 1647*90277196SAndroid Build Coastguard Worker 'name =', fi.name, 'version =', fi.version, 1648*90277196SAndroid Build Coastguard Worker '(does not match requested versions)') 1649*90277196SAndroid Build Coastguard Worker else: 1650*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'NOT including feature api =', api, 1651*90277196SAndroid Build Coastguard Worker 'name =', fi.name, 1652*90277196SAndroid Build Coastguard Worker '(does not match requested API)') 1653*90277196SAndroid Build Coastguard Worker if not apiMatch: 1654*90277196SAndroid Build Coastguard Worker self.gen.logMsg('warn', 'No matching API versions found!') 1655*90277196SAndroid Build Coastguard Worker 1656*90277196SAndroid Build Coastguard Worker # Get all matching extensions, in order by their extension number, 1657*90277196SAndroid Build Coastguard Worker # and add to the list of features. 1658*90277196SAndroid Build Coastguard Worker # Start with extensions whose 'supported' attributes match the API 1659*90277196SAndroid Build Coastguard Worker # being generated. Add extensions matching the pattern specified in 1660*90277196SAndroid Build Coastguard Worker # regExtensions, then remove extensions matching the pattern 1661*90277196SAndroid Build Coastguard Worker # specified in regRemoveExtensions 1662*90277196SAndroid 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'): 1663*90277196SAndroid Build Coastguard Worker extName = ei.name 1664*90277196SAndroid Build Coastguard Worker include = False 1665*90277196SAndroid Build Coastguard Worker 1666*90277196SAndroid Build Coastguard Worker # Include extension if defaultExtensions is not None and is 1667*90277196SAndroid Build Coastguard Worker # exactly matched by the 'supported' attribute. 1668*90277196SAndroid Build Coastguard Worker if apiNameMatch(self.genOpts.defaultExtensions, 1669*90277196SAndroid Build Coastguard Worker ei.elem.get('supported')): 1670*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Including extension', 1671*90277196SAndroid Build Coastguard Worker extName, "(defaultExtensions matches the 'supported' attribute)") 1672*90277196SAndroid Build Coastguard Worker include = True 1673*90277196SAndroid Build Coastguard Worker 1674*90277196SAndroid Build Coastguard Worker # Include additional extensions if the extension name matches 1675*90277196SAndroid Build Coastguard Worker # the regexp specified in the generator options. This allows 1676*90277196SAndroid Build Coastguard Worker # forcing extensions into an interface even if they are not 1677*90277196SAndroid Build Coastguard Worker # tagged appropriately in the registry. 1678*90277196SAndroid Build Coastguard Worker # However, we still respect the 'supported' attribute. 1679*90277196SAndroid Build Coastguard Worker if regAddExtensions.match(extName) is not None: 1680*90277196SAndroid Build Coastguard Worker if not apiNameMatch(self.genOpts.apiname, ei.elem.get('supported')): 1681*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'NOT including extension', 1682*90277196SAndroid Build Coastguard Worker extName, '(matches explicitly requested, but does not match the \'supported\' attribute)') 1683*90277196SAndroid Build Coastguard Worker include = False 1684*90277196SAndroid Build Coastguard Worker else: 1685*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Including extension', 1686*90277196SAndroid Build Coastguard Worker extName, '(matches explicitly requested extensions to add)') 1687*90277196SAndroid Build Coastguard Worker include = True 1688*90277196SAndroid Build Coastguard Worker # Remove extensions if the name matches the regexp specified 1689*90277196SAndroid Build Coastguard Worker # in generator options. This allows forcing removal of 1690*90277196SAndroid Build Coastguard Worker # extensions from an interface even if they are tagged that 1691*90277196SAndroid Build Coastguard Worker # way in the registry. 1692*90277196SAndroid Build Coastguard Worker if regRemoveExtensions.match(extName) is not None: 1693*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'Removing extension', 1694*90277196SAndroid Build Coastguard Worker extName, '(matches explicitly requested extensions to remove)') 1695*90277196SAndroid Build Coastguard Worker include = False 1696*90277196SAndroid Build Coastguard Worker 1697*90277196SAndroid Build Coastguard Worker # If the extension is to be included, add it to the 1698*90277196SAndroid Build Coastguard Worker # extension features list. 1699*90277196SAndroid Build Coastguard Worker if include: 1700*90277196SAndroid Build Coastguard Worker ei.emit = (regEmitExtensions.match(extName) is not None) 1701*90277196SAndroid Build Coastguard Worker features.append(ei) 1702*90277196SAndroid Build Coastguard Worker if not ei.emit: 1703*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'NOT tagging extension', 1704*90277196SAndroid Build Coastguard Worker extName, 1705*90277196SAndroid Build Coastguard Worker 'for emission (does not match emitextensions pattern)') 1706*90277196SAndroid Build Coastguard Worker 1707*90277196SAndroid Build Coastguard Worker # Hack - can be removed when validity generator goes away 1708*90277196SAndroid Build Coastguard Worker # (Jon) I am not sure what this does, or if it should 1709*90277196SAndroid Build Coastguard Worker # respect the ei.emit flag above. 1710*90277196SAndroid Build Coastguard Worker self.requiredextensions.append(extName) 1711*90277196SAndroid Build Coastguard Worker else: 1712*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'NOT including extension', 1713*90277196SAndroid Build Coastguard Worker extName, '(does not match api attribute or explicitly requested extensions)') 1714*90277196SAndroid Build Coastguard Worker 1715*90277196SAndroid Build Coastguard Worker # Add all spirv elements to list 1716*90277196SAndroid Build Coastguard Worker # generators decide to emit them all or not 1717*90277196SAndroid Build Coastguard Worker # Currently no filtering as no client of these elements needs filtering 1718*90277196SAndroid Build Coastguard Worker spirvexts = [] 1719*90277196SAndroid Build Coastguard Worker for key in self.spirvextdict: 1720*90277196SAndroid Build Coastguard Worker si = self.spirvextdict[key] 1721*90277196SAndroid Build Coastguard Worker si.emit = (regEmitSpirv.match(key) is not None) 1722*90277196SAndroid Build Coastguard Worker spirvexts.append(si) 1723*90277196SAndroid Build Coastguard Worker spirvcaps = [] 1724*90277196SAndroid Build Coastguard Worker for key in self.spirvcapdict: 1725*90277196SAndroid Build Coastguard Worker si = self.spirvcapdict[key] 1726*90277196SAndroid Build Coastguard Worker si.emit = (regEmitSpirv.match(key) is not None) 1727*90277196SAndroid Build Coastguard Worker spirvcaps.append(si) 1728*90277196SAndroid Build Coastguard Worker 1729*90277196SAndroid Build Coastguard Worker formats = [] 1730*90277196SAndroid Build Coastguard Worker for key in self.formatsdict: 1731*90277196SAndroid Build Coastguard Worker si = self.formatsdict[key] 1732*90277196SAndroid Build Coastguard Worker si.emit = (regEmitFormats.match(key) is not None) 1733*90277196SAndroid Build Coastguard Worker formats.append(si) 1734*90277196SAndroid Build Coastguard Worker 1735*90277196SAndroid Build Coastguard Worker # Sort the features list, if a sort procedure is defined 1736*90277196SAndroid Build Coastguard Worker if self.genOpts.sortProcedure: 1737*90277196SAndroid Build Coastguard Worker self.genOpts.sortProcedure(features) 1738*90277196SAndroid Build Coastguard Worker 1739*90277196SAndroid Build Coastguard Worker # Passes 1+2: loop over requested API versions and extensions tagging 1740*90277196SAndroid Build Coastguard Worker # types/commands/features as required (in an <require> block) or no 1741*90277196SAndroid Build Coastguard Worker # longer required (in an <remove> block). <remove>s are processed 1742*90277196SAndroid Build Coastguard Worker # after all <require>s, so removals win. 1743*90277196SAndroid Build Coastguard Worker # If a profile other than 'None' is being generated, it must 1744*90277196SAndroid Build Coastguard Worker # match the profile attribute (if any) of the <require> and 1745*90277196SAndroid Build Coastguard Worker # <remove> tags. 1746*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'PASS 1: TAG FEATURES') 1747*90277196SAndroid Build Coastguard Worker for f in features: 1748*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'PASS 1: Tagging required and features for', f.name) 1749*90277196SAndroid Build Coastguard Worker self.fillFeatureDictionary(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile) 1750*90277196SAndroid Build Coastguard Worker self.requireFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile) 1751*90277196SAndroid Build Coastguard Worker self.assignAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile) 1752*90277196SAndroid Build Coastguard Worker 1753*90277196SAndroid Build Coastguard Worker for f in features: 1754*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'PASS 2: Tagging removed features for', f.name) 1755*90277196SAndroid Build Coastguard Worker self.removeFeatures(f.elem, f.name, self.genOpts.apiname, self.genOpts.profile) 1756*90277196SAndroid Build Coastguard Worker self.removeAdditionalValidity(f.elem, self.genOpts.apiname, self.genOpts.profile) 1757*90277196SAndroid Build Coastguard Worker 1758*90277196SAndroid Build Coastguard Worker # Now, strip references to APIs that are not required. 1759*90277196SAndroid Build Coastguard Worker # At present such references may occur in: 1760*90277196SAndroid Build Coastguard Worker # Structs in <type category="struct"> 'structextends' attributes 1761*90277196SAndroid Build Coastguard Worker # Enums in <command> 'successcodes' and 'errorcodes' attributes 1762*90277196SAndroid Build Coastguard Worker self.stripUnsupportedAPIs(self.typedict, 'structextends', self.typedict) 1763*90277196SAndroid Build Coastguard Worker self.stripUnsupportedAPIs(self.cmddict, 'successcodes', self.enumdict) 1764*90277196SAndroid Build Coastguard Worker self.stripUnsupportedAPIs(self.cmddict, 'errorcodes', self.enumdict) 1765*90277196SAndroid Build Coastguard Worker self.stripUnsupportedAPIsFromList(self.validextensionstructs, self.typedict) 1766*90277196SAndroid Build Coastguard Worker 1767*90277196SAndroid Build Coastguard Worker # Construct lists of valid extension structures 1768*90277196SAndroid Build Coastguard Worker self.tagValidExtensionStructs() 1769*90277196SAndroid Build Coastguard Worker 1770*90277196SAndroid Build Coastguard Worker # @@May need to strip <spirvcapability> / <spirvextension> <enable> 1771*90277196SAndroid Build Coastguard Worker # tags of these forms: 1772*90277196SAndroid Build Coastguard Worker # <enable version="VK_API_VERSION_1_0"/> 1773*90277196SAndroid Build Coastguard Worker # <enable struct="VkPhysicalDeviceFeatures" feature="geometryShader" requires="VK_VERSION_1_0"/> 1774*90277196SAndroid Build Coastguard Worker # <enable extension="VK_KHR_shader_draw_parameters"/> 1775*90277196SAndroid Build Coastguard Worker # <enable property="VkPhysicalDeviceVulkan12Properties" member="shaderDenormPreserveFloat16" value="VK_TRUE" requires="VK_VERSION_1_2,VK_KHR_shader_float_controls"/> 1776*90277196SAndroid Build Coastguard Worker 1777*90277196SAndroid Build Coastguard Worker # Pass 3: loop over specified API versions and extensions printing 1778*90277196SAndroid Build Coastguard Worker # declarations for required things which have not already been 1779*90277196SAndroid Build Coastguard Worker # generated. 1780*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'PASS 3: GENERATE INTERFACES FOR FEATURES') 1781*90277196SAndroid Build Coastguard Worker self.gen.beginFile(self.genOpts) 1782*90277196SAndroid Build Coastguard Worker for f in features: 1783*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'PASS 3: Generating interface for', 1784*90277196SAndroid Build Coastguard Worker f.name) 1785*90277196SAndroid Build Coastguard Worker emit = self.emitFeatures = f.emit 1786*90277196SAndroid Build Coastguard Worker if not emit: 1787*90277196SAndroid Build Coastguard Worker self.gen.logMsg('diag', 'PASS 3: NOT declaring feature', 1788*90277196SAndroid Build Coastguard Worker f.elem.get('name'), 'because it is not tagged for emission') 1789*90277196SAndroid Build Coastguard Worker # Generate the interface (or just tag its elements as having been 1790*90277196SAndroid Build Coastguard Worker # emitted, if they have not been). 1791*90277196SAndroid Build Coastguard Worker self.gen.beginFeature(f.elem, emit) 1792*90277196SAndroid Build Coastguard Worker self.generateRequiredInterface(f.elem) 1793*90277196SAndroid Build Coastguard Worker self.gen.endFeature() 1794*90277196SAndroid Build Coastguard Worker # Generate spirv elements 1795*90277196SAndroid Build Coastguard Worker for s in spirvexts: 1796*90277196SAndroid Build Coastguard Worker self.generateSpirv(s, self.spirvextdict) 1797*90277196SAndroid Build Coastguard Worker for s in spirvcaps: 1798*90277196SAndroid Build Coastguard Worker self.generateSpirv(s, self.spirvcapdict) 1799*90277196SAndroid Build Coastguard Worker for s in formats: 1800*90277196SAndroid Build Coastguard Worker self.generateFormat(s, self.formatsdict) 1801*90277196SAndroid Build Coastguard Worker for s in self.syncstagedict: 1802*90277196SAndroid Build Coastguard Worker self.generateSyncStage(self.syncstagedict[s]) 1803*90277196SAndroid Build Coastguard Worker for s in self.syncaccessdict: 1804*90277196SAndroid Build Coastguard Worker self.generateSyncAccess(self.syncaccessdict[s]) 1805*90277196SAndroid Build Coastguard Worker for s in self.syncpipelinedict: 1806*90277196SAndroid Build Coastguard Worker self.generateSyncPipeline(self.syncpipelinedict[s]) 1807*90277196SAndroid Build Coastguard Worker self.gen.endFile() 1808*90277196SAndroid Build Coastguard Worker 1809*90277196SAndroid Build Coastguard Worker def apiReset(self): 1810*90277196SAndroid Build Coastguard Worker """Reset type/enum/command dictionaries before generating another API. 1811*90277196SAndroid Build Coastguard Worker 1812*90277196SAndroid Build Coastguard Worker Use between apiGen() calls to reset internal state.""" 1813*90277196SAndroid Build Coastguard Worker for datatype in self.typedict: 1814*90277196SAndroid Build Coastguard Worker self.typedict[datatype].resetState() 1815*90277196SAndroid Build Coastguard Worker for enum in self.enumdict: 1816*90277196SAndroid Build Coastguard Worker self.enumdict[enum].resetState() 1817*90277196SAndroid Build Coastguard Worker for cmd in self.cmddict: 1818*90277196SAndroid Build Coastguard Worker self.cmddict[cmd].resetState() 1819*90277196SAndroid Build Coastguard Worker for cmd in self.apidict: 1820*90277196SAndroid Build Coastguard Worker self.apidict[cmd].resetState() 1821