示例#1
0
    def genType(self, typeinfo, name, alias):
        OutputGenerator.genType(self, typeinfo, name, alias)
        typeElem = typeinfo.elem
        # If the type is a struct type, traverse the embedded <member> tags
        # generating a structure. Otherwise, emit the tag text.
        category = typeElem.get('category')

        # Add a typeCategory{} entry for the category of this type.
        self.addName(self.typeCategory, name, category)

        if category in ('struct', 'union'):
            self.genStruct(typeinfo, name, alias)
        else:
            if alias:
                # Add name -> alias mapping
                self.addName(self.alias, name, alias)

                # Always emit an alias (?!)
                count = 1

                # May want to only emit full type definition when not an alias?
            else:
                # Extract the type name
                # (from self.genOpts). Copy other text through unchanged.
                # If the resulting text is an empty string, don't emit it.
                count = len(noneStr(typeElem.text))
                for elem in typeElem:
                    count += len(noneStr(elem.text)) + len(noneStr(elem.tail))

            if count > 0:
                if category == 'bitmask':
                    requiredEnum = typeElem.get('requires')
                    self.addName(self.flags, name, requiredEnum)

                    # This happens when the Flags type is defined, but no
                    # FlagBits are defined yet.
                    if requiredEnum is not None:
                        self.addMapping(name, requiredEnum)
                elif category == 'enum':
                    # This case does not seem to come up. It nominally would
                    # result from
                    #   <type name="Something" category="enum"/>,
                    # but the output generator doesn't emit them directly.
                    self.logMsg('warn', 'PyOutputGenerator::genType: invalid \'enum\' category for name:', name)
                elif category == 'funcpointer':
                    self.funcpointers[name] = None
                elif category == 'handle':
                    self.handles[name] = None
                elif category == 'define':
                    self.defines[name] = None
                elif category == 'basetype':
                    # Don't add an entry for base types that are not API types
                    # e.g. an API Bool type gets an entry, uint32_t does not
                    if self.apiName(name):
                        self.basetypes[name] = None
                        self.addName(self.typeCategory, name, 'basetype')
                    else:
                        self.logMsg('diag', 'PyOutputGenerator::genType: unprocessed type:', name, 'category:', category)
            else:
                self.logMsg('diag', 'PyOutputGenerator::genType: unprocessed type:', name)
示例#2
0
    def makeValueInfo(self, params):
        values = []
        for param in params:
            # Get name
            elem = param.find('name')
            name = noneStr(elem.text)
            nameTail = noneStr(elem.tail)

            # Get type info
            elem = param.find('type')
            baseType = noneStr(elem.text)
            fullType = (noneStr(param.text) + baseType +
                        noneStr(elem.tail)).strip()

            # Check for platform specific type definitions that need to be converted to a recognized trace format type.
            platformBaseType = None
            platformFullType = None
            if baseType in self.PLATFORM_TYPES:
                typeInfo = self.PLATFORM_TYPES[baseType]
                platformBaseType = baseType
                platformFullType = fullType
                fullType = fullType.replace(baseType, typeInfo['replaceWith'])
                baseType = typeInfo['baseType']

            # Get array length, always use altlen when available to avoid parsing latexmath
            if 'altlen' in param.attrib:
                arrayLength = param.attrib.get('altlen')
            else:
                arrayLength = self.getArrayLen(param)

            arrayCapacity = None
            if self.isStaticArray(param):
                arrayCapacity = arrayLength
                arrayLength = self.getStaticArrayLen(name, params,
                                                     arrayCapacity)

            # Get bitfield width
            bitfieldWidth = None
            if ':' in nameTail:
                bitfieldWidth = nameTail

            values.append(
                ValueInfo(name=name,
                          baseType=baseType,
                          fullType=fullType,
                          pointerCount=self.getPointerCount(fullType),
                          arrayLength=arrayLength,
                          arrayCapacity=arrayCapacity,
                          platformBaseType=platformBaseType,
                          platformFullType=platformFullType,
                          bitfieldWidth=bitfieldWidth))

        # Link array values to their corresponding length values
        for arrayValue in [v for v in values if v.arrayLength]:
            for v in values:
                if re.search(r'\b{}\b'.format(v.name), arrayValue.arrayLength):
                    arrayValue.arrayLengthValue = v
                    break

        return values
