1#!/usr/bin/python3 -i 2# 3# Copyright (c) 2015-2022 The Khronos Group Inc. 4# Copyright (c) 2015-2022 Valve Corporation 5# Copyright (c) 2015-2022 LunarG, Inc. 6# Copyright (c) 2015-2017 Google Inc. 7# Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 8# Copyright (c) 2023-2023 RasterGrid Kft. 9# 10# Licensed under the Apache License, Version 2.0 (the "License"); 11# you may not use this file except in compliance with the License. 12# You may obtain a copy of the License at 13# 14# http://www.apache.org/licenses/LICENSE-2.0 15# 16# Unless required by applicable law or agreed to in writing, software 17# distributed under the License is distributed on an "AS IS" BASIS, 18# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19# See the License for the specific language governing permissions and 20# limitations under the License. 21# 22# Author: Mark Young <marky@lunarg.com> 23# Author: Mark Lobodzinski <mark@lunarg.com> 24 25import os,re,sys 26import xml.etree.ElementTree as etree 27from generator import * 28from collections import namedtuple 29from common_codegen import * 30 31 32WSI_EXT_NAMES = ['VK_KHR_surface', 33 'VK_KHR_display', 34 'VK_KHR_xlib_surface', 35 'VK_KHR_xcb_surface', 36 'VK_KHR_wayland_surface', 37 'VK_EXT_directfb_surface', 38 'VK_KHR_win32_surface', 39 'VK_KHR_android_surface', 40 'VK_GGP_stream_descriptor_surface', 41 'VK_MVK_macos_surface', 42 'VK_MVK_ios_surface', 43 'VK_EXT_headless_surface', 44 'VK_EXT_metal_surface', 45 'VK_FUCHSIA_imagepipe_surface', 46 'VK_KHR_swapchain', 47 'VK_KHR_display_swapchain', 48 'VK_KHR_get_display_properties2', 49 'VK_KHR_get_surface_capabilities2', 50 'VK_QNX_screen_surface', 51 'VK_NN_vi_surface', 52 'VK_OHOS_surface'] 53 54ADD_INST_CMDS = ['vkCreateInstance', 55 'vkEnumerateInstanceExtensionProperties', 56 'vkEnumerateInstanceLayerProperties', 57 'vkEnumerateInstanceVersion'] 58 59AVOID_EXT_NAMES = ['VK_EXT_debug_report'] 60 61NULL_CHECK_EXT_NAMES= ['VK_EXT_debug_utils'] 62 63AVOID_CMD_NAMES = ['vkCreateDebugUtilsMessengerEXT', 64 'vkDestroyDebugUtilsMessengerEXT', 65 'vkSubmitDebugUtilsMessageEXT'] 66 67DEVICE_CMDS_NEED_TERM = ['vkGetDeviceProcAddr', 68 'vkCreateSwapchainKHR', 69 'vkCreateSharedSwapchainsKHR', 70 'vkGetDeviceGroupSurfacePresentModesKHR', 71 'vkDebugMarkerSetObjectTagEXT', 72 'vkDebugMarkerSetObjectNameEXT', 73 'vkSetDebugUtilsObjectNameEXT', 74 'vkSetDebugUtilsObjectTagEXT', 75 'vkQueueBeginDebugUtilsLabelEXT', 76 'vkQueueEndDebugUtilsLabelEXT', 77 'vkQueueInsertDebugUtilsLabelEXT', 78 'vkCmdBeginDebugUtilsLabelEXT', 79 'vkCmdEndDebugUtilsLabelEXT', 80 'vkCmdInsertDebugUtilsLabelEXT', 81 'vkGetDeviceGroupSurfacePresentModes2EXT'] 82 83DEVICE_CMDS_MUST_USE_TRAMP = ['vkSetDebugUtilsObjectNameEXT', 84 'vkSetDebugUtilsObjectTagEXT', 85 'vkDebugMarkerSetObjectNameEXT', 86 'vkDebugMarkerSetObjectTagEXT'] 87 88# These are the aliased functions that use the same terminator for both extension and core versions 89# Generally, this is only applies to physical device level functions in instance extensions 90SHARED_ALIASES = { 91 # 1.1 aliases 92 'vkEnumeratePhysicalDeviceGroupsKHR': 'vkEnumeratePhysicalDeviceGroups', 93 'vkGetPhysicalDeviceFeatures2KHR': 'vkGetPhysicalDeviceFeatures2', 94 'vkGetPhysicalDeviceProperties2KHR': 'vkGetPhysicalDeviceProperties2', 95 'vkGetPhysicalDeviceFormatProperties2KHR': 'vkGetPhysicalDeviceFormatProperties2', 96 'vkGetPhysicalDeviceImageFormatProperties2KHR': 'vkGetPhysicalDeviceImageFormatProperties2', 97 'vkGetPhysicalDeviceQueueFamilyProperties2KHR': 'vkGetPhysicalDeviceQueueFamilyProperties2', 98 'vkGetPhysicalDeviceMemoryProperties2KHR': 'vkGetPhysicalDeviceMemoryProperties2', 99 'vkGetPhysicalDeviceSparseImageFormatProperties2KHR': 'vkGetPhysicalDeviceSparseImageFormatProperties2', 100 'vkGetPhysicalDeviceExternalBufferPropertiesKHR': 'vkGetPhysicalDeviceExternalBufferProperties', 101 'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR': 'vkGetPhysicalDeviceExternalSemaphoreProperties', 102 'vkGetPhysicalDeviceExternalFencePropertiesKHR': 'vkGetPhysicalDeviceExternalFenceProperties', 103} 104 105PRE_INSTANCE_FUNCTIONS = ['vkEnumerateInstanceExtensionProperties', 106 'vkEnumerateInstanceLayerProperties', 107 'vkEnumerateInstanceVersion'] 108 109# 110# API Version 111class APIVersion: 112 def __init__(self, token, apiname = 'Vulkan', supported = True): 113 self.token = token 114 self.constant = token.replace('_VERSION_', '_API_VERSION_') 115 self.number = token[token.find('_VERSION_') + len('_VERSION_'):].replace('_', '.') 116 self.name = f'{apiname} {self.number}' 117 self.supported = supported 118 119# 120# LoaderExtensionGeneratorOptions - subclass of GeneratorOptions. 121class LoaderExtensionGeneratorOptions(GeneratorOptions): 122 def __init__(self, 123 conventions = None, 124 filename = None, 125 directory = '.', 126 genpath = None, 127 apiname = None, 128 profile = None, 129 versions = '.*', 130 emitversions = '.*', 131 defaultExtensions = None, 132 addExtensions = None, 133 removeExtensions = None, 134 emitExtensions = None, 135 sortProcedure = regSortFeatures, 136 prefixText = "", 137 genFuncPointers = True, 138 protectFile = True, 139 protectFeature = True, 140 apicall = '', 141 apientry = '', 142 apientryp = '', 143 indentFuncProto = True, 144 indentFuncPointer = False, 145 alignFuncParam = 0, 146 expandEnumerants = True): 147 GeneratorOptions.__init__(self, 148 conventions = conventions, 149 filename = filename, 150 directory = directory, 151 genpath = genpath, 152 apiname = apiname, 153 profile = profile, 154 versions = versions, 155 emitversions = emitversions, 156 defaultExtensions = defaultExtensions, 157 addExtensions = addExtensions, 158 removeExtensions = removeExtensions, 159 emitExtensions = emitExtensions, 160 sortProcedure = sortProcedure) 161 self.prefixText = prefixText 162 self.prefixText = None 163 self.apicall = apicall 164 self.apientry = apientry 165 self.apientryp = apientryp 166 self.alignFuncParam = alignFuncParam 167 self.expandEnumerants = expandEnumerants 168 169# 170# LoaderExtensionOutputGenerator - subclass of OutputGenerator. 171# Generates dispatch table helper header files for LVL 172class LoaderExtensionOutputGenerator(OutputGenerator): 173 """Generate dispatch table helper header based on XML element attributes""" 174 def __init__(self, 175 errFile = sys.stderr, 176 warnFile = sys.stderr, 177 diagFile = sys.stdout): 178 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 179 180 # Internal state - accumulators for different inner block text 181 self.ext_instance_dispatch_list = [] # List of extension entries for instance dispatch list 182 self.ext_device_dispatch_list = [] # List of extension entries for device dispatch list 183 self.core_commands = [] # List of CommandData records for core Vulkan commands 184 self.ext_commands = [] # List of CommandData records for extension Vulkan commands 185 self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl']) 186 self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'require', 'protect', 'return_type', 'handle_type', 'params', 'cdecl']) 187 self.instanceExtensions = [] 188 self.ExtensionData = namedtuple('ExtensionData', ['name', 'type', 'protect', 'define', 'num_commands']) 189 190 # 191 # Called once at the beginning of each run 192 def beginFile(self, genOpts): 193 OutputGenerator.beginFile(self, genOpts) 194 195 # User-supplied prefix text, if any (list of strings) 196 if (genOpts.prefixText): 197 for s in genOpts.prefixText: 198 write(s, file=self.outFile) 199 200 # File Comment 201 file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' 202 file_comment += '// See loader_extension_generator.py for modifications\n' 203 write(file_comment, file=self.outFile) 204 205 # Copyright Notice 206 copyright = '/*\n' 207 copyright += ' * Copyright (c) 2015-2022 The Khronos Group Inc.\n' 208 copyright += ' * Copyright (c) 2015-2022 Valve Corporation\n' 209 copyright += ' * Copyright (c) 2015-2022 LunarG, Inc.\n' 210 copyright += ' * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n' 211 copyright += ' * Copyright (c) 2023-2023 RasterGrid Kft.\n' 212 copyright += ' *\n' 213 copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 214 copyright += ' * you may not use this file except in compliance with the License.\n' 215 copyright += ' * You may obtain a copy of the License at\n' 216 copyright += ' *\n' 217 copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 218 copyright += ' *\n' 219 copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 220 copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 221 copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 222 copyright += ' * See the License for the specific language governing permissions and\n' 223 copyright += ' * limitations under the License.\n' 224 copyright += ' *\n' 225 copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n' 226 copyright += ' * Author: Mark Young <marky@lunarg.com>\n' 227 copyright += ' */\n' 228 229 preamble = '' 230 231 preamble += '// clang-format off\n' 232 233 if self.genOpts.filename == 'vk_loader_extensions.h': 234 preamble += '#pragma once\n' 235 236 elif self.genOpts.filename == 'vk_loader_extensions.c': 237 preamble += '#include <stdio.h>\n' 238 preamble += '#include <stdlib.h>\n' 239 preamble += '#include <string.h>\n' 240 preamble += '#include "vk_loader_platform.h"\n' 241 preamble += '#include "loader.h"\n' 242 preamble += '#include "vk_loader_extensions.h"\n' 243 preamble += '#include <vulkan/vk_icd.h>\n' 244 preamble += '#include "wsi.h"\n' 245 preamble += '#include "debug_utils.h"\n' 246 preamble += '#include "extension_manual.h"\n' 247 248 elif self.genOpts.filename == 'vk_layer_dispatch_table.h': 249 preamble += '#pragma once\n' 250 preamble += '\n' 251 preamble += '#if !defined(PFN_GetPhysicalDeviceProcAddr)\n' 252 preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n' 253 preamble += '#endif\n' 254 255 write(copyright, file=self.outFile) 256 write(preamble, file=self.outFile) 257 258 # 259 # Write generate and write dispatch tables to output file 260 def endFile(self): 261 file_data = '' 262 263 if self.genOpts.filename == 'vk_loader_extensions.h': 264 file_data += self.OutputPrototypesInHeader() 265 file_data += self.OutputLoaderTerminators() 266 file_data += self.OutputIcdDispatchTable() 267 file_data += self.OutputIcdExtensionEnableUnion() 268 file_data += self.OutputDeviceFunctionTerminatorDispatchTable() 269 270 elif self.genOpts.filename == 'vk_loader_extensions.c': 271 file_data += self.OutputUtilitiesInSource() 272 file_data += self.OutputIcdDispatchTableInit() 273 file_data += self.OutputLoaderDispatchTables() 274 file_data += self.InitDeviceFunctionTerminatorDispatchTable() 275 file_data += self.OutputDeviceFunctionTrampolinePrototypes() 276 file_data += self.OutputLoaderLookupFunc() 277 file_data += self.CreateTrampTermFuncs() 278 file_data += self.InstExtensionGPA() 279 file_data += self.InstantExtensionCreate() 280 file_data += self.DeviceExtensionGetTerminator() 281 file_data += self.InitInstLoaderExtensionDispatchTable() 282 file_data += self.OutputInstantExtensionWhitelistArray() 283 284 elif self.genOpts.filename == 'vk_layer_dispatch_table.h': 285 file_data += self.OutputLayerInstanceDispatchTable() 286 file_data += self.OutputLayerDeviceDispatchTable() 287 288 file_data += '// clang-format on' 289 290 write(file_data, file=self.outFile); 291 292 # Finish processing in superclass 293 OutputGenerator.endFile(self) 294 295 def beginFeature(self, interface, emit): 296 # Start processing in superclass 297 OutputGenerator.beginFeature(self, interface, emit) 298 self.featureExtraProtect = GetFeatureProtect(interface) 299 300 enums = interface[0].findall('enum') 301 self.currentExtension = '' 302 self.name_definition = '' 303 304 for item in enums: 305 name_definition = item.get('name') 306 if 'EXTENSION_NAME' in name_definition: 307 self.name_definition = name_definition 308 309 self.type = interface.get('type') 310 self.num_commands = 0 311 name = interface.get('name') 312 self.currentExtension = name 313 314 # 315 # Process commands, adding to appropriate dispatch tables 316 def genCmd(self, cmdinfo, name, alias): 317 OutputGenerator.genCmd(self, cmdinfo, name, alias) 318 319 # Get first param type 320 params = cmdinfo.elem.findall('param') 321 info = self.getTypeNameTuple(params[0]) 322 323 self.num_commands += 1 324 325 if 'android' not in name: 326 self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0]) 327 328 def endFeature(self): 329 330 if 'android' not in self.currentExtension: 331 self.instanceExtensions.append(self.ExtensionData(name=self.currentExtension, 332 type=self.type, 333 protect=self.featureExtraProtect, 334 define=self.name_definition, 335 num_commands=self.num_commands)) 336 337 # Finish processing in superclass 338 OutputGenerator.endFeature(self) 339 340 # 341 # Retrieve the value of the len tag 342 def getLen(self, param): 343 result = None 344 len = param.attrib.get('len') 345 if len and len != 'null-terminated': 346 # For string arrays, 'len' can look like 'count,null-terminated', 347 # indicating that we have a null terminated array of strings. We 348 # strip the null-terminated from the 'len' field and only return 349 # the parameter specifying the string count 350 if 'null-terminated' in len: 351 result = len.split(',')[0] 352 else: 353 result = len 354 result = str(result).replace('::', '->') 355 return result 356 357 # 358 # Returns an APIVersion object corresponding to the specified version token or None 359 def getAPIVersion(self, token): 360 if self.genOpts.apiname == 'vulkansc': 361 if token in ['VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2']: 362 # Vulkan 1.0-1.2 is included in Vulkan SC 1.0 363 token = 'VKSC_VERSION_1_0' 364 365 if token.startswith('VKSC_VERSION_'): 366 return APIVersion(token, 'Vulkan SC', True) 367 elif token.startswith('VK_VERSION_'): 368 # Unsupported Vulkan version 369 return APIVersion(token, 'Vulkan', False) 370 else: 371 return None 372 373 if token.startswith('VK_VERSION_'): 374 return APIVersion(token) 375 return None 376 377 # 378 # Determine if this API should be ignored or added to the instance or device dispatch table 379 def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type): 380 handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") 381 382 return_type = cmdinfo.elem.find('proto/type') 383 if (return_type is not None and return_type.text == 'void'): 384 return_type = None 385 386 require = None 387 if name == 'vkGetDeviceGroupSurfacePresentModes2EXT': 388 require_node = self.registry.tree.find("./extensions/extension[@name='{}']/require/command[@name='{}']/..".format(extension_name, name)) 389 if 'depends' in require_node.attrib: 390 require = require_node.attrib['depends'] 391 392 cmd_params = [] 393 394 # Generate a list of commands for use in printing the necessary 395 # core instance terminator prototypes 396 params = cmdinfo.elem.findall('param') 397 lens = set() 398 for param in params: 399 len = self.getLen(param) 400 if len: 401 lens.add(len) 402 paramsInfo = [] 403 for param in params: 404 paramInfo = self.getTypeNameTuple(param) 405 param_type = paramInfo[0] 406 param_name = paramInfo[1] 407 param_cdecl = self.makeCParamDecl(param, 0) 408 cmd_params.append(self.CommandParam(type=param_type, name=param_name, 409 cdecl=param_cdecl)) 410 411 version = self.getAPIVersion(extension_name) 412 if version and not version.supported: 413 # Skip commands in unsupported versions 414 return 415 416 if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice': 417 # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# 418 # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality 419 if version: 420 self.core_commands.append( 421 self.CommandData(name=name, ext_name=version.token, 422 ext_type='device', 423 require=require, 424 protect=self.featureExtraProtect, 425 return_type = return_type, 426 handle_type = handle_type, 427 params = cmd_params, 428 cdecl=self.makeCDecls(cmdinfo.elem)[0])) 429 else: 430 self.ext_device_dispatch_list.append((name, self.featureExtraProtect)) 431 self.ext_commands.append( 432 self.CommandData(name=name, ext_name=extension_name, 433 ext_type=extension_type, 434 require=require, 435 protect=self.featureExtraProtect, 436 return_type = return_type, 437 handle_type = handle_type, 438 params = cmd_params, 439 cdecl=self.makeCDecls(cmdinfo.elem)[0])) 440 else: 441 # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# 442 # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality 443 if version: 444 self.core_commands.append( 445 self.CommandData(name=name, ext_name=version.token, 446 ext_type='instance', 447 require=require, 448 protect=self.featureExtraProtect, 449 return_type = return_type, 450 handle_type = handle_type, 451 params = cmd_params, 452 cdecl=self.makeCDecls(cmdinfo.elem)[0])) 453 454 else: 455 self.ext_instance_dispatch_list.append((name, self.featureExtraProtect)) 456 self.ext_commands.append( 457 self.CommandData(name=name, ext_name=extension_name, 458 ext_type=extension_type, 459 require=require, 460 protect=self.featureExtraProtect, 461 return_type = return_type, 462 handle_type = handle_type, 463 params = cmd_params, 464 cdecl=self.makeCDecls(cmdinfo.elem)[0])) 465 466 # 467 # Retrieve the type and name for a parameter 468 def getTypeNameTuple(self, param): 469 type = '' 470 name = '' 471 for elem in param: 472 if elem.tag == 'type': 473 type = noneStr(elem.text) 474 elif elem.tag == 'name': 475 name = noneStr(elem.text) 476 return (type, name) 477 478 def OutputPrototypesInHeader(self): 479 protos = '' 480 protos += '// Structures defined externally, but used here\n' 481 protos += 'struct loader_instance;\n' 482 protos += 'struct loader_device;\n' 483 protos += 'struct loader_icd_term;\n' 484 protos += 'struct loader_dev_dispatch_table;\n' 485 protos += '\n' 486 protos += '// Device extension error function\n' 487 protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev);\n' 488 protos += '\n' 489 protos += '// Extension interception for vkGetInstanceProcAddr function, so we can return\n' 490 protos += '// the appropriate information for any instance extensions we know about.\n' 491 protos += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr);\n' 492 protos += '\n' 493 protos += '// Extension interception for vkCreateInstance function, so we can properly\n' 494 protos += '// detect and enable any instance extension information for extensions we know\n' 495 protos += '// about.\n' 496 protos += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);\n' 497 protos += '\n' 498 protos += '// Extension interception for vkGetDeviceProcAddr function, so we can return\n' 499 protos += '// an appropriate terminator if this is one of those few device commands requiring\n' 500 protos += '// a terminator.\n' 501 protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name);\n' 502 protos += '\n' 503 protos += '// Dispatch table properly filled in with appropriate terminators for the\n' 504 protos += '// supported extensions.\n' 505 protos += 'extern const VkLayerInstanceDispatchTable instance_disp;\n' 506 protos += '\n' 507 protos += '// Array of extension strings for instance extensions we support.\n' 508 protos += 'extern const char *const LOADER_INSTANCE_EXTENSIONS[];\n' 509 protos += '\n' 510 protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_instance* inst, struct loader_icd_term *icd_term);\n' 511 protos += '\n' 512 protos += '// Init Device function pointer dispatch table with core commands\n' 513 protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n' 514 protos += ' VkDevice dev);\n' 515 protos += '\n' 516 protos += '// Init Device function pointer dispatch table with extension commands\n' 517 protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n' 518 protos += ' PFN_vkGetInstanceProcAddr gipa,\n' 519 protos += ' PFN_vkGetDeviceProcAddr gdpa,\n' 520 protos += ' VkInstance inst,\n' 521 protos += ' VkDevice dev);\n' 522 protos += '\n' 523 protos += '// Init Instance function pointer dispatch table with core commands\n' 524 protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' 525 protos += ' VkInstance inst);\n' 526 protos += '\n' 527 protos += '// Init Instance function pointer dispatch table with core commands\n' 528 protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' 529 protos += ' VkInstance inst);\n' 530 protos += '\n' 531 protos += '// Device command lookup function\n' 532 protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name, bool* name_found);\n' 533 protos += '\n' 534 protos += '// Instance command lookup function\n' 535 protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n' 536 protos += ' bool *found_name);\n' 537 protos += '\n' 538 return protos 539 540 def OutputUtilitiesInSource(self): 541 protos = '' 542 protos += '// Device extension error function\n' 543 protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev) {\n' 544 protos += ' struct loader_device *found_dev;\n' 545 protos += ' // The device going in is a trampoline device\n' 546 protos += ' struct loader_icd_term *icd_term = loader_get_icd_and_device(dev, &found_dev, NULL);\n' 547 protos += '\n' 548 protos += ' if (icd_term)\n' 549 protos += ' loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,\n' 550 protos += ' "Bad destination in loader trampoline dispatch,"\n' 551 protos += ' "Are layers and extensions that you are calling enabled?");\n' 552 protos += ' return VK_ERROR_EXTENSION_NOT_PRESENT;\n' 553 protos += '}\n\n' 554 return protos 555 556 # 557 # Create a layer instance dispatch table from the appropriate list and return it as a string 558 def OutputLayerInstanceDispatchTable(self): 559 commands = [] 560 table = '' 561 cur_extension_name = '' 562 563 table += '// Instance function pointer dispatch table\n' 564 table += 'typedef struct VkLayerInstanceDispatchTable_ {\n' 565 566 # First add in an entry for GetPhysicalDeviceProcAddr. This will not 567 # ever show up in the XML or header, so we have to manually add it. 568 table += ' // Manually add in GetPhysicalDeviceProcAddr entry\n' 569 table += ' PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n' 570 571 for x in range(0, 2): 572 if x == 0: 573 commands = self.core_commands 574 else: 575 commands = self.ext_commands 576 577 for cur_cmd in commands: 578 version = self.getAPIVersion(cur_cmd.ext_name) 579 is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' 580 if is_inst_handle_type: 581 582 if cur_cmd.ext_name != cur_extension_name: 583 if version: 584 table += '\n // ---- Core %s commands\n' % version.name 585 else: 586 table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 587 cur_extension_name = cur_cmd.ext_name 588 589 # Remove 'vk' from proto name 590 base_name = cur_cmd.name[2:] 591 592 if cur_cmd.protect is not None: 593 table += '#if defined(%s)\n' % cur_cmd.protect 594 595 table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) 596 597 if cur_cmd.protect is not None: 598 table += '#endif // %s\n' % cur_cmd.protect 599 600 table += '} VkLayerInstanceDispatchTable;\n\n' 601 return table 602 603 # 604 # Create a layer device dispatch table from the appropriate list and return it as a string 605 def OutputLayerDeviceDispatchTable(self): 606 commands = [] 607 table = '' 608 cur_extension_name = '' 609 610 table += '// Device function pointer dispatch table\n' 611 table += '#define DEVICE_DISP_TABLE_MAGIC_NUMBER 0x10ADED040410ADEDUL\n' 612 table += 'typedef struct VkLayerDispatchTable_ {\n' 613 table += ' uint64_t magic; // Should be DEVICE_DISP_TABLE_MAGIC_NUMBER\n' 614 615 for x in range(0, 2): 616 if x == 0: 617 commands = self.core_commands 618 else: 619 commands = self.ext_commands 620 621 for cur_cmd in commands: 622 version = self.getAPIVersion(cur_cmd.ext_name) 623 is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' 624 if not is_inst_handle_type: 625 626 if cur_cmd.ext_name != cur_extension_name: 627 if version: 628 table += '\n // ---- Core %s commands\n' % version.name 629 else: 630 table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 631 cur_extension_name = cur_cmd.ext_name 632 633 # Remove 'vk' from proto name 634 base_name = cur_cmd.name[2:] 635 636 if cur_cmd.protect is not None: 637 table += '#if defined(%s)\n' % cur_cmd.protect 638 639 table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) 640 641 if cur_cmd.protect is not None: 642 table += '#endif // %s\n' % cur_cmd.protect 643 644 table += '} VkLayerDispatchTable;\n\n' 645 return table 646 647 # 648 # Common code between the dispatch table struct and the function filling out said struct 649 def ShouldPrintInIcdDispatchTable(self, cur_cmd, skip_list): 650 return cur_cmd.name == 'vkGetDeviceProcAddr' or \ 651 (cur_cmd.handle_type not in ['VkDevice', 'VkCommandBuffer', 'VkQueue'] and cur_cmd.name not in skip_list) 652 653 # 654 # Create a dispatch table from the appropriate list and return it as a string 655 def OutputIcdDispatchTable(self): 656 commands = [] 657 table = '' 658 cur_extension_name = '' 659 660 skip_commands = ['vkGetInstanceProcAddr', 661 'vkEnumerateDeviceLayerProperties', 662 ] 663 664 table += '// ICD function pointer dispatch table\n' 665 table += 'struct loader_icd_term_dispatch {\n' 666 667 for x in range(0, 2): 668 if x == 0: 669 commands = self.core_commands 670 else: 671 commands = self.ext_commands 672 673 for cur_cmd in commands: 674 version = self.getAPIVersion(cur_cmd.ext_name) 675 if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_commands)): 676 if cur_cmd.ext_name != cur_extension_name: 677 if version: 678 table += '\n // ---- Core %s commands\n' % version.name 679 else: 680 table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 681 cur_extension_name = cur_cmd.ext_name 682 683 # Remove 'vk' from proto name 684 base_name = cur_cmd.name[2:] 685 686 if cur_cmd.protect is not None: 687 table += '#if defined(%s)\n' % cur_cmd.protect 688 689 table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) 690 691 if cur_cmd.protect is not None: 692 table += '#endif // %s\n' % cur_cmd.protect 693 694 table += '};\n\n' 695 return table 696 697 # 698 # Init a dispatch table from the appropriate list and return it as a string 699 def OutputIcdDispatchTableInit(self): 700 commands = [] 701 cur_extension_name = '' 702 703 table = '' 704 table += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_instance* inst, struct loader_icd_term *icd_term) {\n' 705 table += ' const PFN_vkGetInstanceProcAddr fp_gipa = icd_term->scanned_icd->GetInstanceProcAddr;\n' 706 table += '\n' 707 table += '#define LOOKUP_GIPA(func) icd_term->dispatch.func = (PFN_vk##func)fp_gipa(icd_term->instance, "vk" #func);\n' 708 table += '\n' 709 table += '#define LOOKUP_REQUIRED_GIPA(func) \\\n' 710 table += ' do { \\\n' 711 table += ' LOOKUP_GIPA(func); \\\n' 712 table += ' if (!icd_term->dispatch.func) { \\\n' 713 table += ' loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Unable to load %s from ICD %s",\\\n' 714 table += ' "vk"#func, icd_term->scanned_icd->lib_name); \\\n' 715 table += ' return false; \\\n' 716 table += ' } \\\n' 717 table += ' } while (0)\n' 718 table += '\n' 719 720 721 skip_gipa_commands = ['vkGetInstanceProcAddr', 722 'vkEnumerateDeviceLayerProperties', 723 'vkCreateInstance', 724 'vkEnumerateInstanceExtensionProperties', 725 'vkEnumerateInstanceLayerProperties', 726 'vkEnumerateInstanceVersion', 727 ] 728 729 for x in range(0, 2): 730 if x == 0: 731 commands = self.core_commands 732 else: 733 commands = self.ext_commands 734 735 required = False 736 for cur_cmd in commands: 737 version = self.getAPIVersion(cur_cmd.ext_name) 738 if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_gipa_commands)): 739 740 if cur_cmd.ext_name != cur_extension_name: 741 if version: 742 table += '\n // ---- Core %s\n' % version.name 743 required = version.number == '1.0' 744 else: 745 table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 746 required = False 747 cur_extension_name = cur_cmd.ext_name 748 749 # Remove 'vk' from proto name 750 base_name = cur_cmd.name[2:] 751 752 if cur_cmd.protect is not None: 753 table += '#if defined(%s)\n' % cur_cmd.protect 754 755 if required: 756 # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# 757 # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality 758 table += f' LOOKUP_REQUIRED_GIPA({base_name});\n' 759 else: 760 table += f' LOOKUP_GIPA({base_name});\n' 761 if cur_cmd.protect is not None: 762 table += '#endif // %s\n' % cur_cmd.protect 763 764 table += '\n' 765 table += '#undef LOOKUP_REQUIRED_GIPA\n' 766 table += '#undef LOOKUP_GIPA\n' 767 table += '\n' 768 table += ' return true;\n' 769 table += '};\n\n' 770 return table 771 772 # 773 # Create the extension enable union 774 def OutputIcdExtensionEnableUnion(self): 775 extensions = self.instanceExtensions 776 777 union = '' 778 union += 'struct loader_instance_extension_enables {\n' 779 for ext in extensions: 780 if (self.getAPIVersion(ext.name) or ext.name in WSI_EXT_NAMES or 781 ext.type == 'device' or ext.num_commands == 0): 782 continue 783 784 union += ' uint8_t %s;\n' % ext.name[3:].lower() 785 786 union += '};\n\n' 787 return union 788 789 # 790 # Creates the prototypes for the loader's core instance command terminators 791 def OutputLoaderTerminators(self): 792 terminators = '' 793 terminators += '// Loader core instance terminators\n' 794 795 for cur_cmd in self.core_commands: 796 is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' 797 if is_inst_handle_type: 798 mod_string = '' 799 new_terminator = cur_cmd.cdecl 800 mod_string = new_terminator.replace("VKAPI_CALL vk", "VKAPI_CALL terminator_") 801 802 if cur_cmd.name in PRE_INSTANCE_FUNCTIONS: 803 mod_string = mod_string.replace(cur_cmd.name[2:] + '(\n', cur_cmd.name[2:] + '(\n const Vk' + cur_cmd.name[2:] + 'Chain* chain,\n') 804 805 if (cur_cmd.protect is not None): 806 terminators += '#if defined(%s)\n' % cur_cmd.protect 807 808 terminators += mod_string 809 terminators += '\n' 810 811 if (cur_cmd.protect is not None): 812 terminators += '#endif // %s\n' % cur_cmd.protect 813 814 terminators += '\n' 815 return terminators 816 817 # 818 # Creates code to initialize the various dispatch tables 819 def OutputLoaderDispatchTables(self): 820 commands = [] 821 tables = '' 822 gpa_param = '' 823 cur_type = '' 824 cur_extension_name = '' 825 826 for x in range(0, 4): 827 if x == 0: 828 cur_type = 'device' 829 gpa_param = 'dev' 830 commands = self.core_commands 831 832 tables += '// Init Device function pointer dispatch table with core commands\n' 833 tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n' 834 tables += ' VkDevice dev) {\n' 835 tables += ' VkLayerDispatchTable *table = &dev_table->core_dispatch;\n' 836 tables += ' if (table->magic != DEVICE_DISP_TABLE_MAGIC_NUMBER) { abort(); }\n' 837 tables += ' for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) dev_table->ext_dispatch[i] = (PFN_vkDevExt)vkDevExtError;\n' 838 839 elif x == 1: 840 cur_type = 'device' 841 gpa_param = 'dev' 842 commands = self.ext_commands 843 844 tables += '// Init Device function pointer dispatch table with extension commands\n' 845 tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n' 846 tables += ' PFN_vkGetInstanceProcAddr gipa,\n' 847 tables += ' PFN_vkGetDeviceProcAddr gdpa,\n' 848 tables += ' VkInstance inst,\n' 849 tables += ' VkDevice dev) {\n' 850 tables += ' VkLayerDispatchTable *table = &dev_table->core_dispatch;\n' 851 tables += ' table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n' 852 853 elif x == 2: 854 cur_type = 'instance' 855 gpa_param = 'inst' 856 commands = self.core_commands 857 858 tables += '// Init Instance function pointer dispatch table with core commands\n' 859 tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' 860 tables += ' VkInstance inst) {\n' 861 862 else: 863 cur_type = 'instance' 864 gpa_param = 'inst' 865 commands = self.ext_commands 866 867 tables += '// Init Instance function pointer dispatch table with core commands\n' 868 tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' 869 tables += ' VkInstance inst) {\n' 870 871 for cur_cmd in commands: 872 version = self.getAPIVersion(cur_cmd.ext_name) 873 is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' 874 if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)): 875 if cur_cmd.ext_name != cur_extension_name: 876 if version: 877 tables += '\n // ---- Core %s commands\n' % version.name 878 else: 879 tables += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 880 cur_extension_name = cur_cmd.ext_name 881 882 # Remove 'vk' from proto name 883 base_name = cur_cmd.name[2:] 884 885 # Names to skip 886 if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or 887 base_name == 'EnumerateInstanceExtensionProperties' or 888 base_name == 'EnumerateInstanceLayerProperties' or 889 base_name == 'EnumerateInstanceVersion'): 890 continue 891 892 if cur_cmd.protect is not None: 893 tables += '#if defined(%s)\n' % cur_cmd.protect 894 895 # If we're looking for the proc we are passing in, just point the table to it. This fixes the issue where 896 # a layer overrides the function name for the loader. 897 if x == 1: 898 if base_name == 'GetDeviceProcAddr': 899 tables += ' table->GetDeviceProcAddr = gdpa;\n' 900 elif cur_cmd.ext_type == 'instance': 901 tables += ' table->%s = (PFN_%s)gipa(inst, "%s");\n' % (base_name, cur_cmd.name, cur_cmd.name) 902 else: 903 tables += ' table->%s = (PFN_%s)gdpa(dev, "%s");\n' % (base_name, cur_cmd.name, cur_cmd.name) 904 elif (x < 1 and base_name == 'GetDeviceProcAddr'): 905 tables += ' table->GetDeviceProcAddr = gpa;\n' 906 elif (x > 1 and base_name == 'GetInstanceProcAddr'): 907 tables += ' table->GetInstanceProcAddr = gpa;\n' 908 else: 909 tables += ' table->%s = (PFN_%s)gpa(%s, "%s");\n' % (base_name, cur_cmd.name, gpa_param, cur_cmd.name) 910 911 if cur_cmd.protect is not None: 912 tables += '#endif // %s\n' % cur_cmd.protect 913 914 tables += '}\n\n' 915 return tables 916 917 # 918 # Create a lookup table function from the appropriate list of entrypoints and 919 # return it as a string 920 def OutputLoaderLookupFunc(self): 921 commands = [] 922 tables = '' 923 cur_type = '' 924 cur_extension_name = '' 925 926 for x in range(0, 2): 927 if x == 0: 928 cur_type = 'device' 929 930 tables += '// Device command lookup function\n' 931 tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name, bool* found_name) {\n' 932 tables += ' if (!name || name[0] != \'v\' || name[1] != \'k\') {\n' 933 tables += ' *found_name = false;\n' 934 tables += ' return NULL;\n' 935 tables += ' }\n' 936 tables += '\n' 937 tables += ' name += 2;\n' 938 tables += ' *found_name = true;\n' 939 tables += ' struct loader_device* dev = (struct loader_device *)table;\n' 940 tables += ' const struct loader_instance* inst = dev->phys_dev_term->this_icd_term->this_instance;\n' 941 tables += ' uint32_t api_version = VK_MAKE_API_VERSION(0, inst->app_api_version.major, inst->app_api_version.minor, inst->app_api_version.patch);\n' 942 tables += '\n' 943 else: 944 cur_type = 'instance' 945 946 tables += '// Instance command lookup function\n' 947 tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n' 948 tables += ' bool *found_name) {\n' 949 tables += ' if (!name || name[0] != \'v\' || name[1] != \'k\') {\n' 950 tables += ' *found_name = false;\n' 951 tables += ' return NULL;\n' 952 tables += ' }\n' 953 tables += '\n' 954 tables += ' *found_name = true;\n' 955 tables += ' name += 2;\n' 956 957 958 for y in range(0, 2): 959 if y == 0: 960 commands = self.core_commands 961 else: 962 commands = self.ext_commands 963 964 for cur_cmd in commands: 965 version = self.getAPIVersion(cur_cmd.ext_name) 966 is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' 967 if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)): 968 if cur_cmd.ext_name != cur_extension_name: 969 if version: 970 tables += '\n // ---- Core %s commands\n' % version.name 971 if cur_type == 'device': 972 version_check = f' if (dev->should_ignore_device_commands_from_newer_version && api_version < {version.constant}) return NULL;\n' 973 else: 974 975 tables += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 976 version_check = '' 977 cur_extension_name = cur_cmd.ext_name 978 979 # Remove 'vk' from proto name 980 base_name = cur_cmd.name[2:] 981 982 if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or 983 base_name == 'EnumerateInstanceExtensionProperties' or 984 base_name == 'EnumerateInstanceLayerProperties' or 985 base_name == 'EnumerateInstanceVersion'): 986 continue 987 988 if cur_cmd.protect is not None: 989 tables += '#if defined(%s)\n' % cur_cmd.protect 990 991 tables += f' if (!strcmp(name, "{base_name}")) ' 992 if cur_cmd.name in DEVICE_CMDS_MUST_USE_TRAMP: 993 if version_check != '': 994 tables += f'{{\n{version_check} return dev->layer_extensions.{cur_cmd.ext_name[3:].lower()}_enabled ? (void *){base_name} : NULL;\n }}\n' 995 else: 996 tables += f'return dev->layer_extensions.{cur_cmd.ext_name[3:].lower()}_enabled ? (void *){base_name} : NULL;\n' 997 998 else: 999 if version_check != '': 1000 tables += f'{{\n{version_check} return (void *)table->{base_name};\n }}\n' 1001 else: 1002 tables += f'return (void *)table->{base_name};\n' 1003 1004 if cur_cmd.protect is not None: 1005 tables += '#endif // %s\n' % cur_cmd.protect 1006 1007 tables += '\n' 1008 tables += ' *found_name = false;\n' 1009 tables += ' return NULL;\n' 1010 tables += '}\n\n' 1011 return tables 1012 1013 # 1014 # Create the appropriate trampoline (and possibly terminator) functions 1015 def CreateTrampTermFuncs(self): 1016 entries = [] 1017 funcs = '' 1018 cur_extension_name = '' 1019 1020 # Some extensions have to be manually added. Skip those in the automatic 1021 # generation. They will be manually added later. 1022 manual_ext_commands = ['vkEnumeratePhysicalDeviceGroupsKHR', 1023 'vkGetPhysicalDeviceExternalImageFormatPropertiesNV', 1024 'vkGetPhysicalDeviceFeatures2KHR', 1025 'vkGetPhysicalDeviceProperties2KHR', 1026 'vkGetPhysicalDeviceFormatProperties2KHR', 1027 'vkGetPhysicalDeviceImageFormatProperties2KHR', 1028 'vkGetPhysicalDeviceQueueFamilyProperties2KHR', 1029 'vkGetPhysicalDeviceMemoryProperties2KHR', 1030 'vkGetPhysicalDeviceSparseImageFormatProperties2KHR', 1031 'vkGetPhysicalDeviceSurfaceCapabilities2KHR', 1032 'vkGetPhysicalDeviceSurfaceFormats2KHR', 1033 'vkGetPhysicalDeviceSurfaceCapabilities2EXT', 1034 'vkReleaseDisplayEXT', 1035 'vkAcquireXlibDisplayEXT', 1036 'vkGetRandROutputDisplayEXT', 1037 'vkGetPhysicalDeviceExternalBufferPropertiesKHR', 1038 'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR', 1039 'vkGetPhysicalDeviceExternalFencePropertiesKHR', 1040 'vkGetPhysicalDeviceDisplayProperties2KHR', 1041 'vkGetPhysicalDeviceDisplayPlaneProperties2KHR', 1042 'vkGetDisplayModeProperties2KHR', 1043 'vkGetDisplayPlaneCapabilities2KHR', 1044 'vkGetPhysicalDeviceSurfacePresentModes2EXT', 1045 'vkGetDeviceGroupSurfacePresentModes2EXT', 1046 'vkGetPhysicalDeviceToolPropertiesEXT'] 1047 1048 for ext_cmd in self.ext_commands: 1049 if (ext_cmd.ext_name in WSI_EXT_NAMES or 1050 ext_cmd.ext_name in AVOID_EXT_NAMES or 1051 ext_cmd.name in AVOID_CMD_NAMES or 1052 ext_cmd.name in manual_ext_commands): 1053 continue 1054 1055 version = self.getAPIVersion(ext_cmd.ext_name) 1056 if ext_cmd.ext_name != cur_extension_name: 1057 if version: 1058 funcs += '\n// ---- Core %s trampoline/terminators\n\n' % version.name 1059 else: 1060 funcs += '\n// ---- %s extension trampoline/terminators\n\n' % ext_cmd.ext_name 1061 cur_extension_name = ext_cmd.ext_name 1062 1063 if ext_cmd.protect is not None: 1064 funcs += '#if defined(%s)\n' % ext_cmd.protect 1065 1066 func_header = ext_cmd.cdecl.replace(";", " {\n") 1067 tramp_header = func_header.replace("VKAPI_CALL vk", "VKAPI_CALL ") 1068 return_prefix = ' ' 1069 base_name = ext_cmd.name[2:] 1070 has_surface = 0 1071 update_structure_surface = 0 1072 update_structure_string = '' 1073 requires_terminator = 0 1074 surface_var_name = '' 1075 phys_dev_var_name = '' 1076 instance_var_name = '' 1077 has_return_type = False 1078 always_use_param_name = True 1079 surface_type_to_replace = '' 1080 surface_name_replacement = '' 1081 physdev_type_to_replace = '' 1082 physdev_name_replacement = '' 1083 1084 for param in ext_cmd.params: 1085 if param.type == 'VkSurfaceKHR': 1086 has_surface = 1 1087 surface_var_name = param.name 1088 requires_terminator = 1 1089 always_use_param_name = False 1090 surface_type_to_replace = 'VkSurfaceKHR' 1091 surface_name_replacement = 'icd_surface->real_icd_surfaces[icd_index]' 1092 if param.type == 'VkPhysicalDeviceSurfaceInfo2KHR': 1093 has_surface = 1 1094 surface_var_name = param.name + '->surface' 1095 requires_terminator = 1 1096 update_structure_surface = 1 1097 update_structure_string = ' VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;\n' 1098 update_structure_string += ' info_copy.surface = icd_surface->real_icd_surfaces[icd_index];\n' 1099 always_use_param_name = False 1100 surface_type_to_replace = 'VkPhysicalDeviceSurfaceInfo2KHR' 1101 surface_name_replacement = '&info_copy' 1102 if param.type == 'VkPhysicalDevice': 1103 requires_terminator = 1 1104 phys_dev_var_name = param.name 1105 always_use_param_name = False 1106 physdev_type_to_replace = 'VkPhysicalDevice' 1107 physdev_name_replacement = 'phys_dev_term->phys_dev' 1108 if param.type == 'VkInstance': 1109 requires_terminator = 1 1110 instance_var_name = param.name 1111 1112 if (ext_cmd.return_type is not None): 1113 return_prefix += 'return ' 1114 has_return_type = True 1115 1116 if (ext_cmd.handle_type == 'VkInstance' or ext_cmd.handle_type == 'VkPhysicalDevice' or 1117 'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or 1118 ext_cmd.name in DEVICE_CMDS_NEED_TERM): 1119 requires_terminator = 1 1120 1121 if requires_terminator == 1: 1122 term_header = tramp_header.replace("VKAPI_CALL ", "VKAPI_CALL terminator_") 1123 1124 funcs += tramp_header 1125 1126 if ext_cmd.handle_type == 'VkPhysicalDevice': 1127 funcs += ' const VkLayerInstanceDispatchTable *disp;\n' 1128 funcs += ' VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(%s);\n' % (phys_dev_var_name) 1129 funcs += ' if (VK_NULL_HANDLE == unwrapped_phys_dev) {\n' 1130 funcs += ' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' 1131 funcs += ' "%s: Invalid %s "\n' % (ext_cmd.name, phys_dev_var_name) 1132 funcs += ' "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, phys_dev_var_name) 1133 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1134 funcs += ' }\n' 1135 funcs += ' disp = loader_get_instance_layer_dispatch(%s);\n' % (phys_dev_var_name) 1136 elif ext_cmd.handle_type == 'VkInstance': 1137 funcs += ' struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name) 1138 funcs += ' if (NULL == inst) {\n' 1139 funcs += ' loader_log(\n' 1140 funcs += ' NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' 1141 funcs += ' "%s: Invalid instance [VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.name, instance_var_name) 1142 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1143 funcs += ' }\n' 1144 funcs += '#error("Not implemented. Likely needs to be manually generated!");\n' 1145 else: 1146 funcs += ' const VkLayerDispatchTable *disp = loader_get_dispatch(' 1147 funcs += ext_cmd.params[0].name 1148 funcs += ');\n' 1149 funcs += ' if (NULL == disp) {\n' 1150 funcs += ' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' 1151 funcs += ' "%s: Invalid %s "\n' % (ext_cmd.name, ext_cmd.params[0].name) 1152 funcs += ' "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.params[0].name) 1153 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1154 funcs += ' }\n' 1155 1156 if 'DebugMarkerSetObjectName' in ext_cmd.name: 1157 funcs += ' VkDebugMarkerObjectNameInfoEXT local_name_info;\n' 1158 funcs += ' memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n' 1159 funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' 1160 funcs += ' if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n' 1161 funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->object;\n' 1162 funcs += ' local_name_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' 1163 funcs += ' }\n' 1164 funcs += ' if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) {\n' 1165 funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pNameInfo->object;\n' 1166 funcs += ' local_name_info.object = (uint64_t)(uintptr_t)instance->instance;\n' 1167 funcs += ' }\n' 1168 elif 'DebugMarkerSetObjectTag' in ext_cmd.name: 1169 funcs += ' VkDebugMarkerObjectTagInfoEXT local_tag_info;\n' 1170 funcs += ' memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n' 1171 funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' 1172 funcs += ' if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n' 1173 funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->object;\n' 1174 funcs += ' local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' 1175 funcs += ' }\n' 1176 funcs += ' if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) {\n' 1177 funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pTagInfo->object;\n' 1178 funcs += ' local_tag_info.object = (uint64_t)(uintptr_t)instance->instance;\n' 1179 funcs += ' }\n' 1180 elif 'SetDebugUtilsObjectName' in ext_cmd.name: 1181 funcs += ' VkDebugUtilsObjectNameInfoEXT local_name_info;\n' 1182 funcs += ' memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n' 1183 funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' 1184 funcs += ' if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n' 1185 funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->objectHandle;\n' 1186 funcs += ' local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' 1187 funcs += ' }\n' 1188 funcs += ' if (pNameInfo->objectType == VK_OBJECT_TYPE_INSTANCE) {\n' 1189 funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pNameInfo->objectHandle;\n' 1190 funcs += ' local_name_info.objectHandle = (uint64_t)(uintptr_t)instance->instance;\n' 1191 funcs += ' }\n' 1192 elif 'SetDebugUtilsObjectTag' in ext_cmd.name: 1193 funcs += ' VkDebugUtilsObjectTagInfoEXT local_tag_info;\n' 1194 funcs += ' memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n' 1195 funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' 1196 funcs += ' if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n' 1197 funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->objectHandle;\n' 1198 funcs += ' local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' 1199 funcs += ' }\n' 1200 funcs += ' if (pTagInfo->objectType == VK_OBJECT_TYPE_INSTANCE) {\n' 1201 funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pTagInfo->objectHandle;\n' 1202 funcs += ' local_tag_info.objectHandle = (uint64_t)(uintptr_t)instance->instance;\n' 1203 funcs += ' }\n' 1204 1205 if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: 1206 funcs += ' if (disp->' + base_name + ' != NULL) {\n' 1207 funcs += ' ' 1208 funcs += return_prefix 1209 if ext_cmd.handle_type == 'VkInstance': 1210 funcs += 'inst->' 1211 funcs += 'disp->' 1212 funcs += base_name 1213 funcs += '(' 1214 count = 0 1215 for param in ext_cmd.params: 1216 if count != 0: 1217 funcs += ', ' 1218 1219 if param.type == 'VkPhysicalDevice': 1220 funcs += 'unwrapped_phys_dev' 1221 elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo': 1222 funcs += '&local_name_info' 1223 elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo': 1224 funcs += '&local_tag_info' 1225 else: 1226 funcs += param.name 1227 1228 count += 1 1229 funcs += ');\n' 1230 if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: 1231 if ext_cmd.return_type is not None: 1232 funcs += ' } else {\n' 1233 funcs += ' return VK_SUCCESS;\n' 1234 funcs += ' }\n' 1235 funcs += '}\n\n' 1236 1237 funcs += term_header 1238 if ext_cmd.handle_type == 'VkPhysicalDevice': 1239 funcs += ' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)%s;\n' % (phys_dev_var_name) 1240 funcs += ' struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;\n' 1241 funcs += ' if (NULL == icd_term->dispatch.' 1242 funcs += base_name 1243 funcs += ') {\n' 1244 fatal_error_bit = '' if ext_cmd.ext_type =='instance' and has_return_type else 'VULKAN_LOADER_FATAL_ERROR_BIT | ' 1245 funcs += f' loader_log(icd_term->this_instance, {fatal_error_bit}VULKAN_LOADER_ERROR_BIT, 0,\n' 1246 funcs += ' "ICD associated with VkPhysicalDevice does not support ' 1247 funcs += base_name 1248 funcs += '");\n' 1249 1250 # If this is an instance function taking a physical device (i.e. pre Vulkan 1.1), we need to behave and not crash so return an 1251 # error here. 1252 if ext_cmd.ext_type =='instance' and has_return_type: 1253 funcs += ' return VK_ERROR_EXTENSION_NOT_PRESENT;\n' 1254 else: 1255 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1256 funcs += ' }\n' 1257 1258 if has_surface == 1: 1259 funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(%s);\n' % (surface_var_name) 1260 funcs += ' uint8_t icd_index = phys_dev_term->icd_index;\n' 1261 funcs += ' if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)icd_surface->real_icd_surfaces[icd_index]) {\n' 1262 1263 # If there's a structure with a surface, we need to update its internals with the correct surface for the ICD 1264 if update_structure_surface == 1: 1265 funcs += update_structure_string 1266 1267 funcs += ' ' + return_prefix + 'icd_term->dispatch.' 1268 funcs += base_name 1269 funcs += '(' 1270 count = 0 1271 for param in ext_cmd.params: 1272 if count != 0: 1273 funcs += ', ' 1274 1275 if not always_use_param_name: 1276 if surface_type_to_replace and surface_type_to_replace == param.type: 1277 funcs += surface_name_replacement 1278 elif physdev_type_to_replace and physdev_type_to_replace == param.type: 1279 funcs += physdev_name_replacement 1280 else: 1281 funcs += param.name 1282 else: 1283 funcs += param.name 1284 1285 count += 1 1286 funcs += ');\n' 1287 if not has_return_type: 1288 funcs += ' return;\n' 1289 funcs += ' }\n' 1290 1291 funcs += return_prefix 1292 funcs += 'icd_term->dispatch.' 1293 funcs += base_name 1294 funcs += '(' 1295 count = 0 1296 for param in ext_cmd.params: 1297 if count != 0: 1298 funcs += ', ' 1299 1300 if param.type == 'VkPhysicalDevice': 1301 funcs += 'phys_dev_term->phys_dev' 1302 else: 1303 funcs += param.name 1304 1305 count += 1 1306 funcs += ');\n' 1307 1308 1309 elif ext_cmd.handle_type == 'VkInstance': 1310 funcs += ' struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name) 1311 funcs += ' if (NULL == inst) {\n' 1312 funcs += ' loader_log(\n' 1313 funcs += ' NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' 1314 funcs += ' "%s: Invalid instance [VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.name, instance_var_name) 1315 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1316 funcs += ' }\n' 1317 funcs += '#error("Not implemented. Likely needs to be manually generated!");\n' 1318 elif ext_cmd.ext_name in ['VK_EXT_debug_utils', 'VK_EXT_debug_marker']: 1319 if ext_cmd.name in ['vkDebugMarkerSetObjectNameEXT', 'vkDebugMarkerSetObjectTagEXT', 'vkSetDebugUtilsObjectNameEXT' , 'vkSetDebugUtilsObjectTagEXT']: 1320 1321 is_debug_utils = ext_cmd.ext_name == "VK_EXT_debug_utils" 1322 debug_struct_name = ext_cmd.params[1].name 1323 local_struct = 'local_name_info' if 'ObjectName' in ext_cmd.name else 'local_tag_info' 1324 member_name = 'objectHandle' if is_debug_utils else 'object' 1325 phys_dev_check = 'VK_OBJECT_TYPE_PHYSICAL_DEVICE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT' 1326 surf_check = 'VK_OBJECT_TYPE_SURFACE_KHR' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT' 1327 inst_check = 'VK_OBJECT_TYPE_INSTANCE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT' 1328 funcs += ' uint32_t icd_index = 0;\n' 1329 funcs += ' struct loader_device *dev;\n' 1330 funcs += f' struct loader_icd_term *icd_term = loader_get_icd_and_device({ ext_cmd.params[0].name}, &dev, &icd_index);\n' 1331 funcs += f' if (NULL == icd_term || NULL == dev) {{\n' 1332 funcs += f' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "{ext_cmd.name[2:]}: Invalid device handle");\n' 1333 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1334 funcs += ' }\n' 1335 funcs += f' { ext_cmd.params[1].type} {local_struct};\n' 1336 funcs += f' memcpy(&{local_struct}, {debug_struct_name}, sizeof({ ext_cmd.params[1].type}));\n' 1337 funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' 1338 funcs += f' if ({debug_struct_name}->objectType == {phys_dev_check}) {{\n' 1339 funcs += f' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t){debug_struct_name}->{member_name};\n' 1340 funcs += f' {local_struct}.{member_name} = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n' 1341 funcs += ' // If this is a KHR_surface, and the ICD has created its own, we have to replace it with the proper one for the next call.\n' 1342 funcs += f' }} else if ({debug_struct_name}->objectType == {surf_check}) {{\n' 1343 funcs += ' if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {\n' 1344 funcs += f' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t){debug_struct_name}->{member_name};\n' 1345 funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n' 1346 funcs += f' {local_struct}.{member_name} = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n' 1347 funcs += ' }\n' 1348 funcs += ' }\n' 1349 funcs += ' // If this is an instance we have to replace it with the proper one for the next call.\n' 1350 funcs += f' }} else if ({debug_struct_name}->objectType == {inst_check}) {{\n' 1351 funcs += f' {local_struct}.{member_name} = (uint64_t)(uintptr_t)icd_term->instance;\n' 1352 funcs += ' }\n' 1353 funcs += ' // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports\n' 1354 funcs += ' // debug utils but the driver does not.\n' 1355 funcs += f' if (NULL == dev->loader_dispatch.extension_terminator_dispatch.{ext_cmd.name[2:]})\n return VK_SUCCESS;\n' 1356 dispatch = 'dev->loader_dispatch.' 1357 else: 1358 funcs += f' struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch({ext_cmd.params[0].name});\n' 1359 funcs += f' if (NULL == dispatch_table) {{\n' 1360 funcs += f' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0, "{ext_cmd.ext_name}: Invalid device handle");\n' 1361 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1362 funcs += ' }\n' 1363 funcs += ' // Only call down if the device supports the function\n' 1364 funcs += f' if (NULL != dispatch_table->extension_terminator_dispatch.{base_name})\n ' 1365 dispatch = 'dispatch_table->' 1366 funcs += ' ' 1367 if has_return_type: 1368 funcs += 'return ' 1369 funcs += f'{dispatch}extension_terminator_dispatch.{base_name}(' 1370 count = 0 1371 for param in ext_cmd.params: 1372 if count != 0: 1373 funcs += ', ' 1374 1375 if param.type == 'VkPhysicalDevice': 1376 funcs += 'phys_dev_term->phys_dev' 1377 elif param.type == 'VkSurfaceKHR': 1378 funcs += 'icd_surface->real_icd_surfaces[icd_index]' 1379 elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo': 1380 funcs += '&local_name_info' 1381 elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo': 1382 funcs += '&local_tag_info' 1383 else: 1384 funcs += param.name 1385 count += 1 1386 1387 funcs += ');\n' 1388 1389 else: 1390 funcs += '#error("Unknown error path!");\n' 1391 1392 funcs += '}\n\n' 1393 else: 1394 funcs += tramp_header 1395 1396 funcs += ' const VkLayerDispatchTable *disp = loader_get_dispatch(' 1397 funcs += ext_cmd.params[0].name 1398 funcs += ');\n' 1399 funcs += ' if (NULL == disp) {\n' 1400 funcs += ' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' 1401 funcs += ' "%s: Invalid %s "\n' % (ext_cmd.name, ext_cmd.params[0].name) 1402 funcs += ' "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.params[0].name) 1403 funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' 1404 funcs += ' }\n' 1405 1406 if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: 1407 funcs += ' if (disp->' + base_name + ' != NULL) {\n' 1408 funcs += ' ' 1409 funcs += return_prefix 1410 funcs += 'disp->' 1411 funcs += base_name 1412 funcs += '(' 1413 count = 0 1414 for param in ext_cmd.params: 1415 if count != 0: 1416 funcs += ', ' 1417 funcs += param.name 1418 count += 1 1419 funcs += ');\n' 1420 if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: 1421 if ext_cmd.return_type is not None: 1422 funcs += ' } else {\n' 1423 funcs += ' return VK_SUCCESS;\n' 1424 funcs += ' }\n' 1425 funcs += '}\n\n' 1426 1427 if ext_cmd.protect is not None: 1428 funcs += '#endif // %s\n' % ext_cmd.protect 1429 1430 return funcs 1431 1432 1433 # 1434 # Create a function for the extension GPA call 1435 def InstExtensionGPA(self): 1436 entries = [] 1437 gpa_func = '' 1438 cur_extension_name = '' 1439 1440 gpa_func += '// GPA helpers for extensions\n' 1441 gpa_func += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) {\n' 1442 gpa_func += ' *addr = NULL;\n\n' 1443 1444 for cur_cmd in self.ext_commands: 1445 if (self.getAPIVersion(cur_cmd.ext_name) or 1446 cur_cmd.ext_name in WSI_EXT_NAMES or 1447 cur_cmd.ext_name in AVOID_EXT_NAMES or 1448 cur_cmd.name in AVOID_CMD_NAMES ): 1449 continue 1450 1451 if cur_cmd.ext_name != cur_extension_name: 1452 gpa_func += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 1453 cur_extension_name = cur_cmd.ext_name 1454 1455 if cur_cmd.protect is not None: 1456 gpa_func += '#if defined(%s)\n' % cur_cmd.protect 1457 1458 #base_name = cur_cmd.name[2:] 1459 base_name = SHARED_ALIASES[cur_cmd.name] if cur_cmd.name in SHARED_ALIASES else cur_cmd.name[2:] 1460 1461 if (cur_cmd.ext_type == 'instance'): 1462 gpa_func += ' if (!strcmp("%s", name)) {\n' % (cur_cmd.name) 1463 gpa_func += ' *addr = (ptr_instance->enabled_known_extensions.' 1464 gpa_func += cur_cmd.ext_name[3:].lower() 1465 gpa_func += ' == 1)\n' 1466 gpa_func += ' ? (void *)%s\n' % (base_name) 1467 gpa_func += ' : NULL;\n' 1468 gpa_func += ' return true;\n' 1469 gpa_func += ' }\n' 1470 else: 1471 gpa_func += ' if (!strcmp("%s", name)) {\n' % (cur_cmd.name) 1472 gpa_func += ' *addr = (void *)%s;\n' % (base_name) 1473 gpa_func += ' return true;\n' 1474 gpa_func += ' }\n' 1475 1476 if cur_cmd.protect is not None: 1477 gpa_func += '#endif // %s\n' % cur_cmd.protect 1478 1479 gpa_func += ' return false;\n' 1480 gpa_func += '}\n\n' 1481 1482 return gpa_func 1483 1484 # 1485 # Create the extension name init function 1486 def InstantExtensionCreate(self): 1487 entries = [] 1488 entries = self.instanceExtensions 1489 count = 0 1490 cur_extension_name = '' 1491 1492 create_func = '' 1493 create_func += '// A function that can be used to query enabled extensions during a vkCreateInstance call\n' 1494 create_func += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {\n' 1495 create_func += ' for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n' 1496 for ext in entries: 1497 if (self.getAPIVersion(ext.name) or ext.name in WSI_EXT_NAMES or 1498 ext.name in AVOID_EXT_NAMES or ext.name in AVOID_CMD_NAMES or 1499 ext.type == 'device' or ext.num_commands == 0): 1500 continue 1501 1502 if ext.name != cur_extension_name: 1503 create_func += '\n // ---- %s extension commands\n' % ext.name 1504 cur_extension_name = ext.name 1505 1506 if ext.protect is not None: 1507 create_func += '#if defined(%s)\n' % ext.protect 1508 if count == 0: 1509 create_func += ' if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], ' 1510 else: 1511 create_func += ' } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], ' 1512 1513 create_func += ext.define + ')) {\n' 1514 create_func += ' ptr_instance->enabled_known_extensions.' 1515 create_func += ext.name[3:].lower() 1516 create_func += ' = 1;\n' 1517 1518 if ext.protect is not None: 1519 create_func += '#endif // %s\n' % ext.protect 1520 count += 1 1521 1522 create_func += ' }\n' 1523 create_func += ' }\n' 1524 create_func += '}\n\n' 1525 return create_func 1526 1527 # 1528 # Create code to initialize a dispatch table from the appropriate list of 1529 # extension entrypoints and return it as a string 1530 def DeviceExtensionGetTerminator(self): 1531 term_func = '' 1532 1533 term_func += '// Some device commands still need a terminator because the loader needs to unwrap something about them.\n' 1534 term_func += '// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object. But there may be other items\n' 1535 term_func += '// in the future.\n' 1536 term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name) {\n' 1537 term_func += ''' *found_name = false; 1538 if (!name || name[0] != 'v' || name[1] != 'k') { 1539 return NULL; 1540 } 1541 name += 2; 1542''' 1543 last_protect = None 1544 last_ext = None 1545 for ext_cmd in self.ext_commands: 1546 version = self.getAPIVersion(ext_cmd.ext_name) 1547 if ext_cmd.name in DEVICE_CMDS_NEED_TERM: 1548 if version: 1549 term_func += f' // ---- Core {version.name} commands\n' 1550 else: 1551 last_protect = ext_cmd.protect 1552 if ext_cmd.protect is not None: 1553 term_func += f'#if defined({ext_cmd.protect})\n' 1554 if (last_ext != ext_cmd.ext_name): 1555 term_func += f' // ---- {ext_cmd.ext_name} extension commands\n' 1556 last_ext = ext_cmd.ext_name 1557 1558 term_func += f' if (!strcmp(name, "{ext_cmd.name[2:]}")) {{\n' 1559 term_func += f' *found_name = true;\n' 1560 if ext_cmd.require: 1561 term_func += f' return dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->driver_extensions.{ext_cmd.require[3:].lower()}_enabled ?\n' 1562 else: 1563 term_func += f' return dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled ?\n' 1564 term_func += f' (PFN_vkVoidFunction)terminator_{(ext_cmd.name[2:])} : NULL;\n' 1565 term_func += f' }}\n' 1566 1567 if last_protect is not None: 1568 term_func += '#endif // %s\n' % last_protect 1569 1570 term_func += ' return NULL;\n' 1571 term_func += '}\n\n' 1572 1573 return term_func 1574 1575 # 1576 # Create a dispatch table solely for device functions which have custom terminators 1577 def OutputDeviceFunctionTerminatorDispatchTable(self): 1578 term_func = '' 1579 term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n' 1580 term_func += '// device function. This is used in the terminators themselves.\n' 1581 term_func += 'struct loader_device_terminator_dispatch {\n' 1582 1583 last_protect = None 1584 last_ext = None 1585 for ext_cmd in self.ext_commands: 1586 version = self.getAPIVersion(ext_cmd.ext_name) 1587 if ext_cmd.name in DEVICE_CMDS_NEED_TERM: 1588 if version: 1589 term_func += f' // ---- Core {version.name} commands\n' 1590 else: 1591 last_protect = ext_cmd.protect 1592 if ext_cmd.protect is not None: 1593 term_func += f'#if defined({ext_cmd.protect})\n' 1594 if (last_ext != ext_cmd.ext_name): 1595 term_func += f' // ---- {ext_cmd.ext_name} extension commands\n' 1596 last_ext = ext_cmd.ext_name 1597 1598 term_func += f' PFN_{ext_cmd.name} {ext_cmd.name[2:]};\n' 1599 1600 if last_protect is not None: 1601 term_func += '#endif // %s\n' % last_protect 1602 1603 term_func += '};\n\n' 1604 1605 return term_func 1606 1607 def OutputDeviceFunctionTrampolinePrototypes(self): 1608 tramp_protos = '' 1609 tramp_protos += '// These are prototypes for functions that need their trampoline called in all circumstances.\n' 1610 tramp_protos += '// They are used in loader_lookup_device_dispatch_table but are defined afterwards.\n' 1611 last_protect = None 1612 last_ext = None 1613 for ext_cmd in self.ext_commands: 1614 version = self.getAPIVersion(ext_cmd.ext_name) 1615 if ext_cmd.name in DEVICE_CMDS_MUST_USE_TRAMP: 1616 if version: 1617 tramp_protos += f' // ---- Core {version.name} commands\n' 1618 else: 1619 last_protect = ext_cmd.protect 1620 if ext_cmd.protect is not None: 1621 tramp_protos += f'#if defined({ext_cmd.protect})\n' 1622 if (last_ext != ext_cmd.ext_name): 1623 tramp_protos += f' // ---- {ext_cmd.ext_name} extension commands\n' 1624 last_ext = ext_cmd.ext_name 1625 1626 tramp_protos += f'{ext_cmd.cdecl.replace("VKAPI_CALL vk", "VKAPI_CALL ")}\n' 1627 1628 if last_protect is not None: 1629 tramp_protos += '#endif // %s\n' % last_protect 1630 tramp_protos += '\n' 1631 return tramp_protos 1632 1633 # 1634 # Create code to initialize a dispatch table from the appropriate list of 1635 # extension entrypoints and return it as a string 1636 def InitDeviceFunctionTerminatorDispatchTable(self): 1637 term_func = '' 1638 1639 term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n' 1640 term_func += '// device function. This is used in the terminators themselves.\n' 1641 term_func += 'void init_extension_device_proc_terminator_dispatch(struct loader_device *dev) {\n' 1642 term_func += ' struct loader_device_terminator_dispatch* dispatch = &dev->loader_dispatch.extension_terminator_dispatch;\n' 1643 term_func += ' PFN_vkGetDeviceProcAddr gpda = (PFN_vkGetDeviceProcAddr)dev->phys_dev_term->this_icd_term->dispatch.GetDeviceProcAddr;\n' 1644 last_protect = None 1645 last_ext = None 1646 for ext_cmd in self.ext_commands: 1647 version = self.getAPIVersion(ext_cmd.ext_name) 1648 if ext_cmd.name in DEVICE_CMDS_NEED_TERM: 1649 if version: 1650 term_func += f' // ---- Core {version.name} commands\n' 1651 else: 1652 last_protect = ext_cmd.protect 1653 if ext_cmd.protect is not None: 1654 term_func += f'#if defined({ext_cmd.protect})\n' 1655 if (last_ext != ext_cmd.ext_name): 1656 term_func += f' // ---- {ext_cmd.ext_name} extension commands\n' 1657 last_ext = ext_cmd.ext_name 1658 1659 1660 if ext_cmd.require: 1661 term_func += f' if (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled && dev->driver_extensions.{ext_cmd.require[3:].lower()}_enabled)\n' 1662 term_func += f' dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n' 1663 else: 1664 term_func += f' if (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled)\n' 1665 term_func += f' dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n' 1666 1667 if last_protect is not None: 1668 term_func += '#endif // %s\n' % last_protect 1669 1670 term_func += '}\n\n' 1671 1672 return term_func 1673 1674 # 1675 # Create code to initialize a dispatch table from the appropriate list of 1676 # core and extension entrypoints and return it as a string 1677 def InitInstLoaderExtensionDispatchTable(self): 1678 commands = [] 1679 table = '' 1680 cur_extension_name = '' 1681 1682 table += '// This table contains the loader\'s instance dispatch table, which contains\n' 1683 table += '// default functions if no instance layers are activated. This contains\n' 1684 table += '// pointers to "terminator functions".\n' 1685 table += 'const VkLayerInstanceDispatchTable instance_disp = {\n' 1686 1687 for x in range(0, 2): 1688 if x == 0: 1689 commands = self.core_commands 1690 else: 1691 commands = self.ext_commands 1692 1693 for cur_cmd in commands: 1694 version = self.getAPIVersion(cur_cmd.ext_name) 1695 if cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice': 1696 if cur_cmd.ext_name != cur_extension_name: 1697 if version: 1698 table += '\n // ---- Core %s commands\n' % version.name 1699 else: 1700 table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name 1701 cur_extension_name = cur_cmd.ext_name 1702 1703 # Remove 'vk' from proto name 1704 base_name = cur_cmd.name[2:] 1705 aliased_name = SHARED_ALIASES[cur_cmd.name][2:] if cur_cmd.name in SHARED_ALIASES else base_name 1706 1707 if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or 1708 base_name == 'EnumerateInstanceExtensionProperties' or 1709 base_name == 'EnumerateInstanceLayerProperties' or 1710 base_name == 'EnumerateInstanceVersion'): 1711 continue 1712 1713 if cur_cmd.protect is not None: 1714 table += '#if defined(%s)\n' % cur_cmd.protect 1715 1716 if base_name == 'GetInstanceProcAddr': 1717 table += ' .%s = %s,\n' % (base_name, cur_cmd.name) 1718 else: 1719 table += ' .%s = terminator_%s,\n' % (base_name, aliased_name) 1720 1721 if cur_cmd.protect is not None: 1722 table += '#endif // %s\n' % cur_cmd.protect 1723 table += '};\n\n' 1724 1725 return table 1726 1727 # 1728 # Create the extension name whitelist array 1729 def OutputInstantExtensionWhitelistArray(self): 1730 extensions = self.instanceExtensions 1731 1732 table = '' 1733 table += '// A null-terminated list of all of the instance extensions supported by the loader.\n' 1734 table += '// If an instance extension name is not in this list, but it is exported by one or more of the\n' 1735 table += '// ICDs detected by the loader, then the extension name not in the list will be filtered out\n' 1736 table += '// before passing the list of extensions to the application.\n' 1737 table += 'const char *const LOADER_INSTANCE_EXTENSIONS[] = {\n' 1738 for ext in extensions: 1739 if ext.type == 'device' or self.getAPIVersion(ext.name): 1740 continue 1741 1742 if ext.protect is not None: 1743 table += '#if defined(%s)\n' % ext.protect 1744 table += ' ' 1745 table += ext.define + ',\n' 1746 1747 if ext.protect is not None: 1748 table += '#endif // %s\n' % ext.protect 1749 table += ' NULL };\n' 1750 return table 1751 1752