diff options
Diffstat (limited to 'thirdparty/vulkan/registry/cgenerator.py')
-rwxr-xr-x | thirdparty/vulkan/registry/cgenerator.py | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/thirdparty/vulkan/registry/cgenerator.py b/thirdparty/vulkan/registry/cgenerator.py new file mode 100755 index 0000000000..7f2d9bca09 --- /dev/null +++ b/thirdparty/vulkan/registry/cgenerator.py @@ -0,0 +1,425 @@ +#!/usr/bin/python3 -i +# +# Copyright (c) 2013-2019 The Khronos Group Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re +import sys +from generator import (GeneratorOptions, OutputGenerator, noneStr, + regSortFeatures, write) + +# CGeneratorOptions - subclass of GeneratorOptions. +# +# Adds options used by COutputGenerator objects during C language header +# generation. +# +# Additional members +# prefixText - list of strings to prefix generated header with +# (usually a copyright statement + calling convention macros). +# protectFile - True if multiple inclusion protection should be +# generated (based on the filename) around the entire header. +# protectFeature - True if #ifndef..#endif protection should be +# generated around a feature interface in the header file. +# genFuncPointers - True if function pointer typedefs should be +# generated +# protectProto - If conditional protection should be generated +# around prototype declarations, set to either '#ifdef' +# to require opt-in (#ifdef protectProtoStr) or '#ifndef' +# to require opt-out (#ifndef protectProtoStr). Otherwise +# set to None. +# protectProtoStr - #ifdef/#ifndef symbol to use around prototype +# declarations, if protectProto is set +# apicall - string to use for the function declaration prefix, +# such as APICALL on Windows. +# apientry - string to use for the calling convention macro, +# in typedefs, such as APIENTRY. +# apientryp - string to use for the calling convention macro +# in function pointer typedefs, such as APIENTRYP. +# directory - directory into which to generate include files +# indentFuncProto - True if prototype declarations should put each +# parameter on a separate line +# indentFuncPointer - True if typedefed function pointers should put each +# parameter on a separate line +# alignFuncParam - if nonzero and parameters are being put on a +# separate line, align parameter names at the specified column +# genEnumBeginEndRange - True if BEGIN_RANGE / END_RANGE macros should +# be generated for enumerated types +# genAliasMacro - True if the OpenXR alias macro should be generated +# for aliased types (unclear what other circumstances this is useful) +# aliasMacro - alias macro to inject when genAliasMacro is True +class CGeneratorOptions(GeneratorOptions): + """Represents options during C interface generation for headers""" + + def __init__(self, + conventions = None, + filename = None, + directory = '.', + apiname = None, + profile = None, + versions = '.*', + emitversions = '.*', + defaultExtensions = None, + addExtensions = None, + removeExtensions = None, + emitExtensions = None, + sortProcedure = regSortFeatures, + prefixText = "", + genFuncPointers = True, + protectFile = True, + protectFeature = True, + protectProto = None, + protectProtoStr = None, + apicall = '', + apientry = '', + apientryp = '', + indentFuncProto = True, + indentFuncPointer = False, + alignFuncParam = 0, + genEnumBeginEndRange = False, + genAliasMacro = False, + aliasMacro = '' + ): + GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile, + versions, emitversions, defaultExtensions, + addExtensions, removeExtensions, + emitExtensions, sortProcedure) + self.prefixText = prefixText + self.genFuncPointers = genFuncPointers + self.protectFile = protectFile + self.protectFeature = protectFeature + self.protectProto = protectProto + self.protectProtoStr = protectProtoStr + self.apicall = apicall + self.apientry = apientry + self.apientryp = apientryp + self.indentFuncProto = indentFuncProto + self.indentFuncPointer = indentFuncPointer + self.alignFuncParam = alignFuncParam + self.genEnumBeginEndRange = genEnumBeginEndRange + self.genAliasMacro = genAliasMacro + self.aliasMacro = aliasMacro + +# COutputGenerator - subclass of OutputGenerator. +# Generates C-language API interfaces. +# +# ---- methods ---- +# COutputGenerator(errFile, warnFile, diagFile) - args as for +# OutputGenerator. Defines additional internal state. +# ---- methods overriding base class ---- +# beginFile(genOpts) +# endFile() +# beginFeature(interface, emit) +# endFeature() +# genType(typeinfo,name) +# genStruct(typeinfo,name) +# genGroup(groupinfo,name) +# genEnum(enuminfo, name) +# genCmd(cmdinfo) +class COutputGenerator(OutputGenerator): + """Generate specified API interfaces in a specific style, such as a C header""" + # This is an ordered list of sections in the header file. + TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', + 'group', 'bitmask', 'funcpointer', 'struct'] + ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command'] + + def __init__(self, + errFile = sys.stderr, + warnFile = sys.stderr, + diagFile = sys.stdout): + OutputGenerator.__init__(self, errFile, warnFile, diagFile) + # Internal state - accumulators for different inner block text + self.sections = {section: [] for section in self.ALL_SECTIONS} + self.feature_not_empty = False + self.need_platform_include = False + self.may_alias = None + + def beginFile(self, genOpts): + OutputGenerator.beginFile(self, genOpts) + # C-specific + # + # Multiple inclusion protection & C++ wrappers. + if genOpts.protectFile and self.genOpts.filename: + headerSym = re.sub(r'\.h', '_h_', + os.path.basename(self.genOpts.filename)).upper() + write('#ifndef', headerSym, file=self.outFile) + write('#define', headerSym, '1', file=self.outFile) + self.newline() + write('#ifdef __cplusplus', file=self.outFile) + write('extern "C" {', file=self.outFile) + write('#endif', file=self.outFile) + self.newline() + + # User-supplied prefix text, if any (list of strings) + if genOpts.prefixText: + for s in genOpts.prefixText: + write(s, file=self.outFile) + + def endFile(self): + # C-specific + # Finish C++ wrapper and multiple inclusion protection + self.newline() + write('#ifdef __cplusplus', file=self.outFile) + write('}', file=self.outFile) + write('#endif', file=self.outFile) + if self.genOpts.protectFile and self.genOpts.filename: + self.newline() + write('#endif', file=self.outFile) + # Finish processing in superclass + OutputGenerator.endFile(self) + + def beginFeature(self, interface, emit): + # Start processing in superclass + OutputGenerator.beginFeature(self, interface, emit) + # C-specific + # Accumulate includes, defines, types, enums, function pointer typedefs, + # end function prototypes separately for this feature. They're only + # printed in endFeature(). + self.sections = {section: [] for section in self.ALL_SECTIONS} + self.feature_not_empty = False + + def endFeature(self): + # C-specific + # Actually write the interface to the output file. + if self.emit: + if self.feature_not_empty: + if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename): + self.newline() + if self.genOpts.protectFeature: + write('#ifndef', self.featureName, file=self.outFile) + # If type declarations are needed by other features based on + # this one, it may be necessary to suppress the ExtraProtect, + # or move it below the 'for section...' loop. + if self.featureExtraProtect is not None: + write('#ifdef', self.featureExtraProtect, file=self.outFile) + self.newline() + write('#define', self.featureName, '1', file=self.outFile) + for section in self.TYPE_SECTIONS: + # OpenXR: + # If we need the explicit include of the external platform header, + # put it right before the function pointer definitions + if section == "funcpointer" and self.need_platform_include: + write('// Include for OpenXR Platform-Specific Types', file=self.outFile) + write('#include "openxr_platform.h"', file=self.outFile) + self.newline() + self.need_platform_include = False + contents = self.sections[section] + if contents: + write('\n'.join(contents), file=self.outFile) + if self.genOpts.genFuncPointers and self.sections['commandPointer']: + write('\n'.join(self.sections['commandPointer']), file=self.outFile) + self.newline() + if self.sections['command']: + if self.genOpts.protectProto: + write(self.genOpts.protectProto, + self.genOpts.protectProtoStr, file=self.outFile) + write('\n'.join(self.sections['command']), end='', file=self.outFile) + if self.genOpts.protectProto: + write('#endif', file=self.outFile) + else: + self.newline() + if self.featureExtraProtect is not None: + write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) + if self.genOpts.protectFeature: + write('#endif /*', self.featureName, '*/', file=self.outFile) + # Finish processing in superclass + OutputGenerator.endFeature(self) + + # Append a definition to the specified section + def appendSection(self, section, text): + # self.sections[section].append('SECTION: ' + section + '\n') + self.sections[section].append(text) + self.feature_not_empty = True + + # Type generation + 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) + + # Protection string generation + # Protection strings are the strings defining the OS/Platform/Graphics + # requirements for a given OpenXR command. When generating the + # language header files, we need to make sure the items specific to a + # graphics API or OS platform are properly wrapped in #ifs. + def genProtectString(self, protect_str): + protect_if_str = '' + protect_end_str = '' + protect_list = [] + if protect_str: + if ',' in protect_str: + protect_list.extend(protect_str.split(",")) + protect_def_str = '' + count = 0 + for protect_define in protect_list: + if count > 0: + protect_def_str += ' &&' + protect_def_str += ' defined(%s)' % protect_define + count = count + 1 + count = count + 1 + protect_if_str = '#if' + protect_if_str += protect_def_str + protect_if_str += '\n' + protect_end_str = '#endif //' + protect_end_str += protect_def_str + protect_end_str += '\n' + else: + protect_if_str += '#ifdef %s\n' % protect_str + protect_end_str += '#endif // %s\n' % protect_str + return (protect_if_str, protect_end_str) + + def typeMayAlias(self, typeName): + if not self.may_alias: + # First time we've asked if a type may alias. + # So, let's populate the set of all names of types that may. + + # Everyone with an explicit mayalias="true" + self.may_alias = set(typeName + for typeName, data in self.registry.typedict.items() + if data.elem.get('mayalias') == 'true') + + # Every type mentioned in some other type's parentstruct attribute. + self.may_alias.update(set(x for x in + [otherType.elem.get('parentstruct') + for _, otherType in self.registry.typedict.items()] + if x is not None + )) + return typeName in self.may_alias + + # Struct (e.g. C "struct" type) generation. + # This is a special case of the <type> tag where the contents are + # interpreted as a set of <member> tags instead of freeform C + # C type declarations. The <member> tags are just like <param> + # tags - they are a declaration of a struct or union member. + # Only simple member declarations are supported (no nested + # structs etc.) + # If alias is not None, then this struct aliases another; just + # generate a typedef of that alias. + def genStruct(self, typeinfo, typeName, alias): + OutputGenerator.genStruct(self, typeinfo, typeName, alias) + + typeElem = typeinfo.elem + + if alias: + body = 'typedef ' + alias + ' ' + typeName + ';\n' + else: + body = '' + (protect_begin, protect_end) = self.genProtectString(typeElem.get('protect')) + if protect_begin: + body += protect_begin + body += 'typedef ' + typeElem.get('category') + + # This is an OpenXR-specific alternative where aliasing refers + # to an inheritance hierarchy of types rather than C-level type + # aliases. + if self.genOpts.genAliasMacro and self.typeMayAlias(typeName): + body += ' ' + self.genOpts.aliasMacro + + body += ' ' + typeName + ' {\n' + + targetLen = 0 + for member in typeElem.findall('.//member'): + targetLen = max(targetLen, self.getCParamTypeLength(member)) + for member in typeElem.findall('.//member'): + body += self.makeCParamDecl(member, targetLen + 4) + body += ';\n' + body += '} ' + typeName + ';\n' + if protect_end: + body += protect_end + + self.appendSection('struct', body) + + # Group (e.g. C "enum" type) generation. + # These are concatenated together with other types. + # If alias is not None, it is the name of another group type + # which aliases this type; just generate that alias. + def genGroup(self, groupinfo, groupName, alias = None): + OutputGenerator.genGroup(self, groupinfo, groupName, alias) + groupElem = groupinfo.elem + + # After either enumerated type or alias paths, add the declaration + # to the appropriate section for the group being defined. + if groupElem.get('type') == 'bitmask': + section = 'bitmask' + else: + section = 'group' + + if alias: + # If the group name is aliased, just emit a typedef declaration + # for the alias. + body = 'typedef ' + alias + ' ' + groupName + ';\n' + self.appendSection(section, body) + else: + (section, body) = self.buildEnumCDecl(self.genOpts.genEnumBeginEndRange, groupinfo, groupName) + self.appendSection(section, "\n" + body) + + # Enumerant generation + # <enum> tags may specify their values in several ways, but are usually + # just integers. + def genEnum(self, enuminfo, name, alias): + OutputGenerator.genEnum(self, enuminfo, name, alias) + (_, strVal) = self.enumToValue(enuminfo.elem, False) + body = '#define ' + name.ljust(33) + ' ' + strVal + self.appendSection('enum', body) + + # Command generation + def genCmd(self, cmdinfo, name, alias): + OutputGenerator.genCmd(self, cmdinfo, name, alias) + + # if alias: + # prefix = '// ' + name + ' is an alias of command ' + alias + '\n' + # else: + # prefix = '' + + prefix = '' + decls = self.makeCDecls(cmdinfo.elem) + self.appendSection('command', prefix + decls[0] + '\n') + if self.genOpts.genFuncPointers: + self.appendSection('commandPointer', decls[1]) |