示例#3
0
 def genType(self, typeinfo, name):
     OutputGenerator.genType(self, typeinfo, name)
     typeElem = typeinfo.elem
     # If the type is a struct type, traverse the embedded <member> tags
     # generating a structure. Otherwise, emit the tag text.
     category = typeElem.get('category')
     if (category == 'struct' or category == 'union'):
         self.genStruct(typeinfo, name)
     else:
         # Replace <apientry /> tags with an APIENTRY-style string
         # (from self.genOpts). Copy other text through unchanged.
         # If the resulting text is an empty string, don't emit it.
         s = noneStr(typeElem.text)
         for elem in typeElem:
             if (elem.tag == 'apientry'):
                 s += self.genOpts.apientry + noneStr(elem.tail)
             else:
                 s += noneStr(elem.text) + noneStr(elem.tail)
         if (len(s) > 0):
             if (category in OutputGenerator.categoryToPath.keys()):
                 self.writeInclude(OutputGenerator.categoryToPath[category],
                     name, s + '\n')
             else:
                 self.logMsg('diag', '# NOT writing include file for type:',
                     name, 'category: ', category)
         else:
             self.logMsg('diag', '# NOT writing empty include file for type', name)
示例#4
0
    def makeValueInfo(self, params):
        values = []
        for param in params:
            # Get name
            elem = param.find('name')
            name = noneStr(elem.text)
            nameTail = noneStr(elem.tail)

            # Get type info
            elem = param.find('type')
            baseType = noneStr(elem.text)
            fullType = (noneStr(param.text) + baseType +
                        noneStr(elem.tail)).strip()

            # Check for platform specific type definitions that need to be converted to a recognized trace format type.
            platformBaseType = None
            platformFullType = None
            if baseType in self.PLATFORM_TYPES:
                typeInfo = self.PLATFORM_TYPES[baseType]
                platformBaseType = baseType
                platformFullType = fullType
                fullType = fullType.replace(baseType, typeInfo['replaceWith'])
                baseType = typeInfo['baseType']

            # Get array length
            arrayLength = self.getArrayLen(param)
            altArrayLength = param.attrib.get('altlen')
            arrayCapacity = None
            if self.isStaticArray(param):
                arrayCapacity = arrayLength
                arrayLength = self.getStaticArrayLen(name, params,
                                                     arrayCapacity)

            # Get bitfield width
            bitfieldWidth = None
            if ':' in nameTail:
                bitfieldWidth = nameTail

            values.append(
                ValueInfo(name=name,
                          baseType=baseType,
                          fullType=fullType,
                          pointerCount=self.getPointerCount(fullType),
                          arrayLength=arrayLength,
                          altArrayLength=altArrayLength,
                          arrayCapacity=arrayCapacity,
                          platformBaseType=platformBaseType,
                          platformFullType=platformFullType,
                          bitfieldWidth=bitfieldWidth))

        return values
