• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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