/ scripts / Retired / extensionStubSource.py
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