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