#!/usr/bin/python3 -i # # Copyright (c) 2015-2017 The Khronos Group Inc. # Copyright (c) 2015-2017 Valve Corporation # Copyright (c) 2015-2017 LunarG, Inc. # Copyright (c) 2015-2017 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Author: Mark Young # Author: Mark Lobodzinski import os,re,sys import xml.etree.ElementTree as etree from generator import * from collections import namedtuple from common_codegen import * ADD_INST_CMDS = ['vkCreateInstance', 'vkEnumerateInstanceExtensionProperties', 'vkEnumerateInstanceLayerProperties', 'vkEnumerateInstanceVersion'] # # LayerDispatchTableGeneratorOptions - subclass of GeneratorOptions. class LayerDispatchTableGeneratorOptions(GeneratorOptions): def __init__(self, filename = None, directory = '.', apiname = None, profile = None, versions = '.*', emitversions = '.*', defaultExtensions = None, addExtensions = None, removeExtensions = None, emitExtensions = None, sortProcedure = regSortFeatures, prefixText = "", genFuncPointers = True, protectFile = True, protectFeature = True, apicall = '', apientry = '', apientryp = '', indentFuncProto = True, indentFuncPointer = False, alignFuncParam = 0, expandEnumerants = True): GeneratorOptions.__init__(self, filename, directory, apiname, profile, versions, emitversions, defaultExtensions, addExtensions, removeExtensions, emitExtensions, sortProcedure) self.prefixText = prefixText self.prefixText = None self.apicall = apicall self.apientry = apientry self.apientryp = apientryp self.alignFuncParam = alignFuncParam self.expandEnumerants = expandEnumerants # # LayerDispatchTableOutputGenerator - subclass of OutputGenerator. # Generates dispatch table helper header files for LVL class LayerDispatchTableOutputGenerator(OutputGenerator): """Generate dispatch tables header based on XML element attributes""" def __init__(self, errFile = sys.stderr, warnFile = sys.stderr, diagFile = sys.stdout): OutputGenerator.__init__(self, errFile, warnFile, diagFile) # Internal state - accumulators for different inner block text self.ext_instance_dispatch_list = [] # List of extension entries for instance dispatch list self.ext_device_dispatch_list = [] # List of extension entries for device dispatch list self.core_commands = [] # List of CommandData records for core Vulkan commands self.ext_commands = [] # List of CommandData records for extension Vulkan commands self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl']) self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'protect', 'return_type', 'handle_type', 'params', 'cdecl']) # # Called once at the beginning of each run def beginFile(self, genOpts): OutputGenerator.beginFile(self, genOpts) # User-supplied prefix text, if any (list of strings) if (genOpts.prefixText): for s in genOpts.prefixText: write(s, file=self.outFile) # File Comment file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' file_comment += '// See layer_dispatch_table_generator.py for modifications\n' write(file_comment, file=self.outFile) # Copyright Notice copyright = '/*\n' copyright += ' * Copyright (c) 2015-2018 The Khronos Group Inc.\n' copyright += ' * Copyright (c) 2015-2018 Valve Corporation\n' copyright += ' * Copyright (c) 2015-2018 LunarG, Inc.\n' copyright += ' *\n' copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' copyright += ' * you may not use this file except in compliance with the License.\n' copyright += ' * You may obtain a copy of the License at\n' copyright += ' *\n' copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' copyright += ' *\n' copyright += ' * Unless required by applicable law or agreed to in writing, software\n' copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' copyright += ' * See the License for the specific language governing permissions and\n' copyright += ' * limitations under the License.\n' copyright += ' *\n' copyright += ' * Author: Mark Lobodzinski \n' copyright += ' * Author: Mark Young \n' copyright += ' */\n' preamble = '' if self.genOpts.filename == 'vk_layer_dispatch_table.h': preamble += '#pragma once\n' preamble += '\n' preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n' write(copyright, file=self.outFile) write(preamble, file=self.outFile) # # Write generate and write dispatch tables to output file def endFile(self): file_data = '' if self.genOpts.filename == 'vk_layer_dispatch_table.h': file_data += self.OutputLayerInstanceDispatchTable() file_data += self.OutputLayerDeviceDispatchTable() write(file_data, file=self.outFile); # Finish processing in superclass OutputGenerator.endFile(self) def beginFeature(self, interface, emit): # Start processing in superclass OutputGenerator.beginFeature(self, interface, emit) self.featureExtraProtect = GetFeatureProtect(interface) enums = interface[0].findall('enum') self.currentExtension = '' self.type = interface.get('type') self.num_commands = 0 name = interface.get('name') self.currentExtension = name # # Process commands, adding to appropriate dispatch tables def genCmd(self, cmdinfo, name, alias): OutputGenerator.genCmd(self, cmdinfo, name, alias) # Get first param type params = cmdinfo.elem.findall('param') info = self.getTypeNameTuple(params[0]) self.num_commands += 1 if 'android' not in name: self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0]) def endFeature(self): # Finish processing in superclass OutputGenerator.endFeature(self) # # Retrieve the value of the len tag def getLen(self, param): result = None len = param.attrib.get('len') if len and len != 'null-terminated': # For string arrays, 'len' can look like 'count,null-terminated', # indicating that we have a null terminated array of strings. We # strip the null-terminated from the 'len' field and only return # the parameter specifying the string count if 'null-terminated' in len: result = len.split(',')[0] else: result = len result = str(result).replace('::', '->') return result # # Determine if this API should be ignored or added to the instance or device dispatch table def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type): handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") return_type = cmdinfo.elem.find('proto/type') if (return_type is not None and return_type.text == 'void'): return_type = None cmd_params = [] # Generate a list of commands for use in printing the necessary # core instance terminator prototypes params = cmdinfo.elem.findall('param') lens = set() for param in params: len = self.getLen(param) if len: lens.add(len) paramsInfo = [] for param in params: paramInfo = self.getTypeNameTuple(param) param_type = paramInfo[0] param_name = paramInfo[1] param_cdecl = self.makeCParamDecl(param, 0) cmd_params.append(self.CommandParam(type=param_type, name=param_name, cdecl=param_cdecl)) if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice': # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality if 'VK_VERSION_' in extension_name: self.core_commands.append( self.CommandData(name=name, ext_name=extension_name, ext_type='device', protect=self.featureExtraProtect, return_type = return_type, handle_type = handle_type, params = cmd_params, cdecl=self.makeCDecls(cmdinfo.elem)[0])) else: self.ext_device_dispatch_list.append((name, self.featureExtraProtect)) self.ext_commands.append( self.CommandData(name=name, ext_name=extension_name, ext_type=extension_type, protect=self.featureExtraProtect, return_type = return_type, handle_type = handle_type, params = cmd_params, cdecl=self.makeCDecls(cmdinfo.elem)[0])) else: # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality if 'VK_VERSION_' in extension_name: self.core_commands.append( self.CommandData(name=name, ext_name=extension_name, ext_type='instance', protect=self.featureExtraProtect, return_type = return_type, handle_type = handle_type, params = cmd_params, cdecl=self.makeCDecls(cmdinfo.elem)[0])) else: self.ext_instance_dispatch_list.append((name, self.featureExtraProtect)) self.ext_commands.append( self.CommandData(name=name, ext_name=extension_name, ext_type=extension_type, protect=self.featureExtraProtect, return_type = return_type, handle_type = handle_type, params = cmd_params, cdecl=self.makeCDecls(cmdinfo.elem)[0])) # # Retrieve the type and name for a parameter def getTypeNameTuple(self, param): type = '' name = '' for elem in param: if elem.tag == 'type': type = noneStr(elem.text) elif elem.tag == 'name': name = noneStr(elem.text) return (type, name) # # Create a layer instance dispatch table from the appropriate list and return it as a string def OutputLayerInstanceDispatchTable(self): commands = [] table = '' cur_extension_name = '' table += '// Instance function pointer dispatch table\n' table += 'typedef struct VkLayerInstanceDispatchTable_ {\n' # First add in an entry for GetPhysicalDeviceProcAddr. This will not # ever show up in the XML or header, so we have to manually add it. table += ' // Manually add in GetPhysicalDeviceProcAddr entry\n' table += ' PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n' for x in range(0, 2): if x == 0: commands = self.core_commands else: commands = self.ext_commands for cur_cmd in commands: is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' if is_inst_handle_type: if cur_cmd.ext_name != cur_extension_name: if 'VK_VERSION_' in cur_cmd.ext_name: table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:] else: table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name cur_extension_name = cur_cmd.ext_name # Remove 'vk' from proto name base_name = cur_cmd.name[2:] if cur_cmd.protect is not None: table += '#ifdef %s\n' % cur_cmd.protect table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) if cur_cmd.protect is not None: table += '#endif // %s\n' % cur_cmd.protect table += '} VkLayerInstanceDispatchTable;\n\n' return table # # Create a layer device dispatch table from the appropriate list and return it as a string def OutputLayerDeviceDispatchTable(self): commands = [] table = '' cur_extension_name = '' table += '// Device function pointer dispatch table\n' table += 'typedef struct VkLayerDispatchTable_ {\n' for x in range(0, 2): if x == 0: commands = self.core_commands else: commands = self.ext_commands for cur_cmd in commands: is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' if not is_inst_handle_type: if cur_cmd.ext_name != cur_extension_name: if 'VK_VERSION_' in cur_cmd.ext_name: table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:] else: table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name cur_extension_name = cur_cmd.ext_name # Remove 'vk' from proto name base_name = cur_cmd.name[2:] if cur_cmd.protect is not None: table += '#ifdef %s\n' % cur_cmd.protect table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) if cur_cmd.protect is not None: table += '#endif // %s\n' % cur_cmd.protect table += '} VkLayerDispatchTable;\n\n' return table