Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/python3 -i
      2 #
      3 # Copyright (c) 2015-2017 The Khronos Group Inc.
      4 # Copyright (c) 2015-2017 Valve Corporation
      5 # Copyright (c) 2015-2017 LunarG, Inc.
      6 # Copyright (c) 2015-2017 Google Inc.
      7 #
      8 # Licensed under the Apache License, Version 2.0 (the "License");
      9 # you may not use this file except in compliance with the License.
     10 # You may obtain a copy of the License at
     11 #
     12 #     http://www.apache.org/licenses/LICENSE-2.0
     13 #
     14 # Unless required by applicable law or agreed to in writing, software
     15 # distributed under the License is distributed on an "AS IS" BASIS,
     16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17 # See the License for the specific language governing permissions and
     18 # limitations under the License.
     19 #
     20 # Author: Mark Lobodzinski <mark (at] lunarg.com>
     21 
     22 import os,re,sys
     23 import xml.etree.ElementTree as etree
     24 from generator import *
     25 from collections import namedtuple
     26 
     27 #
     28 # DispatchTableHelperOutputGeneratorOptions - subclass of GeneratorOptions.
     29 class DispatchTableHelperOutputGeneratorOptions(GeneratorOptions):
     30     def __init__(self,
     31                  filename = None,
     32                  directory = '.',
     33                  apiname = None,
     34                  profile = None,
     35                  versions = '.*',
     36                  emitversions = '.*',
     37                  defaultExtensions = None,
     38                  addExtensions = None,
     39                  removeExtensions = None,
     40                  sortProcedure = regSortFeatures,
     41                  prefixText = "",
     42                  genFuncPointers = True,
     43                  protectFile = True,
     44                  protectFeature = True,
     45                  protectProto = None,
     46                  protectProtoStr = None,
     47                  apicall = '',
     48                  apientry = '',
     49                  apientryp = '',
     50                  alignFuncParam = 0):
     51         GeneratorOptions.__init__(self, filename, directory, apiname, profile,
     52                                   versions, emitversions, defaultExtensions,
     53                                   addExtensions, removeExtensions, sortProcedure)
     54         self.prefixText      = prefixText
     55         self.genFuncPointers = genFuncPointers
     56         self.prefixText      = None
     57         self.protectFile     = protectFile
     58         self.protectFeature  = protectFeature
     59         self.protectProto    = protectProto
     60         self.protectProtoStr = protectProtoStr
     61         self.apicall         = apicall
     62         self.apientry        = apientry
     63         self.apientryp       = apientryp
     64         self.alignFuncParam  = alignFuncParam
     65 #
     66 # DispatchTableHelperOutputGenerator - subclass of OutputGenerator.
     67 # Generates dispatch table helper header files for LVL
     68 class DispatchTableHelperOutputGenerator(OutputGenerator):
     69     """Generate dispatch table helper header based on XML element attributes"""
     70     def __init__(self,
     71                  errFile = sys.stderr,
     72                  warnFile = sys.stderr,
     73                  diagFile = sys.stdout):
     74         OutputGenerator.__init__(self, errFile, warnFile, diagFile)
     75         # Internal state - accumulators for different inner block text
     76         self.instance_dispatch_list = []      # List of entries for instance dispatch list
     77         self.device_dispatch_list = []        # List of entries for device dispatch list
     78     #
     79     # Called once at the beginning of each run
     80     def beginFile(self, genOpts):
     81         OutputGenerator.beginFile(self, genOpts)
     82         # Protect against multiple inclusions
     83         self.protect_header = False
     84         if (genOpts.protectFile and genOpts.filename):
     85             self.protect_header = True
     86             headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(genOpts.filename))
     87             write('#ifndef', headerSym, file=self.outFile)
     88             write('#define', headerSym, '1', file=self.outFile)
     89             self.newline()
     90         # User-supplied prefix text, if any (list of strings)
     91         if (genOpts.prefixText):
     92             for s in genOpts.prefixText:
     93                 write(s, file=self.outFile)
     94         # File Comment
     95         file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
     96         file_comment += '// See dispatch_helper_generator.py for modifications\n'
     97         write(file_comment, file=self.outFile)
     98         # Copyright Notice
     99         copyright =  '/*\n'
    100         copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n'
    101         copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n'
    102         copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n'
    103         copyright += ' *\n'
    104         copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
    105         copyright += ' * you may not use this file except in compliance with the License.\n'
    106         copyright += ' * You may obtain a copy of the License at\n'
    107         copyright += ' *\n'
    108         copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
    109         copyright += ' *\n'
    110         copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
    111         copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
    112         copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
    113         copyright += ' * See the License for the specific language governing permissions and\n'
    114         copyright += ' * limitations under the License.\n'
    115         copyright += ' *\n'
    116         copyright += ' * Author: Courtney Goeltzenleuchter <courtney (at] LunarG.com>\n'
    117         copyright += ' * Author: Jon Ashburn <jon (at] lunarg.com>\n'
    118         copyright += ' * Author: Mark Lobodzinski <mark (at] lunarg.com>\n'
    119         copyright += ' */\n'
    120 
    121         preamble = ''
    122         preamble += '#include <vulkan/vulkan.h>\n'
    123         preamble += '#include <vulkan/vk_layer.h>\n'
    124         preamble += '#include <string.h>\n'
    125 
    126         write(copyright, file=self.outFile)
    127         write(preamble, file=self.outFile)
    128     #
    129     # Write generate and write dispatch tables to output file
    130     def endFile(self):
    131         device_table = ''
    132         instance_table = ''
    133 
    134         device_table += self.OutputDispatchTableHelper('device')
    135         instance_table += self.OutputDispatchTableHelper('instance')
    136 
    137         write(device_table, file=self.outFile);
    138         write("\n", file=self.outFile)
    139         write(instance_table, file=self.outFile);
    140 
    141         if self.protect_header:
    142             self.newline()
    143             write('#endif', file=self.outFile)
    144         # Finish processing in superclass
    145         OutputGenerator.endFile(self)
    146     #
    147     # Process commands, adding to appropriate dispatch tables
    148     def genCmd(self, cmdinfo, name):
    149         OutputGenerator.genCmd(self, cmdinfo, name)
    150 
    151         avoid_entries = ['vkCreateInstance',
    152                          'vkCreateDevice']
    153         # Get first param type
    154         params = cmdinfo.elem.findall('param')
    155         info = self.getTypeNameTuple(params[0])
    156 
    157         if name not in avoid_entries:
    158             self.AddCommandToDispatchList(name, info[0], self.featureExtraProtect)
    159 
    160     #
    161     # Determine if this API should be ignored or added to the instance or device dispatch table
    162     def AddCommandToDispatchList(self, name, handle_type, protect):
    163         handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
    164         if handle == None:
    165             return
    166         if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr':
    167             self.device_dispatch_list.append((name, self.featureExtraProtect))
    168         else:
    169             self.instance_dispatch_list.append((name, self.featureExtraProtect))
    170         return
    171     #
    172     # Retrieve the type and name for a parameter
    173     def getTypeNameTuple(self, param):
    174         type = ''
    175         name = ''
    176         for elem in param:
    177             if elem.tag == 'type':
    178                 type = noneStr(elem.text)
    179             elif elem.tag == 'name':
    180                 name = noneStr(elem.text)
    181         return (type, name)
    182     #
    183     # Create a dispatch table from the appropriate list and return it as a string
    184     def OutputDispatchTableHelper(self, table_type):
    185         entries = []
    186         table = ''
    187         if table_type == 'device':
    188             entries = self.device_dispatch_list
    189             table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa) {\n'
    190             table += '    memset(table, 0, sizeof(*table));\n'
    191             table += '    // Device function pointers\n'
    192         else:
    193             entries = self.instance_dispatch_list
    194             table += 'static inline void layer_init_instance_dispatch_table(VkInstance instance, VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa) {\n'
    195             table += '    memset(table, 0, sizeof(*table));\n'
    196             table += '    // Instance function pointers\n'
    197 
    198         for item in entries:
    199             # Remove 'vk' from proto name
    200             base_name = item[0][2:]
    201 
    202             if item[1] is not None:
    203                 table += '#ifdef %s\n' % item[1]
    204 
    205             # If we're looking for the proc we are passing in, just point the table to it.  This fixes the issue where
    206             # a layer overrides the function name for the loader.
    207             if (table_type == 'device' and base_name == 'GetDeviceProcAddr'):
    208                 table += '    table->GetDeviceProcAddr = gpa;\n'
    209             elif (table_type != 'device' and base_name == 'GetInstanceProcAddr'):
    210                 table += '    table->GetInstanceProcAddr = gpa;\n'
    211             else:
    212                 table += '    table->%s = (PFN_%s) gpa(%s, "%s");\n' % (base_name, item[0], table_type, item[0])
    213 
    214             if item[1] is not None:
    215                 table += '#endif // %s\n' % item[1]
    216         table += '}'
    217         return table
    218