示例#5
0
    def genType(self, typeinfo, name, alias):
        """Generate type."""
        OutputGenerator.genType(self, typeinfo, name, alias)
        typeElem = typeinfo.elem
        # If the type is a struct type, traverse the embedded <member> tags
        # generating a structure. Otherwise, emit the tag text.
        category = typeElem.get('category')

        if category in ('struct', 'union'):
            # If the type is a struct type, generate it using the
            # special-purpose generator.
            self.genStruct(typeinfo, name, alias)
        else:
            body = self.genRequirements(name)
            if alias:
                # If the type is an alias, just emit a typedef declaration
                body += 'typedef ' + alias + ' ' + name + ';\n'
                self.writeInclude(OutputGenerator.categoryToPath[category],
                                  name, body)
            else:
                # Replace <apientry /> tags with an APIENTRY-style string
                # (from self.genOpts). Copy other text through unchanged.
                # If the resulting text is an empty string, don't emit it.
                body += noneStr(typeElem.text)
                for elem in typeElem:
                    if elem.tag == 'apientry':
                        body += self.genOpts.apientry + noneStr(elem.tail)
                    else:
                        body += noneStr(elem.text) + noneStr(elem.tail)

                if body:
                    if category in OutputGenerator.categoryToPath:
                        self.writeInclude(
                            OutputGenerator.categoryToPath[category], name,
                            body + '\n')
                    else:
                        self.logMsg('diag',
                                    '# NOT writing include file for type:',
                                    name, '- bad category: ', category)
                else:
                    self.logMsg('diag',
                                '# NOT writing empty include file for type',
                                name)
示例#6
0
    def genType(self, typeinfo, name, alias):
        "Generate type."
        OutputGenerator.genType(self, typeinfo, name, alias)
        typeElem = typeinfo.elem

        # Vulkan:
        # Determine the category of the type, and the type section to add
        # its definition to.
        # 'funcpointer' is added to the 'struct' section as a workaround for
        # internal issue #877, since structures and function pointer types
        # can have cross-dependencies.
        category = typeElem.get('category')
        if category == 'funcpointer':
            section = 'struct'
        else:
            section = category

        if category in ('struct', 'union'):
            # If the type is a struct type, generate it using the
            # special-purpose generator.
            self.genStruct(typeinfo, name, alias)
        else:
            if self.genOpts is None:
                raise MissingGeneratorOptionsError()
            # OpenXR: this section was not under 'else:' previously, just fell through
            if alias:
                # If the type is an alias, just emit a typedef declaration
                body = 'typedef ' + alias + ' ' + name + ';\n'
            else:
                # Replace <apientry /> tags with an APIENTRY-style string
                # (from self.genOpts). Copy other text through unchanged.
                # If the resulting text is an empty string, don't emit it.
                body = noneStr(typeElem.text)
                for elem in typeElem:
                    if elem.tag == 'apientry':
                        body += self.genOpts.apientry + noneStr(elem.tail)
                    else:
                        body += noneStr(elem.text) + noneStr(elem.tail)
            if body:
                # Add extra newline after multi-line entries.
                if '\n' in body[0:-1]:
                    body += '\n'
                self.appendSection(section, body)
示例#7
0
    def getStaticArrayLen(self, name, params, capacity):
        # The XML registry does not provide a direct method for determining if a parameter provides the length
        # of a static array, but the parameter naming follows a pattern of array name = 'values' and length
        # name = 'valueCount'.  We will search the parameter list for a length parameter using this pattern.
        lengthName = name[:-1] + 'Count'
        for param in params:
            if lengthName == noneStr(param.find('name').text):
                return lengthName

        # Not all static arrays have an associated length parameter. These will use capacity as length.
        return capacity
示例#8
0
    def genType(self, typeinfo, name, alias):
        OutputGenerator.genType(self, typeinfo, name, alias)
        typeElem = typeinfo.elem

        # Vulkan:
        # Determine the category of the type, and the type section to add
        # its definition to.
        # 'funcpointer' is added to the 'struct' section as a workaround for
        # internal issue #877, since structures and function pointer types
        # can have cross-dependencies.
        category = typeElem.get('category')
        if category == 'funcpointer':
            section = 'struct'
        else:
            section = category

        if category in ('struct', 'union'):
            # If the type is a struct type, generate it using the
            # special-purpose generator.
            self.genStruct(typeinfo, name, alias)
        else:
            # OpenXR: this section was not under 'else:' previously, just fell through
            if alias:
                # If the type is an alias, just emit a typedef declaration
                body = 'typedef ' + alias + ' ' + name + ';\n'
            else:
                # Replace <apientry /> tags with an APIENTRY-style string
                # (from self.genOpts). Copy other text through unchanged.
                # If the resulting text is an empty string, don't emit it.
                body = noneStr(typeElem.text)
                for elem in typeElem:
                    if elem.tag == 'apientry':
                        body += self.genOpts.apientry + noneStr(elem.tail)
                    else:
                        body += noneStr(elem.text) + noneStr(elem.tail)
            if body:
                # Add extra newline after multi-line entries.
                if '\n' in body[0:-1]:
                    body += '\n'
                self.appendSection(section, body)
