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 Young <marky (at] lunarg.com>
     21 # Author: Mark Lobodzinski <mark (at] lunarg.com>
     22 
     23 import os,re,sys
     24 import xml.etree.ElementTree as etree
     25 from generator import *
     26 from collections import namedtuple
     27 from common_codegen import *
     28 
     29 ADD_INST_CMDS = ['vkCreateInstance',
     30                  'vkEnumerateInstanceExtensionProperties',
     31                  'vkEnumerateInstanceLayerProperties',
     32                  'vkEnumerateInstanceVersion']
     33 
     34 #
     35 # LayerDispatchTableGeneratorOptions - subclass of GeneratorOptions.
     36 class LayerDispatchTableGeneratorOptions(GeneratorOptions):
     37     def __init__(self,
     38                  filename = None,
     39                  directory = '.',
     40                  apiname = None,
     41                  profile = None,
     42                  versions = '.*',
     43                  emitversions = '.*',
     44                  defaultExtensions = None,
     45                  addExtensions = None,
     46                  removeExtensions = None,
     47                  emitExtensions = None,
     48                  sortProcedure = regSortFeatures,
     49                  prefixText = "",
     50                  genFuncPointers = True,
     51                  protectFile = True,
     52                  protectFeature = True,
     53                  apicall = '',
     54                  apientry = '',
     55                  apientryp = '',
     56                  indentFuncProto = True,
     57                  indentFuncPointer = False,
     58                  alignFuncParam = 0,
     59                  expandEnumerants = True):
     60         GeneratorOptions.__init__(self, filename, directory, apiname, profile,
     61                                   versions, emitversions, defaultExtensions,
     62                                   addExtensions, removeExtensions, emitExtensions, sortProcedure)
     63         self.prefixText      = prefixText
     64         self.prefixText      = None
     65         self.apicall         = apicall
     66         self.apientry        = apientry
     67         self.apientryp       = apientryp
     68         self.alignFuncParam  = alignFuncParam
     69         self.expandEnumerants = expandEnumerants
     70 
     71 #
     72 # LayerDispatchTableOutputGenerator - subclass of OutputGenerator.
     73 # Generates dispatch table helper header files for LVL
     74 class LayerDispatchTableOutputGenerator(OutputGenerator):
     75     """Generate dispatch tables header based on XML element attributes"""
     76     def __init__(self,
     77                  errFile = sys.stderr,
     78                  warnFile = sys.stderr,
     79                  diagFile = sys.stdout):
     80         OutputGenerator.__init__(self, errFile, warnFile, diagFile)
     81 
     82         # Internal state - accumulators for different inner block text
     83         self.ext_instance_dispatch_list = []  # List of extension entries for instance dispatch list
     84         self.ext_device_dispatch_list = []    # List of extension entries for device dispatch list
     85         self.core_commands = []               # List of CommandData records for core Vulkan commands
     86         self.ext_commands = []                # List of CommandData records for extension Vulkan commands
     87         self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl'])
     88         self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'protect', 'return_type', 'handle_type', 'params', 'cdecl'])
     89 
     90     #
     91     # Called once at the beginning of each run
     92     def beginFile(self, genOpts):
     93         OutputGenerator.beginFile(self, genOpts)
     94 
     95         # User-supplied prefix text, if any (list of strings)
     96         if (genOpts.prefixText):
     97             for s in genOpts.prefixText:
     98                 write(s, file=self.outFile)
     99 
    100         # File Comment
    101         file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n'
    102         file_comment += '// See layer_dispatch_table_generator.py for modifications\n'
    103         write(file_comment, file=self.outFile)
    104 
    105         # Copyright Notice
    106         copyright =  '/*\n'
    107         copyright += ' * Copyright (c) 2015-2018 The Khronos Group Inc.\n'
    108         copyright += ' * Copyright (c) 2015-2018 Valve Corporation\n'
    109         copyright += ' * Copyright (c) 2015-2018 LunarG, Inc.\n'
    110         copyright += ' *\n'
    111         copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n'
    112         copyright += ' * you may not use this file except in compliance with the License.\n'
    113         copyright += ' * You may obtain a copy of the License at\n'
    114         copyright += ' *\n'
    115         copyright += ' *     http://www.apache.org/licenses/LICENSE-2.0\n'
    116         copyright += ' *\n'
    117         copyright += ' * Unless required by applicable law or agreed to in writing, software\n'
    118         copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n'
    119         copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n'
    120         copyright += ' * See the License for the specific language governing permissions and\n'
    121         copyright += ' * limitations under the License.\n'
    122         copyright += ' *\n'
    123         copyright += ' * Author: Mark Lobodzinski <mark (at] lunarg.com>\n'
    124         copyright += ' * Author: Mark Young <marky (at] lunarg.com>\n'
    125         copyright += ' */\n'
    126 
    127         preamble = ''
    128         if self.genOpts.filename == 'vk_layer_dispatch_table.h':
    129             preamble += '#pragma once\n'
    130             preamble += '\n'
    131             preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n'
    132 
    133         write(copyright, file=self.outFile)
    134         write(preamble, file=self.outFile)
    135 
    136     #
    137     # Write generate and write dispatch tables to output file
    138     def endFile(self):
    139         file_data = ''
    140         if self.genOpts.filename == 'vk_layer_dispatch_table.h':
    141             file_data += self.OutputLayerInstanceDispatchTable()
    142             file_data += self.OutputLayerDeviceDispatchTable()
    143 
    144         write(file_data, file=self.outFile);
    145 
    146         # Finish processing in superclass
    147         OutputGenerator.endFile(self)
    148 
    149     def beginFeature(self, interface, emit):
    150         # Start processing in superclass
    151         OutputGenerator.beginFeature(self, interface, emit)
    152         self.featureExtraProtect = GetFeatureProtect(interface)
    153 
    154         enums = interface[0].findall('enum')
    155         self.currentExtension = ''
    156 
    157         self.type = interface.get('type')
    158         self.num_commands = 0
    159         name = interface.get('name')
    160         self.currentExtension = name
    161 
    162     #
    163     # Process commands, adding to appropriate dispatch tables
    164     def genCmd(self, cmdinfo, name, alias):
    165         OutputGenerator.genCmd(self, cmdinfo, name, alias)
    166 
    167         # Get first param type
    168         params = cmdinfo.elem.findall('param')
    169         info = self.getTypeNameTuple(params[0])
    170 
    171         self.num_commands += 1
    172 
    173         if 'android' not in name:
    174             self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0])
    175 
    176     def endFeature(self):
    177         # Finish processing in superclass
    178         OutputGenerator.endFeature(self)
    179 
    180     #
    181     # Retrieve the value of the len tag
    182     def getLen(self, param):
    183         result = None
    184         len = param.attrib.get('len')
    185         if len and len != 'null-terminated':
    186             # For string arrays, 'len' can look like 'count,null-terminated',
    187             # indicating that we have a null terminated array of strings.  We
    188             # strip the null-terminated from the 'len' field and only return
    189             # the parameter specifying the string count
    190             if 'null-terminated' in len:
    191                 result = len.split(',')[0]
    192             else:
    193                 result = len
    194             result = str(result).replace('::', '->')
    195         return result
    196 
    197     #
    198     # Determine if this API should be ignored or added to the instance or device dispatch table
    199     def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
    200         handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
    201 
    202         return_type =  cmdinfo.elem.find('proto/type')
    203         if (return_type is not None and return_type.text == 'void'):
    204            return_type = None
    205 
    206         cmd_params = []
    207 
    208         # Generate a list of commands for use in printing the necessary
    209         # core instance terminator prototypes
    210         params = cmdinfo.elem.findall('param')
    211         lens = set()
    212         for param in params:
    213             len = self.getLen(param)
    214             if len:
    215                 lens.add(len)
    216         paramsInfo = []
    217         for param in params:
    218             paramInfo = self.getTypeNameTuple(param)
    219             param_type = paramInfo[0]
    220             param_name = paramInfo[1]
    221             param_cdecl = self.makeCParamDecl(param, 0)
    222             cmd_params.append(self.CommandParam(type=param_type, name=param_name,
    223                                                 cdecl=param_cdecl))
    224 
    225         if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
    226             # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
    227             # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
    228             if 'VK_VERSION_' in extension_name:
    229                 self.core_commands.append(
    230                     self.CommandData(name=name, ext_name=extension_name,
    231                                      ext_type='device',
    232                                      protect=self.featureExtraProtect,
    233                                      return_type = return_type,
    234                                      handle_type = handle_type,
    235                                      params = cmd_params,
    236                                      cdecl=self.makeCDecls(cmdinfo.elem)[0]))
    237             else:
    238                 self.ext_device_dispatch_list.append((name, self.featureExtraProtect))
    239                 self.ext_commands.append(
    240                     self.CommandData(name=name, ext_name=extension_name,
    241                                      ext_type=extension_type,
    242                                      protect=self.featureExtraProtect,
    243                                      return_type = return_type,
    244                                      handle_type = handle_type,
    245                                      params = cmd_params,
    246                                      cdecl=self.makeCDecls(cmdinfo.elem)[0]))
    247         else:
    248             # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
    249             # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
    250             if 'VK_VERSION_' in extension_name:
    251                 self.core_commands.append(
    252                     self.CommandData(name=name, ext_name=extension_name,
    253                                      ext_type='instance',
    254                                      protect=self.featureExtraProtect,
    255                                      return_type = return_type,
    256                                      handle_type = handle_type,
    257                                      params = cmd_params,
    258                                      cdecl=self.makeCDecls(cmdinfo.elem)[0]))
    259 
    260             else:
    261                 self.ext_instance_dispatch_list.append((name, self.featureExtraProtect))
    262                 self.ext_commands.append(
    263                     self.CommandData(name=name, ext_name=extension_name,
    264                                      ext_type=extension_type,
    265                                      protect=self.featureExtraProtect,
    266                                      return_type = return_type,
    267                                      handle_type = handle_type,
    268                                      params = cmd_params,
    269                                      cdecl=self.makeCDecls(cmdinfo.elem)[0]))
    270 
    271     #
    272     # Retrieve the type and name for a parameter
    273     def getTypeNameTuple(self, param):
    274         type = ''
    275         name = ''
    276         for elem in param:
    277             if elem.tag == 'type':
    278                 type = noneStr(elem.text)
    279             elif elem.tag == 'name':
    280                 name = noneStr(elem.text)
    281         return (type, name)
    282 
    283     #
    284     # Create a layer instance dispatch table from the appropriate list and return it as a string
    285     def OutputLayerInstanceDispatchTable(self):
    286         commands = []
    287         table = ''
    288         cur_extension_name = ''
    289 
    290         table += '// Instance function pointer dispatch table\n'
    291         table += 'typedef struct VkLayerInstanceDispatchTable_ {\n'
    292 
    293         # First add in an entry for GetPhysicalDeviceProcAddr.  This will not
    294         # ever show up in the XML or header, so we have to manually add it.
    295         table += '    // Manually add in GetPhysicalDeviceProcAddr entry\n'
    296         table += '    PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n'
    297 
    298         for x in range(0, 2):
    299             if x == 0:
    300                 commands = self.core_commands
    301             else:
    302                 commands = self.ext_commands
    303 
    304             for cur_cmd in commands:
    305                 is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
    306                 if is_inst_handle_type:
    307 
    308                     if cur_cmd.ext_name != cur_extension_name:
    309                         if 'VK_VERSION_' in cur_cmd.ext_name:
    310                             table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
    311                         else:
    312                             table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
    313                         cur_extension_name = cur_cmd.ext_name
    314 
    315                     # Remove 'vk' from proto name
    316                     base_name = cur_cmd.name[2:]
    317 
    318                     if cur_cmd.protect is not None:
    319                         table += '#ifdef %s\n' % cur_cmd.protect
    320 
    321                     table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
    322 
    323                     if cur_cmd.protect is not None:
    324                         table += '#endif // %s\n' % cur_cmd.protect
    325 
    326         table += '} VkLayerInstanceDispatchTable;\n\n'
    327         return table
    328 
    329     #
    330     # Create a layer device dispatch table from the appropriate list and return it as a string
    331     def OutputLayerDeviceDispatchTable(self):
    332         commands = []
    333         table = ''
    334         cur_extension_name = ''
    335 
    336         table += '// Device function pointer dispatch table\n'
    337         table += 'typedef struct VkLayerDispatchTable_ {\n'
    338 
    339         for x in range(0, 2):
    340             if x == 0:
    341                 commands = self.core_commands
    342             else:
    343                 commands = self.ext_commands
    344 
    345             for cur_cmd in commands:
    346                 is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
    347                 if not is_inst_handle_type:
    348 
    349                     if cur_cmd.ext_name != cur_extension_name:
    350                         if 'VK_VERSION_' in cur_cmd.ext_name:
    351                             table += '\n    // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
    352                         else:
    353                             table += '\n    // ---- %s extension commands\n' % cur_cmd.ext_name
    354                         cur_extension_name = cur_cmd.ext_name
    355 
    356                     # Remove 'vk' from proto name
    357                     base_name = cur_cmd.name[2:]
    358 
    359                     if cur_cmd.protect is not None:
    360                         table += '#ifdef %s\n' % cur_cmd.protect
    361 
    362                     table += '    PFN_%s %s;\n' % (cur_cmd.name, base_name)
    363 
    364                     if cur_cmd.protect is not None:
    365                         table += '#endif // %s\n' % cur_cmd.protect
    366 
    367         table += '} VkLayerDispatchTable;\n\n'
    368         return table
    369