| #!/usr/bin/python3 -i |
| # |
| # Copyright 2013-2023 The Khronos Group Inc. |
| # |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| import os,re,sys |
| from generator import * |
| |
| doc = """ |
| /* |
| ** This target is no longer maintained and supported. |
| ** See README.adoc for discussion. |
| ** |
| ** This is a simple extension loader which provides the implementations for the |
| ** extension prototypes declared in vulkan header. It supports loading extensions either |
| ** for a single instance or a single device. Multiple instances are not yet supported. |
| ** |
| ** To use the loader add vulkan_ext.c to your solution and include <vulkan/vulkan_ext.h>. |
| ** |
| ** If your application is using a single instance, but multiple devices callParam |
| ** |
| ** vkExtInitInstance(instance); |
| ** |
| ** after initializing the instance. This way the extension loader will use the loaders |
| ** trampoline functions to call the correct driver for each call. This method is safe |
| ** if your application might use more than one device at the cost of one additional |
| ** indirection, the dispatch table of each dispatchable object. |
| ** |
| ** If your application uses only a single device it is better to use |
| ** |
| ** vkExtInitDevice(device); |
| ** |
| ** once the device has been initialized. This will resolve the function pointers |
| ** upfront and thus removes one indirection for each call into the driver. This *can* |
| ** result in slightly more performance for calling overhead limited cases. |
| */ |
| """ |
| |
| # StubExtGeneratorOptions - 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). |
| # alignFuncParam - if nonzero and parameters are being put on a |
| # separate line, align parameter names at the specified column |
| class StubExtGeneratorOptions(GeneratorOptions): |
| """Represents options during C interface generation for headers""" |
| def __init__(self, |
| filename = None, |
| directory = '.', |
| apiname = None, |
| profile = None, |
| versions = '.*', |
| emitversions = '.*', |
| defaultExtensions = None, |
| addExtensions = None, |
| removeExtensions = None, |
| emitExtensions = None, |
| sortProcedure = regSortFeatures, |
| prefixText = "", |
| alignFuncParam = 0): |
| GeneratorOptions.__init__(self, filename, directory, apiname, profile, |
| versions, emitversions, defaultExtensions, |
| addExtensions, removeExtensions, |
| emitExtensions, sortProcedure) |
| self.prefixText = prefixText |
| self.alignFuncParam = alignFuncParam |
| |
| # ExtensionStubSourceOutputGenerator - subclass of OutputGenerator. |
| # Generates C-language extension wrapper interface sources. |
| # |
| # ---- methods ---- |
| # ExtensionStubSourceOutputGenerator(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 ExtensionStubSourceOutputGenerator(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) |
| # |
| def beginFile(self, genOpts): |
| OutputGenerator.beginFile(self, genOpts) |
| # C-specific |
| # |
| # Multiple inclusion protection & C++ wrappers. |
| |
| # Internal state - accumulators for function pointers and function |
| # pointer initializatoin |
| self.pointers = []; |
| self.pointerInitializersInstance = []; |
| self.pointerInitializersDevice = []; |
| |
| # |
| # Write header protection |
| filename = self.genOpts.directory + '/' + 'vulkan_ext.h' |
| self.outFileHeader = open(filename, 'w', encoding='utf-8') |
| |
| write('#ifndef VULKAN_EXT_H', file=self.outFileHeader) |
| write('#define VULKAN_EXT_H', file=self.outFileHeader) |
| write('', file=self.outFileHeader) |
| write('#ifdef __cplusplus', file=self.outFileHeader) |
| write('extern "C" {', file=self.outFileHeader) |
| write('#endif', file=self.outFileHeader) |
| |
| # |
| # User-supplied prefix text, if any (list of strings) |
| if (genOpts.prefixText): |
| for s in genOpts.prefixText: |
| write(s, file=self.outFile) |
| write(s, file=self.outFileHeader) |
| |
| write(doc, file=self.outFileHeader) |
| |
| write('#include <vulkan/vulkan.h>', file=self.outFile) |
| self.newline() |
| |
| write('#include <vulkan/vulkan_core.h>', file=self.outFileHeader) |
| write('', file=self.outFileHeader) |
| |
| write('void vkExtInitInstance(VkInstance instance);', file=self.outFileHeader) |
| write('void vkExtInitDevice(VkDevice device);', file=self.outFileHeader) |
| write('', file=self.outFileHeader) |
| |
| def endFile(self): |
| for pointer in self.pointers: |
| write(pointer, file=self.outFile) |
| |
| self.newline() |
| |
| write('void vkExtInitInstance(VkInstance instance)\n{', file=self.outFile) |
| for pointerInitializer in self.pointerInitializersInstance: |
| write(pointerInitializer, file=self.outFile) |
| write('}', file=self.outFile) |
| |
| self.newline() |
| |
| write('void vkExtInitDevice(VkDevice device)\n{', file=self.outFile) |
| for pointerInitializer in self.pointerInitializersDevice: |
| write(pointerInitializer, file=self.outFile) |
| write('}', file=self.outFile) |
| |
| self.newline() |
| |
| #Finish header file |
| write('#ifdef __cplusplus', file=self.outFileHeader) |
| write('}', file=self.outFileHeader) |
| write('#endif', file=self.outFileHeader) |
| write('', file=self.outFileHeader) |
| write('#endif', file=self.outFileHeader) |
| self.outFileHeader.close() |
| |
| # Finish processing in superclass |
| OutputGenerator.endFile(self) |
| |
| def beginFeature(self, interface, emit): |
| # Start processing in superclass |
| OutputGenerator.beginFeature(self, interface, emit) |
| |
| # Accumulate function pointers and function pointer initialization |
| self.featurePointers = [] |
| self.featurePointerInitializersInstance = [] |
| self.featurePointerInitializersDevice = [] |
| |
| def endFeature(self): |
| # Add feature to global list with protectFeature |
| if (self.emit and self.featurePointers): |
| if (self.genOpts.protectFeature): |
| self.pointers.append('#ifdef ' + self.featureName) |
| self.pointerInitializersInstance.append('#ifdef ' + self.featureName) |
| self.pointerInitializersDevice.append('#ifdef ' + self.featureName) |
| |
| if (self.featureExtraProtect != None): |
| self.pointers.append('#ifdef ' + self.featureExtraProtect) |
| self.pointerInitializersInstance.append('#ifndef ' + self.featureName) |
| self.pointerInitializersDevice.append('#ifndef ' + self.featureName) |
| |
| self.pointers += self.featurePointers; |
| self.pointerInitializersInstance += self.featurePointerInitializersInstance; |
| self.pointerInitializersDevice += self.featurePointerInitializersDevice; |
| |
| if (self.featureExtraProtect != None): |
| self.pointers.append('#endif /* ' + self.featureExtraProtect + ' */') |
| self.pointerInitializersInstance.append('#endif /* ' + self.featureExtraProtect + ' */') |
| self.pointerInitializersDevice.append('#endif /* ' + self.featureExtraProtect + ' */') |
| if (self.genOpts.protectFeature): |
| self.pointers.append('#endif /* ' + self.featureName + ' */') |
| self.pointerInitializersInstance.append('#endif /* ' + self.featureName + ' */') |
| self.pointerInitializersDevice.append('#endif /* ' + self.featureName + ' */') |
| |
| # Finish processing in superclass |
| OutputGenerator.endFeature(self) |
| # |
| # Type generation |
| def genType(self, typeinfo, name, alias): |
| pass |
| |
| def genStruct(self, typeinfo, typeName, alias): |
| pass |
| |
| def genGroup(self, groupinfo, groupName, alias): |
| pass |
| |
| def genEnum(self, enuminfo, name, alias): |
| pass |
| |
| # |
| # Command generation |
| def genCmd(self, cmdinfo, name, alias): |
| OutputGenerator.genCmd(self, cmdinfo, name, alias) |
| |
| # |
| decls = self.makeStub(cmdinfo.elem) |
| self.featurePointerInitializersInstance.append(decls[0]) |
| self.featurePointerInitializersDevice.append(decls[1]) |
| self.featurePointers.append(decls[2]) |
| |
| # |
| # makeStub - return static declaration for function pointer and initialization of function pointer |
| # as a two-element list of strings. |
| # cmd - Element containing a <command> tag |
| 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) |
| |
| type = self.makeFunctionPointerType(nameTag.text, tail) |
| |
| # For each child element, if it is 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 += 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 |
| if n > 0: |
| indentCallParam = '(\n' |
| indentdecl = '(\n' |
| for i in range(0,n): |
| callParam = '' |
| |
| paramdecl += self.makeCParamDecl(params[i], self.genOpts.alignFuncParam) |
| pfnCall += self.makeCCallParam(params[i], self.genOpts.alignFuncParam) |
| if (i < n - 1): |
| paramdecl += ',\n' |
| pfnCall += ',\n' |
| else: |
| paramdecl += ')' |
| pfnCall += '\n );\n' |
| indentdecl += paramdecl |
| indentCallParam += pfnCall |
| else: |
| indentdecl = '(void);' |
| |
| pfnCall += '}\n' |
| |
| featureInstance = ' ' + pfnName + ' = ('+type+')vkGetInstanceProcAddr(instance, "' + name + '");' |
| featureDevice = ' ' + pfnName + ' = ('+type+')vkGetDeviceProcAddr(device, "' + name + '");' |
| return [featureInstance, featureDevice , pfnDecl + stubDecl + paramdecl + pfnCall] |
| |
| # Return function pointer type for given function |
| def makeFunctionPointerType(self, name, tail): |
| return 'PFN_' + name + tail |
| |
| # Return name of static variable which stores the function pointer for the given function |
| def makeFunctionPointerName(self, name, tail): |
| return 'pfn_' + name + tail |
| |
| # |
| # makeCParamDecl - return a string which is an indented, formatted |
| # declaration for a <param> or <member> block (e.g. function parameter |
| # or structure/union member). |
| # param - Element (<param> or <member>) to format |
| # aligncol - if non-zero, attempt to align the nested <name> element |
| # at this column |
| def makeCCallParam(self, param, aligncol): |
| return ' ' + param.find('name').text |
| |