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