示例#9
0
    def genCmd(self, cmdinfo, name, alias):
        OutputGenerator.genCmd(self, cmdinfo, name, alias)
        if self.processCmds:
            # Create the declaration for the function prototype
            proto = cmdinfo.elem.find('proto')
            protoDecl = self.genOpts.apicall + noneStr(proto.text)
            for elem in proto:
                text = noneStr(elem.text)
                tail = noneStr(elem.tail)
                if (elem.tag == 'name'):
                    if text.startswith('vk'):
                        text = text[2:]
                    protoDecl += self.makeProtoName(text, tail)
                else:
                    protoDecl += text + tail

            returnType = noneStr(proto.text) + noneStr(proto.find('type').text)

            # TODO: Define a class or namedtuple for the dictionary entry
            self.featureCmdParams[name] = (returnType, protoDecl,
                                           self.makeValueInfo(
                                               cmdinfo.elem.findall('param')))
示例#10
0
    def genType(self, typeinfo, name, alias):
        OutputGenerator.genType(self, typeinfo, name, alias)
        typeElem = typeinfo.elem
        # If the type is a struct type, traverse the embedded <member> tags
        # generating a structure. Otherwise, emit the tag text.
        category = typeElem.get('category')

        body = ''
        if category in ('struct', 'union'):
            # If the type is a struct type, generate it using the
            # special-purpose generator.
            self.genStruct(typeinfo, name, alias)
        else:
            if alias:
                # If the type is an alias, just emit a typedef declaration
                body = 'typedef ' + alias + ' ' + name + ';\n'
                self.writeInclude(OutputGenerator.categoryToPath[category],
                    name, body)
            else:
                # Replace <apientry /> tags with an APIENTRY-style string
                # (from self.genOpts). Copy other text through unchanged.
                # If the resulting text is an empty string, don't emit it.
                body = noneStr(typeElem.text)
                for elem in typeElem:
                    if elem.tag == 'apientry':
                        body += self.genOpts.apientry + noneStr(elem.tail)
                    else:
                        body += noneStr(elem.text) + noneStr(elem.tail)

                if body:
                    if category in OutputGenerator.categoryToPath:
                        self.writeInclude(OutputGenerator.categoryToPath[category],
                            name, body + '\n')
                    else:
                        self.logMsg('diag', '# NOT writing include file for type:',
                            name, '- bad category: ', category)
                else:
                    self.logMsg('diag', '# NOT writing empty include file for type', name)
示例#11
0
    def makeStructureTypeEnum(self, typeinfo, typename):
        members = typeinfo.elem.findall('.//member')

        for member in members:
            membername = noneStr(member.find('name').text)

            # We only care about structures with an sType, which can be included in a pNext chain.
            if membername == 'sType':
                # Check for value in the XML element.
                values = member.attrib.get('values')

                if values:
                    return values
                else:
                    # If the value was not specified by the XML element, process the struct type to create it.
                    stype = re.sub('([a-z0-9])([A-Z])', r'\1_\2', typename)
                    stype = stype.replace('D3_D12', 'D3D12')
                    stype = stype.replace('Device_IDProp', 'Device_ID_Prop')
                    stype = stype.upper()
                    return re.sub('VK_', 'VK_STRUCTURE_TYPE_', stype)
        return None
