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