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