示例#12
0
def makeVulkanTypeFromXMLTag(typeInfo, tag):
    res = VulkanType()

    # Process the length expression

    if tag.attrib.get("len") is not None:
        lengths = tag.attrib.get("len").split(",")
        res.lenExpr = lengths[0]

    # Calculate static array expression

    nametag = tag.find("name")
    enumtag = tag.find("enum")

    if enumtag is not None:
        res.staticArrExpr = enumtag.text
    elif nametag is not None:
        res.staticArrExpr = noneStr(nametag.tail)[1:-1]
        if res.staticArrExpr != "":
            res.staticArrCount = int(res.staticArrExpr)

    # Determine const

    beforeTypePart = noneStr(tag.text)

    if "const" in beforeTypePart:
        res.isConst = True

    # Calculate type and pointer info

    for elem in tag:
        if elem.tag == "name":
            res.paramName = elem.text
        if elem.tag == "type":
            duringTypePart = noneStr(elem.text)
            afterTypePart = noneStr(elem.tail)
            # Now we know enough to fill some stuff in
            res.typeName = duringTypePart

            if res.typeName in TRANSFORMED_TYPES:
                res.isTransformed = True

            # This only handles pointerIndirectionLevels == 2
            # along with optional constant pointer for the inner part.
            for c in afterTypePart:
                if c == "*":
                    res.pointerIndirectionLevels += 1
            if "const" in afterTypePart and res.pointerIndirectionLevels == 2:
                res.isPointerToConstPointer = True

            # If void*, treat like it's not a pointer
            # if duringTypePart == "void":
            # res.pointerIndirectionLevels -= 1

    # Calculate optionality (based on validitygenerator.py)
    if tag.attrib.get("optional") is not None:
        res.isOptional = True
        res.optionalStr = tag.attrib.get("optional")

    # If no validity is being generated, it usually means that
    # validity is complex and not absolute, so let's say yes.
    if tag.attrib.get("noautovalidity") is not None:
        res.isOptional = True

    # If this is a structure extension, it is optional.
    if tag.attrib.get("structextends") is not None:
        res.isOptional = True

    # If this is a pNext pointer, it is optional.
    if res.paramName == "pNext":
        res.isOptional = True

    res.primitiveEncodingSize = \
        typeInfo.getPrimitiveEncodingSize(res.typeName)

    # Annotations: Environment binds
    if tag.attrib.get("binds") is not None:
        bindPairs = map(lambda x: x.strip(),
                        tag.attrib.get("binds").split(","))
        bindPairsSplit = map(lambda p: p.split(":"), bindPairs)
        res.binds = dict(
            map(lambda sp: (sp[0].strip(), sp[1].strip()), bindPairsSplit))

    # Annotations: Device memory
    for k in DEVICE_MEMORY_INFO_KEYS:
        if tag.attrib.get(k) is not None:
            res.deviceMemoryAttrib = k
            res.deviceMemoryVal = \
                tag.attrib.get(k)
            break

    # Annotations: Filters
    if tag.attrib.get("filterVar") is not None:
        res.filterVar = tag.attrib.get("filterVar").strip()

    if tag.attrib.get("filterVals") is not None:
        res.filterVals = \
            list(map(lambda v: v.strip(),
                    tag.attrib.get("filterVals").strip().split(",")))
        print("Filtervals: %s" % res.filterVals)

    if tag.attrib.get("filterFunc") is not None:
        res.filterFunc = parseFilterFuncExpr(tag.attrib.get("filterFunc"))

    if tag.attrib.get("filterOtherwise") is not None:
        res.Otherwise = tag.attrib.get("filterOtherwise")

    # store all other attribs here
    res.attribs = dict(tag.attrib)

    return res
