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