1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2015-2021 The Khronos Group Inc. 4# Copyright (c) 2015-2021 Valve Corporation 5# Copyright (c) 2015-2021 LunarG, Inc. 6# Copyright (c) 2015-2021 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@lunarg.com> 21 22import os,re,sys 23import xml.etree.ElementTree as etree 24from generator import * 25from collections import namedtuple 26from common_codegen import * 27 28return_type_table = {"VkResult": "VK_SUCCESS", 29 "uint32_t": "0", 30 "uint64_t": "0L", 31 "VkDeviceAddress": "0L", 32 "VkDeviceSize": "0L"} 33 34# 35# DispatchTableHelperOutputGeneratorOptions - subclass of GeneratorOptions. 36class DispatchTableHelperOutputGeneratorOptions(GeneratorOptions): 37 def __init__(self, 38 conventions = None, 39 filename = None, 40 directory = '.', 41 genpath = None, 42 apiname = None, 43 profile = None, 44 versions = '.*', 45 emitversions = '.*', 46 defaultExtensions = None, 47 addExtensions = None, 48 removeExtensions = None, 49 emitExtensions = None, 50 sortProcedure = regSortFeatures, 51 prefixText = "", 52 genFuncPointers = True, 53 apicall = '', 54 apientry = '', 55 apientryp = '', 56 alignFuncParam = 0, 57 expandEnumerants = True): 58 GeneratorOptions.__init__(self, 59 conventions = conventions, 60 filename = filename, 61 directory = directory, 62 genpath = genpath, 63 apiname = apiname, 64 profile = profile, 65 versions = versions, 66 emitversions = emitversions, 67 defaultExtensions = defaultExtensions, 68 addExtensions = addExtensions, 69 removeExtensions = removeExtensions, 70 emitExtensions = emitExtensions, 71 sortProcedure = sortProcedure) 72 self.prefixText = prefixText 73 self.genFuncPointers = genFuncPointers 74 self.prefixText = None 75 self.apicall = apicall 76 self.apientry = apientry 77 self.apientryp = apientryp 78 self.alignFuncParam = alignFuncParam 79# 80# DispatchTableHelperOutputGenerator - subclass of OutputGenerator. 81# Generates dispatch table helper header files for LVL 82class DispatchTableHelperOutputGenerator(OutputGenerator): 83 """Generate dispatch table helper header based on XML element attributes""" 84 def __init__(self, 85 errFile = sys.stderr, 86 warnFile = sys.stderr, 87 diagFile = sys.stdout): 88 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 89 # Internal state - accumulators for different inner block text 90 self.instance_dispatch_list = [] # List of entries for instance dispatch list 91 self.device_dispatch_list = [] # List of entries for device dispatch list 92 self.dev_ext_stub_list = [] # List of stub functions for device extension functions 93 self.device_extension_list = [] # List of device extension functions 94 self.extension_type = '' 95 # 96 # Called once at the beginning of each run 97 def beginFile(self, genOpts): 98 OutputGenerator.beginFile(self, genOpts) 99 write("#pragma once", file=self.outFile) 100 # User-supplied prefix text, if any (list of strings) 101 if (genOpts.prefixText): 102 for s in genOpts.prefixText: 103 write(s, file=self.outFile) 104 # File Comment 105 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 106 file_comment += '// See dispatch_helper_generator.py for modifications\n' 107 write(file_comment, file=self.outFile) 108 # Copyright Notice 109 copyright = '/*\n' 110 copyright += ' * Copyright (c) 2015-2021 The Khronos Group Inc.\n' 111 copyright += ' * Copyright (c) 2015-2021 Valve Corporation\n' 112 copyright += ' * Copyright (c) 2015-2021 LunarG, Inc.\n' 113 copyright += ' *\n' 114 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 115 copyright += ' * you may not use this file except in compliance with the License.\n' 116 copyright += ' * You may obtain a copy of the License at\n' 117 copyright += ' *\n' 118 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 119 copyright += ' *\n' 120 copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 121 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 122 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 123 copyright += ' * See the License for the specific language governing permissions and\n' 124 copyright += ' * limitations under the License.\n' 125 copyright += ' *\n' 126 copyright += ' * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>\n' 127 copyright += ' * Author: Jon Ashburn <jon@lunarg.com>\n' 128 copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n' 129 copyright += ' */\n' 130 131 preamble = '' 132 preamble += '#include <vulkan/vulkan.h>\n' 133 preamble += '#include <vulkan/vk_layer.h>\n' 134 preamble += '#include <string.h>\n' 135 preamble += '#include "vk_layer_dispatch_table.h"\n' 136 137 write(copyright, file=self.outFile) 138 write(preamble, file=self.outFile) 139 # 140 # Write generate and write dispatch tables to output file 141 def endFile(self): 142 device_table = '' 143 instance_table = '' 144 145 device_table += self.OutputDispatchTableHelper('device') 146 instance_table += self.OutputDispatchTableHelper('instance') 147 148 for stub in self.dev_ext_stub_list: 149 write(stub, file=self.outFile) 150 write("\n\n", file=self.outFile) 151 write(device_table, file=self.outFile); 152 write("\n", file=self.outFile) 153 write(instance_table, file=self.outFile); 154 155 # Finish processing in superclass 156 OutputGenerator.endFile(self) 157 # 158 # Processing at beginning of each feature or extension 159 def beginFeature(self, interface, emit): 160 OutputGenerator.beginFeature(self, interface, emit) 161 self.featureExtraProtect = GetFeatureProtect(interface) 162 self.extension_type = interface.get('type') 163 164 # 165 # Process commands, adding to appropriate dispatch tables 166 def genCmd(self, cmdinfo, name, alias): 167 OutputGenerator.genCmd(self, cmdinfo, name, alias) 168 169 avoid_entries = ['vkCreateInstance', 170 'vkCreateDevice'] 171 # Get first param type 172 params = cmdinfo.elem.findall('param') 173 info = self.getTypeNameTuple(params[0]) 174 175 if name not in avoid_entries: 176 self.AddCommandToDispatchList(name, info[0], self.featureExtraProtect, cmdinfo) 177 178 # 179 # Determine if this API should be ignored or added to the instance or device dispatch table 180 def AddCommandToDispatchList(self, name, handle_type, protect, cmdinfo): 181 handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") 182 if handle is None: 183 return 184 if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr': 185 self.device_dispatch_list.append((name, self.featureExtraProtect)) 186 if "VK_VERSION" not in self.featureName and self.extension_type == 'device': 187 self.device_extension_list.append(name) 188 # Build up stub function 189 decl = self.makeCDecls(cmdinfo.elem)[1] 190 return_type = cmdinfo.elem.find('proto/type').text 191 return_statement = "" # default type is void, so no return type 192 try: 193 return_statement = 'return ' + return_type_table[return_type] + ';' 194 except KeyError: 195 if return_type != "void": 196 raise AssertionError("return_type_table does not contain all possible types. Add an entry for `" + return_type + "`.") 197 decl = decl.split('*PFN_vk')[1] 198 decl = decl.replace(')(', '(') 199 decl = 'static VKAPI_ATTR ' + return_type + ' VKAPI_CALL Stub' + decl 200 func_body = ' { ' + return_statement + ' }' 201 decl = decl.replace (';', func_body) 202 if self.featureExtraProtect is not None: 203 self.dev_ext_stub_list.append('#ifdef %s' % self.featureExtraProtect) 204 self.dev_ext_stub_list.append(decl) 205 if self.featureExtraProtect is not None: 206 self.dev_ext_stub_list.append('#endif // %s' % self.featureExtraProtect) 207 else: 208 self.instance_dispatch_list.append((name, self.featureExtraProtect)) 209 return 210 # 211 # Retrieve the type and name for a parameter 212 def getTypeNameTuple(self, param): 213 type = '' 214 name = '' 215 for elem in param: 216 if elem.tag == 'type': 217 type = noneStr(elem.text) 218 elif elem.tag == 'name': 219 name = noneStr(elem.text) 220 return (type, name) 221 # 222 # Create a dispatch table from the appropriate list and return it as a string 223 def OutputDispatchTableHelper(self, table_type): 224 entries = [] 225 table = '' 226 if table_type == 'device': 227 entries = self.device_dispatch_list 228 table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa) {\n' 229 table += ' memset(table, 0, sizeof(*table));\n' 230 table += ' table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n\n' 231 table += ' // Device function pointers\n' 232 else: 233 entries = self.instance_dispatch_list 234 table += 'static inline void layer_init_instance_dispatch_table(VkInstance instance, VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa) {\n' 235 table += ' memset(table, 0, sizeof(*table));\n\n' 236 table += ' // Instance function pointers\n' 237 238 for item in entries: 239 # Remove 'vk' from proto name 240 base_name = item[0][2:] 241 242 if item[1] is not None: 243 table += '#ifdef %s\n' % item[1] 244 245 # If we're looking for the proc we are passing in, just point the table to it. This fixes the issue where 246 # a layer overrides the function name for the loader. 247 if (table_type == 'device' and base_name == 'GetDeviceProcAddr'): 248 table += ' table->GetDeviceProcAddr = gpa;\n' 249 elif (table_type != 'device' and base_name == 'GetInstanceProcAddr'): 250 table += ' table->GetInstanceProcAddr = gpa;\n' 251 else: 252 table += ' table->%s = (PFN_%s) gpa(%s, "%s");\n' % (base_name, item[0], table_type, item[0]) 253 if item[0] in self.device_extension_list: 254 stub_check = ' if (table->%s == nullptr) { table->%s = (PFN_%s)Stub%s; }\n' % (base_name, base_name, item[0], base_name) 255 table += stub_check 256 if item[1] is not None: 257 table += '#endif // %s\n' % item[1] 258 259 table += '}' 260 return table 261