示例#13
0
    def genType(self, typeinfo, name, alias):
        """Generate type.

        - For 'struct' or 'union' types, defer to genStruct() to
          add to the dictionary.
        - For 'bitmask' types, add the type name to the 'flags' dictionary,
          with the value being the corresponding 'enums' name defining
          the acceptable flag bits.
        - For 'enum' types, add the type name to the 'enums' dictionary,
          with the value being '@STOPHERE@' (because this case seems
          never to happen).
        - For 'funcpointer' types, add the type name to the 'funcpointers'
          dictionary.
        - For 'handle' and 'define' types, add the handle or #define name
          to the 'struct' dictionary, because that's how the spec sources
          tag these types even though they aren't structs."""
        OutputGenerator.genType(self, typeinfo, name, alias)
        typeElem = typeinfo.elem
        # If the type is a struct type, traverse the embedded <member> tags
        # generating a structure. Otherwise, emit the tag text.
        category = typeElem.get('category')

        # Add a typeCategory{} entry for the category of this type.
        self.addName(self.typeCategory, name, category)

        if category in ('struct', 'union'):
            self.genStruct(typeinfo, name, alias)
        else:
            if alias:
                # Add name -> alias mapping
                self.addName(self.alias, name, alias)

                # Always emit an alias (?!)
                count = 1

                # May want to only emit full type definition when not an alias?
            else:
                # Extract the type name
                # (from self.genOpts). Copy other text through unchanged.
                # If the resulting text is an empty string, don't emit it.
                count = len(noneStr(typeElem.text))
                for elem in typeElem:
                    count += len(noneStr(elem.text)) + len(noneStr(elem.tail))

            if count > 0:
                if category == 'bitmask':
                    requiredEnum = typeElem.get('requires')
                    self.addName(self.flags, name, requiredEnum)

                    # This happens when the Flags type is defined, but no
                    # FlagBits are defined yet.
                    if requiredEnum is not None:
                        self.addMapping(name, requiredEnum)
                elif category == 'enum':
                    # This case does not seem to come up. It nominally would
                    # result from
                    #   <type name="Something" category="enum"/>,
                    # but the output generator doesn't emit them directly.
                    self.logMsg(
                        'warn',
                        'PyOutputGenerator::genType: invalid \'enum\' category for name:',
                        name)
                elif category == 'funcpointer':
                    self.funcpointers[name] = None
                elif category == 'handle':
                    self.handles[name] = None
                elif category == 'define':
                    self.defines[name] = None
                elif category == 'basetype':
                    # Don't add an entry for base types that are not API types
                    # e.g. an API Bool type gets an entry, uint32_t does not
                    if self.apiName(name):
                        self.basetypes[name] = None
                        self.addName(self.typeCategory, name, 'basetype')
                    else:
                        self.logMsg(
                            'diag',
                            'PyOutputGenerator::genType: unprocessed type:',
                            name, 'category:', category)
            else:
                self.logMsg('diag',
                            'PyOutputGenerator::genType: unprocessed type:',
                            name)
