summaryrefslogtreecommitdiff
path: root/registry/vulkan/scripts/Retired/extensionStubSource.py
blob: b9ff837e66c79384e4b5994d8858989971394675 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/usr/bin/python3 -i
#
# Copyright 2013-2021 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's 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's 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