extensionStubSource.py
1 #!/usr/bin/python3 -i 2 # 3 # Copyright (c) 2013-2019 The Khronos Group Inc. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 import os,re,sys 18 from generator import * 19 20 doc = """ 21 /* 22 ** This target is no longer maintained and supported. 23 ** See README.adoc for discussion. 24 ** 25 ** This is a simple extension loader which provides the implementations for the 26 ** extension prototypes declared in vulkan header. It supports loading extensions either 27 ** for a single instance or a single device. Multiple instances are not yet supported. 28 ** 29 ** To use the loader add vulkan_ext.c to your solution and include <vulkan/vulkan_ext.h>. 30 ** 31 ** If your application is using a single instance, but multiple devices callParam 32 ** 33 ** vkExtInitInstance(instance); 34 ** 35 ** after initializing the instance. This way the extension loader will use the loaders 36 ** trampoline functions to call the correct driver for each call. This method is safe 37 ** if your application might use more than one device at the cost of one additional 38 ** indirection, the dispatch table of each dispatchable object. 39 ** 40 ** If your application uses only a single device it's better to use 41 ** 42 ** vkExtInitDevice(device); 43 ** 44 ** once the device has been initialized. This will resolve the function pointers 45 ** upfront and thus removes one indirection for each call into the driver. This *can* 46 ** result in slightly more performance for calling overhead limited cases. 47 */ 48 """ 49 50 # StubExtGeneratorOptions - subclass of GeneratorOptions. 51 # 52 # Adds options used by COutputGenerator objects during C language header 53 # generation. 54 # 55 # Additional members 56 # prefixText - list of strings to prefix generated header with 57 # (usually a copyright statement + calling convention macros). 58 # alignFuncParam - if nonzero and parameters are being put on a 59 # separate line, align parameter names at the specified column 60 class StubExtGeneratorOptions(GeneratorOptions): 61 """Represents options during C interface generation for headers""" 62 def __init__(self, 63 filename = None, 64 directory = '.', 65 apiname = None, 66 profile = None, 67 versions = '.*', 68 emitversions = '.*', 69 defaultExtensions = None, 70 addExtensions = None, 71 removeExtensions = None, 72 emitExtensions = None, 73 sortProcedure = regSortFeatures, 74 prefixText = "", 75 alignFuncParam = 0): 76 GeneratorOptions.__init__(self, filename, directory, apiname, profile, 77 versions, emitversions, defaultExtensions, 78 addExtensions, removeExtensions, 79 emitExtensions, sortProcedure) 80 self.prefixText = prefixText 81 self.alignFuncParam = alignFuncParam 82 83 # ExtensionStubSourceOutputGenerator - subclass of OutputGenerator. 84 # Generates C-language extension wrapper interface sources. 85 # 86 # ---- methods ---- 87 # ExtensionStubSourceOutputGenerator(errFile, warnFile, diagFile) - args as for 88 # OutputGenerator. Defines additional internal state. 89 # ---- methods overriding base class ---- 90 # beginFile(genOpts) 91 # endFile() 92 # beginFeature(interface, emit) 93 # endFeature() 94 # genType(typeinfo,name) 95 # genStruct(typeinfo,name) 96 # genGroup(groupinfo,name) 97 # genEnum(enuminfo, name) 98 # genCmd(cmdinfo) 99 class ExtensionStubSourceOutputGenerator(OutputGenerator): 100 """Generate specified API interfaces in a specific style, such as a C header""" 101 # This is an ordered list of sections in the header file. 102 TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', 103 'group', 'bitmask', 'funcpointer', 'struct'] 104 ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command'] 105 def __init__(self, 106 errFile = sys.stderr, 107 warnFile = sys.stderr, 108 diagFile = sys.stdout): 109 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 110 # 111 def beginFile(self, genOpts): 112 OutputGenerator.beginFile(self, genOpts) 113 # C-specific 114 # 115 # Multiple inclusion protection & C++ wrappers. 116 117 # Internal state - accumulators for function pointers and function 118 # pointer initializatoin 119 self.pointers = []; 120 self.pointerInitializersInstance = []; 121 self.pointerInitializersDevice = []; 122 123 # 124 # Write header protection 125 filename = self.genOpts.directory + '/' + 'vulkan_ext.h' 126 self.outFileHeader = open(filename, 'w', encoding='utf-8') 127 128 write('#ifndef VULKAN_EXT_H', file=self.outFileHeader) 129 write('#define VULKAN_EXT_H', file=self.outFileHeader) 130 write('', file=self.outFileHeader) 131 write('#ifdef __cplusplus', file=self.outFileHeader) 132 write('extern "C" {', file=self.outFileHeader) 133 write('#endif', file=self.outFileHeader) 134 135 # 136 # User-supplied prefix text, if any (list of strings) 137 if (genOpts.prefixText): 138 for s in genOpts.prefixText: 139 write(s, file=self.outFile) 140 write(s, file=self.outFileHeader) 141 142 write(doc, file=self.outFileHeader) 143 144 write('#include <vulkan/vulkan.h>', file=self.outFile) 145 self.newline() 146 147 write('#include <vulkan/vulkan_core.h>', file=self.outFileHeader) 148 write('', file=self.outFileHeader) 149 150 write('void vkExtInitInstance(VkInstance instance);', file=self.outFileHeader) 151 write('void vkExtInitDevice(VkDevice device);', file=self.outFileHeader) 152 write('', file=self.outFileHeader) 153 154 def endFile(self): 155 for pointer in self.pointers: 156 write(pointer, file=self.outFile) 157 158 self.newline() 159 160 write('void vkExtInitInstance(VkInstance instance)\n{', file=self.outFile) 161 for pointerInitializer in self.pointerInitializersInstance: 162 write(pointerInitializer, file=self.outFile) 163 write('}', file=self.outFile) 164 165 self.newline() 166 167 write('void vkExtInitDevice(VkDevice device)\n{', file=self.outFile) 168 for pointerInitializer in self.pointerInitializersDevice: 169 write(pointerInitializer, file=self.outFile) 170 write('}', file=self.outFile) 171 172 self.newline() 173 174 #Finish header file 175 write('#ifdef __cplusplus', file=self.outFileHeader) 176 write('}', file=self.outFileHeader) 177 write('#endif', file=self.outFileHeader) 178 write('', file=self.outFileHeader) 179 write('#endif', file=self.outFileHeader) 180 self.outFileHeader.close() 181 182 # Finish processing in superclass 183 OutputGenerator.endFile(self) 184 185 def beginFeature(self, interface, emit): 186 # Start processing in superclass 187 OutputGenerator.beginFeature(self, interface, emit) 188 189 # Accumulate function pointers and function pointer initialization 190 self.featurePointers = [] 191 self.featurePointerInitializersInstance = [] 192 self.featurePointerInitializersDevice = [] 193 194 def endFeature(self): 195 # Add feature to global list with protectFeature 196 if (self.emit and self.featurePointers): 197 if (self.genOpts.protectFeature): 198 self.pointers.append('#ifdef ' + self.featureName) 199 self.pointerInitializersInstance.append('#ifdef ' + self.featureName) 200 self.pointerInitializersDevice.append('#ifdef ' + self.featureName) 201 202 if (self.featureExtraProtect != None): 203 self.pointers.append('#ifdef ' + self.featureExtraProtect) 204 self.pointerInitializersInstance.append('#ifndef ' + self.featureName) 205 self.pointerInitializersDevice.append('#ifndef ' + self.featureName) 206 207 self.pointers += self.featurePointers; 208 self.pointerInitializersInstance += self.featurePointerInitializersInstance; 209 self.pointerInitializersDevice += self.featurePointerInitializersDevice; 210 211 if (self.featureExtraProtect != None): 212 self.pointers.append('#endif /* ' + self.featureExtraProtect + ' */') 213 self.pointerInitializersInstance.append('#endif /* ' + self.featureExtraProtect + ' */') 214 self.pointerInitializersDevice.append('#endif /* ' + self.featureExtraProtect + ' */') 215 if (self.genOpts.protectFeature): 216 self.pointers.append('#endif /* ' + self.featureName + ' */') 217 self.pointerInitializersInstance.append('#endif /* ' + self.featureName + ' */') 218 self.pointerInitializersDevice.append('#endif /* ' + self.featureName + ' */') 219 220 # Finish processing in superclass 221 OutputGenerator.endFeature(self) 222 # 223 # Type generation 224 def genType(self, typeinfo, name, alias): 225 pass 226 227 def genStruct(self, typeinfo, typeName, alias): 228 pass 229 230 def genGroup(self, groupinfo, groupName, alias): 231 pass 232 233 def genEnum(self, enuminfo, name, alias): 234 pass 235 236 # 237 # Command generation 238 def genCmd(self, cmdinfo, name, alias): 239 OutputGenerator.genCmd(self, cmdinfo, name, alias) 240 241 # 242 decls = self.makeStub(cmdinfo.elem) 243 self.featurePointerInitializersInstance.append(decls[0]) 244 self.featurePointerInitializersDevice.append(decls[1]) 245 self.featurePointers.append(decls[2]) 246 247 # 248 # makeStub - return static declaration for function pointer and initialization of function pointer 249 # as a two-element list of strings. 250 # cmd - Element containing a <command> tag 251 def makeStub(self, cmd): 252 """Generate a stub function pointer <command> Element""" 253 proto = cmd.find('proto') 254 params = cmd.findall('param') 255 name = cmd.find('name') 256 257 # Begin accumulating prototype and typedef strings 258 pfnDecl = 'static ' 259 pfnDecl += noneStr(proto.text) 260 261 # Find the name tag and generate the function pointer and function pointer initialization code 262 nameTag = proto.find('name') 263 tail = noneStr(nameTag.tail) 264 returnType = noneStr(proto.find('type').text) 265 266 type = self.makeFunctionPointerType(nameTag.text, tail) 267 268 # For each child element, if it's a <name> wrap in appropriate 269 # declaration. Otherwise append its contents and tail con#tents. 270 stubDecl = '' 271 for elem in proto: 272 text = noneStr(elem.text) 273 tail = noneStr(elem.tail) 274 if (elem.tag == 'name'): 275 name = self.makeProtoName(text, tail) 276 stubDecl += name 277 else: 278 stubDecl += text + tail 279 280 pfnName = self.makeFunctionPointerName(nameTag.text, noneStr(tail)); 281 pfnDecl += type + ' ' + pfnName + ';' 282 283 # Now generate the stub function 284 pfnDecl += '\n' 285 286 # Now add the parameter declaration list, which is identical 287 # for prototypes and typedefs. Concatenate all the text from 288 # a <param> node without the tags. No tree walking required 289 # since all tags are ignored. 290 n = len(params) 291 paramdecl = '(\n' 292 293 pfnCall = '\n{\n ' + ('return ', '')[returnType == 'void'] + pfnName + '(\n' 294 # Indented parameters 295 if n > 0: 296 indentCallParam = '(\n' 297 indentdecl = '(\n' 298 for i in range(0,n): 299 callParam = '' 300 301 paramdecl += self.makeCParamDecl(params[i], self.genOpts.alignFuncParam) 302 pfnCall += self.makeCCallParam(params[i], self.genOpts.alignFuncParam) 303 if (i < n - 1): 304 paramdecl += ',\n' 305 pfnCall += ',\n' 306 else: 307 paramdecl += ')' 308 pfnCall += '\n );\n' 309 indentdecl += paramdecl 310 indentCallParam += pfnCall 311 else: 312 indentdecl = '(void);' 313 314 pfnCall += '}\n' 315 316 featureInstance = ' ' + pfnName + ' = ('+type+')vkGetInstanceProcAddr(instance, "' + name + '");' 317 featureDevice = ' ' + pfnName + ' = ('+type+')vkGetDeviceProcAddr(device, "' + name + '");' 318 return [featureInstance, featureDevice , pfnDecl + stubDecl + paramdecl + pfnCall] 319 320 # Return function pointer type for given function 321 def makeFunctionPointerType(self, name, tail): 322 return 'PFN_' + name + tail 323 324 # Return name of static variable which stores the function pointer for the given function 325 def makeFunctionPointerName(self, name, tail): 326 return 'pfn_' + name + tail 327 328 # 329 # makeCParamDecl - return a string which is an indented, formatted 330 # declaration for a <param> or <member> block (e.g. function parameter 331 # or structure/union member). 332 # param - Element (<param> or <member>) to format 333 # aligncol - if non-zero, attempt to align the nested <name> element 334 # at this column 335 def makeCCallParam(self, param, aligncol): 336 return ' ' + param.find('name').text 337