def makeVulkanTypeFromXMLTag(typeInfo, tag):
    res = VulkanType()

    # Process the length expression

    if tag.attrib.get("len") is not None:
        lengths = tag.attrib.get("len").split(",")
        res.lenExpr = lengths[0]

    # Calculate static array expression

    nametag = tag.find("name")
    enumtag = tag.find("enum")

    if enumtag is not None:
        res.staticArrExpr = enumtag.text
    elif nametag is not None:
        res.staticArrExpr = noneStr(nametag.tail)[1:-1]
        if res.staticArrExpr != "":
            res.staticArrCount = int(res.staticArrExpr)

    # Determine const

    beforeTypePart = noneStr(tag.text)

    if "const" in beforeTypePart:
        res.isConst = True

    # Calculate type and pointer info

    for elem in tag:
        if elem.tag == "name":
            res.paramName = elem.text
        if elem.tag == "type":
            duringTypePart = noneStr(elem.text)
            afterTypePart = noneStr(elem.tail)
            # Now we know enough to fill some stuff in
            res.typeName = duringTypePart

            if res.typeName in TRANSFORMED_TYPES:
                res.isTransformed = True

            # This only handles pointerIndirectionLevels == 2
            # along with optional constant pointer for the inner part.
            for c in afterTypePart:
                if c == "*":
                    res.pointerIndirectionLevels += 1
            if "const" in afterTypePart and res.pointerIndirectionLevels == 2:
                res.isPointerToConstPointer = True

            # If void*, treat like it's not a pointer
            # if duringTypePart == "void":
            # res.pointerIndirectionLevels -= 1

    # Calculate optionality (based on validitygenerator.py)
    if tag.attrib.get("optional") is not None:
        res.isOptional = True

    # If no validity is being generated, it usually means that
    # validity is complex and not absolute, so let's say yes.
    if tag.attrib.get("noautovalidity") is not None:
        res.isOptional = True

    # If this is a structure extension, it is optional.
    if tag.attrib.get("structextends") is not None:
        res.isOptional = True

    # If this is a pNext pointer, it is optional.
    if res.paramName == "pNext":
        res.isOptional = True

    res.primitiveEncodingSize = \
        typeInfo.getPrimitiveEncodingSize(res.typeName)

    # it is assumed only one such key
    # applies to any field.
    for k in DEVICE_MEMORY_INFO_KEYS:
        if tag.attrib.get(k) is not None:
            res.deviceMemoryAttrib = k
            res.deviceMemoryVal = \
                tag.attrib.get(k)
            break

    return res
    def makeStub(self, cmd):
        """Generate a stub function pointer <command> Element"""
        proto = cmd.find('proto')
        params = cmd.findall('param')
        name = cmd.find('name')

        # Begin accumulating prototype and typedef strings
        pfnDecl = 'static '
        pfnDecl += noneStr(proto.text)

        # Find the name tag and generate the function pointer and function pointer initialization code
        nameTag = proto.find('name')
        tail = noneStr(nameTag.tail)
        returnType = noneStr(proto.find('type').text)

        pfn_type = self.makeFunctionPointerType(nameTag.text, tail)

        # For each child element, if it's a <name> wrap in appropriate
        # declaration. Otherwise append its contents and tail con#tents.
        stubDecl = ''
        for elem in proto:
            text = noneStr(elem.text)
            tail = noneStr(elem.tail)
            if elem.tag == 'name':
                name = self.makeProtoName(text, tail)
                stubDecl += name
            else:
                stubDecl += text + tail

        pfnName = self.makeFunctionPointerName(nameTag.text, noneStr(tail))
        pfnDecl += pfn_type + ' ' + pfnName + ';'

        # Now generate the stub function
        pfnDecl += '\n'

        # Now add the parameter declaration list, which is identical
        # for prototypes and typedefs. Concatenate all the text from
        # a <param> node without the tags. No tree walking required
        # since all tags are ignored.
        n = len(params)
        paramdecl = '(\n'

        pfnCall = '\n{\n    ' + ('return ',
                                 '')[returnType == 'void'] + pfnName + '(\n'
        # Indented parameters
        align = self.genOpts.alignFuncParam
        if n > 0:
            indentCallParam = '(\n'
            indentdecl = '(\n'
            indentdecl += ',\n'.join(
                self.makeCParamDecl(p, align) for p in params)
            indentdecl += ')'
            pfnCall += ',\n'.join(
                self.makeCCallParam(p, align) for p in params)
            pfnCall += '\n    );\n'
            indentCallParam += pfnCall
        else:
            indentdecl = '(void);'

        pfnCall += '}\n'

        featureInstance = '    ' + pfnName + ' = (' + pfn_type + ')vkGetInstanceProcAddr(instance, "' + name + '");'
        featureDevice = '    ' + pfnName + ' = (' + pfn_type + ')vkGetDeviceProcAddr(device, "' + name + '");'
        return [
            featureInstance, featureDevice,
            pfnDecl + stubDecl + paramdecl + pfnCall
        ]