| #!/usr/bin/python3 -i |
| # |
| # Copyright (c) 2015-2022 The Khronos Group Inc. |
| # Copyright (c) 2015-2022 Valve Corporation |
| # Copyright (c) 2015-2022 LunarG, Inc. |
| # Copyright (c) 2015-2017 Google Inc. |
| # Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| # Copyright (c) 2023-2023 RasterGrid Kft. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # Author: Mark Young <marky@lunarg.com> |
| # Author: Mark Lobodzinski <mark@lunarg.com> |
| |
| import os,re,sys |
| import xml.etree.ElementTree as etree |
| from generator import * |
| from collections import namedtuple |
| from common_codegen import * |
| |
| |
| WSI_EXT_NAMES = ['VK_KHR_surface', |
| 'VK_KHR_display', |
| 'VK_KHR_xlib_surface', |
| 'VK_KHR_xcb_surface', |
| 'VK_KHR_wayland_surface', |
| 'VK_EXT_directfb_surface', |
| 'VK_KHR_win32_surface', |
| 'VK_KHR_android_surface', |
| 'VK_GGP_stream_descriptor_surface', |
| 'VK_MVK_macos_surface', |
| 'VK_MVK_ios_surface', |
| 'VK_EXT_headless_surface', |
| 'VK_EXT_metal_surface', |
| 'VK_FUCHSIA_imagepipe_surface', |
| 'VK_KHR_swapchain', |
| 'VK_KHR_display_swapchain', |
| 'VK_KHR_get_display_properties2', |
| 'VK_KHR_get_surface_capabilities2', |
| 'VK_QNX_screen_surface', |
| 'VK_NN_vi_surface'] |
| |
| ADD_INST_CMDS = ['vkCreateInstance', |
| 'vkEnumerateInstanceExtensionProperties', |
| 'vkEnumerateInstanceLayerProperties', |
| 'vkEnumerateInstanceVersion'] |
| |
| AVOID_EXT_NAMES = ['VK_EXT_debug_report'] |
| |
| NULL_CHECK_EXT_NAMES= ['VK_EXT_debug_utils'] |
| |
| AVOID_CMD_NAMES = ['vkCreateDebugUtilsMessengerEXT', |
| 'vkDestroyDebugUtilsMessengerEXT', |
| 'vkSubmitDebugUtilsMessageEXT'] |
| |
| DEVICE_CMDS_NEED_TERM = ['vkGetDeviceProcAddr', |
| 'vkCreateSwapchainKHR', |
| 'vkCreateSharedSwapchainsKHR', |
| 'vkGetDeviceGroupSurfacePresentModesKHR', |
| 'vkDebugMarkerSetObjectTagEXT', |
| 'vkDebugMarkerSetObjectNameEXT', |
| 'vkSetDebugUtilsObjectNameEXT', |
| 'vkSetDebugUtilsObjectTagEXT', |
| 'vkQueueBeginDebugUtilsLabelEXT', |
| 'vkQueueEndDebugUtilsLabelEXT', |
| 'vkQueueInsertDebugUtilsLabelEXT', |
| 'vkCmdBeginDebugUtilsLabelEXT', |
| 'vkCmdEndDebugUtilsLabelEXT', |
| 'vkCmdInsertDebugUtilsLabelEXT', |
| 'vkGetDeviceGroupSurfacePresentModes2EXT'] |
| |
| DEVICE_CMDS_MUST_USE_TRAMP = ['vkSetDebugUtilsObjectNameEXT', |
| 'vkSetDebugUtilsObjectTagEXT', |
| 'vkDebugMarkerSetObjectNameEXT', |
| 'vkDebugMarkerSetObjectTagEXT'] |
| |
| # These are the aliased functions that use the same terminator for both extension and core versions |
| # Generally, this is only applies to physical device level functions in instance extensions |
| SHARED_ALIASES = { |
| # 1.1 aliases |
| 'vkEnumeratePhysicalDeviceGroupsKHR': 'vkEnumeratePhysicalDeviceGroups', |
| 'vkGetPhysicalDeviceFeatures2KHR': 'vkGetPhysicalDeviceFeatures2', |
| 'vkGetPhysicalDeviceProperties2KHR': 'vkGetPhysicalDeviceProperties2', |
| 'vkGetPhysicalDeviceFormatProperties2KHR': 'vkGetPhysicalDeviceFormatProperties2', |
| 'vkGetPhysicalDeviceImageFormatProperties2KHR': 'vkGetPhysicalDeviceImageFormatProperties2', |
| 'vkGetPhysicalDeviceQueueFamilyProperties2KHR': 'vkGetPhysicalDeviceQueueFamilyProperties2', |
| 'vkGetPhysicalDeviceMemoryProperties2KHR': 'vkGetPhysicalDeviceMemoryProperties2', |
| 'vkGetPhysicalDeviceSparseImageFormatProperties2KHR': 'vkGetPhysicalDeviceSparseImageFormatProperties2', |
| 'vkGetPhysicalDeviceExternalBufferPropertiesKHR': 'vkGetPhysicalDeviceExternalBufferProperties', |
| 'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR': 'vkGetPhysicalDeviceExternalSemaphoreProperties', |
| 'vkGetPhysicalDeviceExternalFencePropertiesKHR': 'vkGetPhysicalDeviceExternalFenceProperties', |
| } |
| |
| PRE_INSTANCE_FUNCTIONS = ['vkEnumerateInstanceExtensionProperties', |
| 'vkEnumerateInstanceLayerProperties', |
| 'vkEnumerateInstanceVersion'] |
| |
| # |
| # API Version |
| class APIVersion: |
| def __init__(self, token, apiname = 'Vulkan', supported = True): |
| self.token = token |
| self.constant = token.replace('_VERSION_', '_API_VERSION_') |
| self.number = token[token.find('_VERSION_') + len('_VERSION_'):].replace('_', '.') |
| self.name = f'{apiname} {self.number}' |
| self.supported = supported |
| |
| # |
| # LoaderExtensionGeneratorOptions - subclass of GeneratorOptions. |
| class LoaderExtensionGeneratorOptions(GeneratorOptions): |
| def __init__(self, |
| conventions = None, |
| filename = None, |
| directory = '.', |
| genpath = None, |
| apiname = None, |
| profile = None, |
| versions = '.*', |
| emitversions = '.*', |
| defaultExtensions = None, |
| addExtensions = None, |
| removeExtensions = None, |
| emitExtensions = None, |
| sortProcedure = regSortFeatures, |
| prefixText = "", |
| genFuncPointers = True, |
| protectFile = True, |
| protectFeature = True, |
| apicall = '', |
| apientry = '', |
| apientryp = '', |
| indentFuncProto = True, |
| indentFuncPointer = False, |
| alignFuncParam = 0, |
| expandEnumerants = True): |
| GeneratorOptions.__init__(self, |
| conventions = conventions, |
| filename = filename, |
| directory = directory, |
| genpath = genpath, |
| apiname = apiname, |
| profile = profile, |
| versions = versions, |
| emitversions = emitversions, |
| defaultExtensions = defaultExtensions, |
| addExtensions = addExtensions, |
| removeExtensions = removeExtensions, |
| emitExtensions = emitExtensions, |
| sortProcedure = sortProcedure) |
| self.prefixText = prefixText |
| self.prefixText = None |
| self.apicall = apicall |
| self.apientry = apientry |
| self.apientryp = apientryp |
| self.alignFuncParam = alignFuncParam |
| self.expandEnumerants = expandEnumerants |
| |
| # |
| # LoaderExtensionOutputGenerator - subclass of OutputGenerator. |
| # Generates dispatch table helper header files for LVL |
| class LoaderExtensionOutputGenerator(OutputGenerator): |
| """Generate dispatch table helper header based on XML element attributes""" |
| def __init__(self, |
| errFile = sys.stderr, |
| warnFile = sys.stderr, |
| diagFile = sys.stdout): |
| OutputGenerator.__init__(self, errFile, warnFile, diagFile) |
| |
| # Internal state - accumulators for different inner block text |
| self.ext_instance_dispatch_list = [] # List of extension entries for instance dispatch list |
| self.ext_device_dispatch_list = [] # List of extension entries for device dispatch list |
| self.core_commands = [] # List of CommandData records for core Vulkan commands |
| self.ext_commands = [] # List of CommandData records for extension Vulkan commands |
| self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'cdecl']) |
| self.CommandData = namedtuple('CommandData', ['name', 'ext_name', 'ext_type', 'require', 'protect', 'return_type', 'handle_type', 'params', 'cdecl']) |
| self.instanceExtensions = [] |
| self.ExtensionData = namedtuple('ExtensionData', ['name', 'type', 'protect', 'define', 'num_commands']) |
| |
| # |
| # Called once at the beginning of each run |
| def beginFile(self, genOpts): |
| OutputGenerator.beginFile(self, genOpts) |
| |
| # User-supplied prefix text, if any (list of strings) |
| if (genOpts.prefixText): |
| for s in genOpts.prefixText: |
| write(s, file=self.outFile) |
| |
| # File Comment |
| file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' |
| file_comment += '// See loader_extension_generator.py for modifications\n' |
| write(file_comment, file=self.outFile) |
| |
| # Copyright Notice |
| copyright = '/*\n' |
| copyright += ' * Copyright (c) 2015-2022 The Khronos Group Inc.\n' |
| copyright += ' * Copyright (c) 2015-2022 Valve Corporation\n' |
| copyright += ' * Copyright (c) 2015-2022 LunarG, Inc.\n' |
| copyright += ' * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n' |
| copyright += ' * Copyright (c) 2023-2023 RasterGrid Kft.\n' |
| copyright += ' *\n' |
| copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' |
| copyright += ' * you may not use this file except in compliance with the License.\n' |
| copyright += ' * You may obtain a copy of the License at\n' |
| copyright += ' *\n' |
| copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' |
| copyright += ' *\n' |
| copyright += ' * Unless required by applicable law or agreed to in writing, software\n' |
| copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' |
| copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' |
| copyright += ' * See the License for the specific language governing permissions and\n' |
| copyright += ' * limitations under the License.\n' |
| copyright += ' *\n' |
| copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n' |
| copyright += ' * Author: Mark Young <marky@lunarg.com>\n' |
| copyright += ' */\n' |
| |
| preamble = '' |
| |
| preamble += '// clang-format off\n' |
| |
| if self.genOpts.filename == 'vk_loader_extensions.h': |
| preamble += '#pragma once\n' |
| |
| elif self.genOpts.filename == 'vk_loader_extensions.c': |
| preamble += '#include <stdio.h>\n' |
| preamble += '#include <stdlib.h>\n' |
| preamble += '#include <string.h>\n' |
| preamble += '#include "vk_loader_platform.h"\n' |
| preamble += '#include "loader.h"\n' |
| preamble += '#include "vk_loader_extensions.h"\n' |
| preamble += '#include <vulkan/vk_icd.h>\n' |
| preamble += '#include "wsi.h"\n' |
| preamble += '#include "debug_utils.h"\n' |
| preamble += '#include "extension_manual.h"\n' |
| |
| elif self.genOpts.filename == 'vk_layer_dispatch_table.h': |
| preamble += '#pragma once\n' |
| preamble += '\n' |
| preamble += '#if !defined(PFN_GetPhysicalDeviceProcAddr)\n' |
| preamble += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\n' |
| preamble += '#endif\n' |
| |
| write(copyright, file=self.outFile) |
| write(preamble, file=self.outFile) |
| |
| # |
| # Write generate and write dispatch tables to output file |
| def endFile(self): |
| file_data = '' |
| |
| if self.genOpts.filename == 'vk_loader_extensions.h': |
| file_data += self.OutputPrototypesInHeader() |
| file_data += self.OutputLoaderTerminators() |
| file_data += self.OutputIcdDispatchTable() |
| file_data += self.OutputIcdExtensionEnableUnion() |
| file_data += self.OutputDeviceFunctionTerminatorDispatchTable() |
| |
| elif self.genOpts.filename == 'vk_loader_extensions.c': |
| file_data += self.OutputUtilitiesInSource() |
| file_data += self.OutputIcdDispatchTableInit() |
| file_data += self.OutputLoaderDispatchTables() |
| file_data += self.InitDeviceFunctionTerminatorDispatchTable() |
| file_data += self.OutputDeviceFunctionTrampolinePrototypes() |
| file_data += self.OutputLoaderLookupFunc() |
| file_data += self.CreateTrampTermFuncs() |
| file_data += self.InstExtensionGPA() |
| file_data += self.InstantExtensionCreate() |
| file_data += self.DeviceExtensionGetTerminator() |
| file_data += self.InitInstLoaderExtensionDispatchTable() |
| file_data += self.OutputInstantExtensionWhitelistArray() |
| |
| elif self.genOpts.filename == 'vk_layer_dispatch_table.h': |
| file_data += self.OutputLayerInstanceDispatchTable() |
| file_data += self.OutputLayerDeviceDispatchTable() |
| |
| file_data += '// clang-format on' |
| |
| write(file_data, file=self.outFile); |
| |
| # Finish processing in superclass |
| OutputGenerator.endFile(self) |
| |
| def beginFeature(self, interface, emit): |
| # Start processing in superclass |
| OutputGenerator.beginFeature(self, interface, emit) |
| self.featureExtraProtect = GetFeatureProtect(interface) |
| |
| enums = interface[0].findall('enum') |
| self.currentExtension = '' |
| self.name_definition = '' |
| |
| for item in enums: |
| name_definition = item.get('name') |
| if 'EXTENSION_NAME' in name_definition: |
| self.name_definition = name_definition |
| |
| self.type = interface.get('type') |
| self.num_commands = 0 |
| name = interface.get('name') |
| self.currentExtension = name |
| |
| # |
| # Process commands, adding to appropriate dispatch tables |
| def genCmd(self, cmdinfo, name, alias): |
| OutputGenerator.genCmd(self, cmdinfo, name, alias) |
| |
| # Get first param type |
| params = cmdinfo.elem.findall('param') |
| info = self.getTypeNameTuple(params[0]) |
| |
| self.num_commands += 1 |
| |
| if 'android' not in name: |
| self.AddCommandToDispatchList(self.currentExtension, self.type, name, cmdinfo, info[0]) |
| |
| def endFeature(self): |
| |
| if 'android' not in self.currentExtension: |
| self.instanceExtensions.append(self.ExtensionData(name=self.currentExtension, |
| type=self.type, |
| protect=self.featureExtraProtect, |
| define=self.name_definition, |
| num_commands=self.num_commands)) |
| |
| # Finish processing in superclass |
| OutputGenerator.endFeature(self) |
| |
| # |
| # Retrieve the value of the len tag |
| def getLen(self, param): |
| result = None |
| len = param.attrib.get('len') |
| if len and len != 'null-terminated': |
| # For string arrays, 'len' can look like 'count,null-terminated', |
| # indicating that we have a null terminated array of strings. We |
| # strip the null-terminated from the 'len' field and only return |
| # the parameter specifying the string count |
| if 'null-terminated' in len: |
| result = len.split(',')[0] |
| else: |
| result = len |
| result = str(result).replace('::', '->') |
| return result |
| |
| # |
| # Returns an APIVersion object corresponding to the specified version token or None |
| def getAPIVersion(self, token): |
| if self.genOpts.apiname == 'vulkansc': |
| if token in ['VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2']: |
| # Vulkan 1.0-1.2 is included in Vulkan SC 1.0 |
| token = 'VKSC_VERSION_1_0' |
| |
| if token.startswith('VKSC_VERSION_'): |
| return APIVersion(token, 'Vulkan SC', True) |
| elif token.startswith('VK_VERSION_'): |
| # Unsupported Vulkan version |
| return APIVersion(token, 'Vulkan', False) |
| else: |
| return None |
| |
| if token.startswith('VK_VERSION_'): |
| return APIVersion(token) |
| return None |
| |
| # |
| # Determine if this API should be ignored or added to the instance or device dispatch table |
| def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type): |
| handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") |
| |
| return_type = cmdinfo.elem.find('proto/type') |
| if (return_type is not None and return_type.text == 'void'): |
| return_type = None |
| |
| require = None |
| if name == 'vkGetDeviceGroupSurfacePresentModes2EXT': |
| require_node = self.registry.tree.find("./extensions/extension[@name='{}']/require/command[@name='{}']/..".format(extension_name, name)) |
| if 'depends' in require_node.attrib: |
| require = require_node.attrib['depends'] |
| |
| cmd_params = [] |
| |
| # Generate a list of commands for use in printing the necessary |
| # core instance terminator prototypes |
| params = cmdinfo.elem.findall('param') |
| lens = set() |
| for param in params: |
| len = self.getLen(param) |
| if len: |
| lens.add(len) |
| paramsInfo = [] |
| for param in params: |
| paramInfo = self.getTypeNameTuple(param) |
| param_type = paramInfo[0] |
| param_name = paramInfo[1] |
| param_cdecl = self.makeCParamDecl(param, 0) |
| cmd_params.append(self.CommandParam(type=param_type, name=param_name, |
| cdecl=param_cdecl)) |
| |
| version = self.getAPIVersion(extension_name) |
| if version and not version.supported: |
| # Skip commands in unsupported versions |
| return |
| |
| if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice': |
| # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# |
| # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality |
| if version: |
| self.core_commands.append( |
| self.CommandData(name=name, ext_name=version.token, |
| ext_type='device', |
| require=require, |
| protect=self.featureExtraProtect, |
| return_type = return_type, |
| handle_type = handle_type, |
| params = cmd_params, |
| cdecl=self.makeCDecls(cmdinfo.elem)[0])) |
| else: |
| self.ext_device_dispatch_list.append((name, self.featureExtraProtect)) |
| self.ext_commands.append( |
| self.CommandData(name=name, ext_name=extension_name, |
| ext_type=extension_type, |
| require=require, |
| protect=self.featureExtraProtect, |
| return_type = return_type, |
| handle_type = handle_type, |
| params = cmd_params, |
| cdecl=self.makeCDecls(cmdinfo.elem)[0])) |
| else: |
| # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# |
| # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality |
| if version: |
| self.core_commands.append( |
| self.CommandData(name=name, ext_name=version.token, |
| ext_type='instance', |
| require=require, |
| protect=self.featureExtraProtect, |
| return_type = return_type, |
| handle_type = handle_type, |
| params = cmd_params, |
| cdecl=self.makeCDecls(cmdinfo.elem)[0])) |
| |
| else: |
| self.ext_instance_dispatch_list.append((name, self.featureExtraProtect)) |
| self.ext_commands.append( |
| self.CommandData(name=name, ext_name=extension_name, |
| ext_type=extension_type, |
| require=require, |
| protect=self.featureExtraProtect, |
| return_type = return_type, |
| handle_type = handle_type, |
| params = cmd_params, |
| cdecl=self.makeCDecls(cmdinfo.elem)[0])) |
| |
| # |
| # Retrieve the type and name for a parameter |
| def getTypeNameTuple(self, param): |
| type = '' |
| name = '' |
| for elem in param: |
| if elem.tag == 'type': |
| type = noneStr(elem.text) |
| elif elem.tag == 'name': |
| name = noneStr(elem.text) |
| return (type, name) |
| |
| # Convert an XML dependency expression to a C expression, taking a callback to replace extension names |
| # See https://registry.khronos.org/vulkan/specs/1.3/registry.html#depends-expressions |
| @staticmethod |
| def ConvertDependencyExpression(expr, replace_func): |
| # '(' and ')' can pass through unchanged |
| expr = re.sub(',', ' || ', expr) |
| expr = re.sub(r'\+', ' && ', expr) |
| expr = re.sub(r'\w+', lambda match: replace_func(match.group()), expr) |
| return expr |
| |
| def OutputPrototypesInHeader(self): |
| protos = '' |
| protos += '// Structures defined externally, but used here\n' |
| protos += 'struct loader_instance;\n' |
| protos += 'struct loader_device;\n' |
| protos += 'struct loader_icd_term;\n' |
| protos += 'struct loader_dev_dispatch_table;\n' |
| protos += '\n' |
| protos += '// Device extension error function\n' |
| protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev);\n' |
| protos += '\n' |
| protos += '// Extension interception for vkGetInstanceProcAddr function, so we can return\n' |
| protos += '// the appropriate information for any instance extensions we know about.\n' |
| protos += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr);\n' |
| protos += '\n' |
| protos += '// Extension interception for vkCreateInstance function, so we can properly\n' |
| protos += '// detect and enable any instance extension information for extensions we know\n' |
| protos += '// about.\n' |
| protos += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo);\n' |
| protos += '\n' |
| protos += '// Extension interception for vkGetDeviceProcAddr function, so we can return\n' |
| protos += '// an appropriate terminator if this is one of those few device commands requiring\n' |
| protos += '// a terminator.\n' |
| protos += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name);\n' |
| protos += '\n' |
| protos += '// Dispatch table properly filled in with appropriate terminators for the\n' |
| protos += '// supported extensions.\n' |
| protos += 'extern const VkLayerInstanceDispatchTable instance_disp;\n' |
| protos += '\n' |
| protos += '// Array of extension strings for instance extensions we support.\n' |
| protos += 'extern const char *const LOADER_INSTANCE_EXTENSIONS[];\n' |
| protos += '\n' |
| protos += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_instance* inst, struct loader_icd_term *icd_term);\n' |
| protos += '\n' |
| protos += '// Init Device function pointer dispatch table with core commands\n' |
| protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n' |
| protos += ' VkDevice dev);\n' |
| protos += '\n' |
| protos += '// Init Device function pointer dispatch table with extension commands\n' |
| protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n' |
| protos += ' PFN_vkGetInstanceProcAddr gipa,\n' |
| protos += ' PFN_vkGetDeviceProcAddr gdpa,\n' |
| protos += ' VkInstance inst,\n' |
| protos += ' VkDevice dev);\n' |
| protos += '\n' |
| protos += '// Init Instance function pointer dispatch table with core commands\n' |
| protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' |
| protos += ' VkInstance inst);\n' |
| protos += '\n' |
| protos += '// Init Instance function pointer dispatch table with core commands\n' |
| protos += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' |
| protos += ' VkInstance inst);\n' |
| protos += '\n' |
| protos += '// Device command lookup function\n' |
| protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name, bool* name_found);\n' |
| protos += '\n' |
| protos += '// Instance command lookup function\n' |
| protos += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n' |
| protos += ' bool *found_name);\n' |
| protos += '\n' |
| return protos |
| |
| def OutputUtilitiesInSource(self): |
| protos = '' |
| protos += '// Device extension error function\n' |
| protos += 'VKAPI_ATTR VkResult VKAPI_CALL vkDevExtError(VkDevice dev) {\n' |
| protos += ' struct loader_device *found_dev;\n' |
| protos += ' // The device going in is a trampoline device\n' |
| protos += ' struct loader_icd_term *icd_term = loader_get_icd_and_device(dev, &found_dev);\n' |
| protos += '\n' |
| protos += ' if (icd_term)\n' |
| protos += ' loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,\n' |
| protos += ' "Bad destination in loader trampoline dispatch,"\n' |
| protos += ' "Are layers and extensions that you are calling enabled?");\n' |
| protos += ' return VK_ERROR_EXTENSION_NOT_PRESENT;\n' |
| protos += '}\n\n' |
| return protos |
| |
| # |
| # Create a layer instance dispatch table from the appropriate list and return it as a string |
| def OutputLayerInstanceDispatchTable(self): |
| commands = [] |
| table = '' |
| cur_extension_name = '' |
| |
| table += '// Instance function pointer dispatch table\n' |
| table += 'typedef struct VkLayerInstanceDispatchTable_ {\n' |
| |
| # First add in an entry for GetPhysicalDeviceProcAddr. This will not |
| # ever show up in the XML or header, so we have to manually add it. |
| table += ' // Manually add in GetPhysicalDeviceProcAddr entry\n' |
| table += ' PFN_GetPhysicalDeviceProcAddr GetPhysicalDeviceProcAddr;\n' |
| |
| for x in range(0, 2): |
| if x == 0: |
| commands = self.core_commands |
| else: |
| commands = self.ext_commands |
| |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' |
| if is_inst_handle_type: |
| |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| table += '\n // ---- Core %s commands\n' % version.name |
| else: |
| table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| |
| if cur_cmd.protect is not None: |
| table += '#if defined(%s)\n' % cur_cmd.protect |
| |
| table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) |
| |
| if cur_cmd.protect is not None: |
| table += '#endif // %s\n' % cur_cmd.protect |
| |
| table += '} VkLayerInstanceDispatchTable;\n\n' |
| return table |
| |
| # |
| # Create a layer device dispatch table from the appropriate list and return it as a string |
| def OutputLayerDeviceDispatchTable(self): |
| commands = [] |
| table = '' |
| cur_extension_name = '' |
| |
| table += '// Device function pointer dispatch table\n' |
| table += '#define DEVICE_DISP_TABLE_MAGIC_NUMBER 0x10ADED040410ADEDUL\n' |
| table += 'typedef struct VkLayerDispatchTable_ {\n' |
| table += ' uint64_t magic; // Should be DEVICE_DISP_TABLE_MAGIC_NUMBER\n' |
| |
| for x in range(0, 2): |
| if x == 0: |
| commands = self.core_commands |
| else: |
| commands = self.ext_commands |
| |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' |
| if not is_inst_handle_type: |
| |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| table += '\n // ---- Core %s commands\n' % version.name |
| else: |
| table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| |
| if cur_cmd.protect is not None: |
| table += '#if defined(%s)\n' % cur_cmd.protect |
| |
| table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) |
| |
| if cur_cmd.protect is not None: |
| table += '#endif // %s\n' % cur_cmd.protect |
| |
| table += '} VkLayerDispatchTable;\n\n' |
| return table |
| |
| # |
| # Common code between the dispatch table struct and the function filling out said struct |
| def ShouldPrintInIcdDispatchTable(self, cur_cmd, skip_list): |
| return cur_cmd.name == 'vkGetDeviceProcAddr' or \ |
| (cur_cmd.handle_type not in ['VkDevice', 'VkCommandBuffer', 'VkQueue'] and cur_cmd.name not in skip_list) |
| |
| # |
| # Create a dispatch table from the appropriate list and return it as a string |
| def OutputIcdDispatchTable(self): |
| commands = [] |
| table = '' |
| cur_extension_name = '' |
| |
| skip_commands = ['vkGetInstanceProcAddr', |
| 'vkEnumerateDeviceLayerProperties', |
| ] |
| |
| table += '// ICD function pointer dispatch table\n' |
| table += 'struct loader_icd_term_dispatch {\n' |
| |
| for x in range(0, 2): |
| if x == 0: |
| commands = self.core_commands |
| else: |
| commands = self.ext_commands |
| |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_commands)): |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| table += '\n // ---- Core %s commands\n' % version.name |
| else: |
| table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| |
| if cur_cmd.protect is not None: |
| table += '#if defined(%s)\n' % cur_cmd.protect |
| |
| table += ' PFN_%s %s;\n' % (cur_cmd.name, base_name) |
| |
| if cur_cmd.protect is not None: |
| table += '#endif // %s\n' % cur_cmd.protect |
| |
| table += '};\n\n' |
| return table |
| |
| # |
| # Init a dispatch table from the appropriate list and return it as a string |
| def OutputIcdDispatchTableInit(self): |
| commands = [] |
| cur_extension_name = '' |
| |
| table = '' |
| table += 'VKAPI_ATTR bool VKAPI_CALL loader_icd_init_entries(struct loader_instance* inst, struct loader_icd_term *icd_term) {\n' |
| table += ' const PFN_vkGetInstanceProcAddr fp_gipa = icd_term->scanned_icd->GetInstanceProcAddr;\n' |
| table += '\n' |
| table += '#define LOOKUP_GIPA(func) icd_term->dispatch.func = (PFN_vk##func)fp_gipa(icd_term->instance, "vk" #func);\n' |
| table += '\n' |
| table += '#define LOOKUP_REQUIRED_GIPA(func) \\\n' |
| table += ' do { \\\n' |
| table += ' LOOKUP_GIPA(func); \\\n' |
| table += ' if (!icd_term->dispatch.func) { \\\n' |
| table += ' loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Unable to load %s from ICD %s",\\\n' |
| table += ' "vk"#func, icd_term->scanned_icd->lib_name); \\\n' |
| table += ' return false; \\\n' |
| table += ' } \\\n' |
| table += ' } while (0)\n' |
| table += '\n' |
| |
| |
| skip_gipa_commands = ['vkGetInstanceProcAddr', |
| 'vkEnumerateDeviceLayerProperties', |
| 'vkCreateInstance', |
| 'vkEnumerateInstanceExtensionProperties', |
| 'vkEnumerateInstanceLayerProperties', |
| 'vkEnumerateInstanceVersion', |
| ] |
| |
| for x in range(0, 2): |
| if x == 0: |
| commands = self.core_commands |
| else: |
| commands = self.ext_commands |
| |
| required = False |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| if (self.ShouldPrintInIcdDispatchTable(cur_cmd, skip_gipa_commands)): |
| |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| table += '\n // ---- Core %s\n' % version.name |
| required = version.number == '1.0' |
| else: |
| table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| required = False |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| |
| if cur_cmd.protect is not None: |
| table += '#if defined(%s)\n' % cur_cmd.protect |
| |
| if required: |
| # The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_# |
| # For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality |
| table += f' LOOKUP_REQUIRED_GIPA({base_name});\n' |
| else: |
| table += f' LOOKUP_GIPA({base_name});\n' |
| if cur_cmd.protect is not None: |
| table += '#endif // %s\n' % cur_cmd.protect |
| |
| table += '\n' |
| table += '#undef LOOKUP_REQUIRED_GIPA\n' |
| table += '#undef LOOKUP_GIPA\n' |
| table += '\n' |
| table += ' return true;\n' |
| table += '};\n\n' |
| return table |
| |
| # |
| # Create the extension enable union |
| def OutputIcdExtensionEnableUnion(self): |
| extensions = self.instanceExtensions |
| |
| union = '' |
| union += 'struct loader_instance_extension_enables {\n' |
| for ext in extensions: |
| if (self.getAPIVersion(ext.name) or ext.name in WSI_EXT_NAMES or |
| ext.type == 'device' or ext.num_commands == 0): |
| continue |
| |
| union += ' uint8_t %s;\n' % ext.name[3:].lower() |
| |
| union += '};\n\n' |
| return union |
| |
| # |
| # Creates the prototypes for the loader's core instance command terminators |
| def OutputLoaderTerminators(self): |
| terminators = '' |
| terminators += '// Loader core instance terminators\n' |
| |
| for cur_cmd in self.core_commands: |
| is_inst_handle_type = cur_cmd.name in ADD_INST_CMDS or cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' |
| if is_inst_handle_type: |
| mod_string = '' |
| new_terminator = cur_cmd.cdecl |
| mod_string = new_terminator.replace("VKAPI_CALL vk", "VKAPI_CALL terminator_") |
| |
| if cur_cmd.name in PRE_INSTANCE_FUNCTIONS: |
| pre_instance_basic_version = mod_string |
| mod_string = mod_string.replace("terminator_", "terminator_pre_instance_") |
| mod_string = mod_string.replace(cur_cmd.name[2:] + '(\n', cur_cmd.name[2:] + '(\n const Vk' + cur_cmd.name[2:] + 'Chain* chain,\n') |
| |
| if cur_cmd.protect is not None: |
| terminators += '#if defined(%s)\n' % cur_cmd.protect |
| |
| if cur_cmd.name in PRE_INSTANCE_FUNCTIONS: |
| terminators += pre_instance_basic_version |
| terminators += '\n' |
| |
| terminators += mod_string |
| terminators += '\n' |
| |
| if cur_cmd.protect is not None: |
| terminators += '#endif // %s\n' % cur_cmd.protect |
| |
| terminators += '\n' |
| return terminators |
| |
| # |
| # Creates code to initialize the various dispatch tables |
| def OutputLoaderDispatchTables(self): |
| commands = [] |
| tables = '' |
| gpa_param = '' |
| cur_type = '' |
| cur_extension_name = '' |
| |
| for x in range(0, 4): |
| if x == 0: |
| cur_type = 'device' |
| gpa_param = 'dev' |
| commands = self.core_commands |
| |
| tables += '// Init Device function pointer dispatch table with core commands\n' |
| tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_dispatch_table(struct loader_dev_dispatch_table *dev_table, PFN_vkGetDeviceProcAddr gpa,\n' |
| tables += ' VkDevice dev) {\n' |
| tables += ' VkLayerDispatchTable *table = &dev_table->core_dispatch;\n' |
| tables += ' if (table->magic != DEVICE_DISP_TABLE_MAGIC_NUMBER) { abort(); }\n' |
| tables += ' for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) dev_table->ext_dispatch[i] = (PFN_vkDevExt)vkDevExtError;\n' |
| |
| elif x == 1: |
| cur_type = 'device' |
| gpa_param = 'dev' |
| commands = self.ext_commands |
| |
| tables += '// Init Device function pointer dispatch table with extension commands\n' |
| tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_device_extension_dispatch_table(struct loader_dev_dispatch_table *dev_table,\n' |
| tables += ' PFN_vkGetInstanceProcAddr gipa,\n' |
| tables += ' PFN_vkGetDeviceProcAddr gdpa,\n' |
| tables += ' VkInstance inst,\n' |
| tables += ' VkDevice dev) {\n' |
| tables += ' VkLayerDispatchTable *table = &dev_table->core_dispatch;\n' |
| tables += ' table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n' |
| |
| elif x == 2: |
| cur_type = 'instance' |
| gpa_param = 'inst' |
| commands = self.core_commands |
| |
| tables += '// Init Instance function pointer dispatch table with core commands\n' |
| tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' |
| tables += ' VkInstance inst) {\n' |
| |
| else: |
| cur_type = 'instance' |
| gpa_param = 'inst' |
| commands = self.ext_commands |
| |
| tables += '// Init Instance function pointer dispatch table with core commands\n' |
| tables += 'VKAPI_ATTR void VKAPI_CALL loader_init_instance_extension_dispatch_table(VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa,\n' |
| tables += ' VkInstance inst) {\n' |
| |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' |
| if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)): |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| tables += '\n // ---- Core %s commands\n' % version.name |
| else: |
| tables += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| |
| # Names to skip |
| if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or |
| base_name == 'EnumerateInstanceExtensionProperties' or |
| base_name == 'EnumerateInstanceLayerProperties' or |
| base_name == 'EnumerateInstanceVersion'): |
| continue |
| |
| if cur_cmd.protect is not None: |
| tables += '#if defined(%s)\n' % cur_cmd.protect |
| |
| # If we're looking for the proc we are passing in, just point the table to it. This fixes the issue where |
| # a layer overrides the function name for the loader. |
| if x == 1: |
| if base_name == 'GetDeviceProcAddr': |
| tables += ' table->GetDeviceProcAddr = gdpa;\n' |
| elif cur_cmd.ext_type == 'instance': |
| tables += ' table->%s = (PFN_%s)gipa(inst, "%s");\n' % (base_name, cur_cmd.name, cur_cmd.name) |
| else: |
| tables += ' table->%s = (PFN_%s)gdpa(dev, "%s");\n' % (base_name, cur_cmd.name, cur_cmd.name) |
| elif (x < 1 and base_name == 'GetDeviceProcAddr'): |
| tables += ' table->GetDeviceProcAddr = gpa;\n' |
| elif (x > 1 and base_name == 'GetInstanceProcAddr'): |
| tables += ' table->GetInstanceProcAddr = gpa;\n' |
| else: |
| tables += ' table->%s = (PFN_%s)gpa(%s, "%s");\n' % (base_name, cur_cmd.name, gpa_param, cur_cmd.name) |
| |
| if cur_cmd.protect is not None: |
| tables += '#endif // %s\n' % cur_cmd.protect |
| |
| tables += '}\n\n' |
| return tables |
| |
| # |
| # Create a lookup table function from the appropriate list of entrypoints and |
| # return it as a string |
| def OutputLoaderLookupFunc(self): |
| commands = [] |
| tables = '' |
| cur_type = '' |
| cur_extension_name = '' |
| |
| for x in range(0, 2): |
| if x == 0: |
| cur_type = 'device' |
| |
| tables += '// Device command lookup function\n' |
| tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_device_dispatch_table(const VkLayerDispatchTable *table, const char *name, bool* found_name) {\n' |
| tables += ' if (!name || name[0] != \'v\' || name[1] != \'k\') {\n' |
| tables += ' *found_name = false;\n' |
| tables += ' return NULL;\n' |
| tables += ' }\n' |
| tables += '\n' |
| tables += ' name += 2;\n' |
| tables += ' *found_name = true;\n' |
| tables += ' struct loader_device* dev = (struct loader_device *)table;\n' |
| tables += ' const struct loader_instance* inst = dev->phys_dev_term->this_icd_term->this_instance;\n' |
| 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' |
| tables += '\n' |
| else: |
| cur_type = 'instance' |
| |
| tables += '// Instance command lookup function\n' |
| tables += 'VKAPI_ATTR void* VKAPI_CALL loader_lookup_instance_dispatch_table(const VkLayerInstanceDispatchTable *table, const char *name,\n' |
| tables += ' bool *found_name) {\n' |
| tables += ' if (!name || name[0] != \'v\' || name[1] != \'k\') {\n' |
| tables += ' *found_name = false;\n' |
| tables += ' return NULL;\n' |
| tables += ' }\n' |
| tables += '\n' |
| tables += ' *found_name = true;\n' |
| tables += ' name += 2;\n' |
| |
| |
| for y in range(0, 2): |
| if y == 0: |
| commands = self.core_commands |
| else: |
| commands = self.ext_commands |
| |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice' |
| if ((cur_type == 'instance' and is_inst_handle_type) or (cur_type == 'device' and not is_inst_handle_type)): |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| tables += '\n // ---- Core %s commands\n' % version.name |
| if cur_type == 'device': |
| version_check = f' if (dev->should_ignore_device_commands_from_newer_version && api_version < {version.constant}) return NULL;\n' |
| else: |
| |
| tables += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| version_check = '' |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| |
| if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or |
| base_name == 'EnumerateInstanceExtensionProperties' or |
| base_name == 'EnumerateInstanceLayerProperties' or |
| base_name == 'EnumerateInstanceVersion'): |
| continue |
| |
| if cur_cmd.protect is not None: |
| tables += '#if defined(%s)\n' % cur_cmd.protect |
| |
| tables += f' if (!strcmp(name, "{base_name}")) ' |
| if cur_cmd.name in DEVICE_CMDS_MUST_USE_TRAMP: |
| if version_check != '': |
| tables += f'{{\n{version_check} return dev->layer_extensions.{cur_cmd.ext_name[3:].lower()}_enabled ? (void *){base_name} : NULL;\n }}\n' |
| else: |
| tables += f'return dev->layer_extensions.{cur_cmd.ext_name[3:].lower()}_enabled ? (void *){base_name} : NULL;\n' |
| |
| else: |
| if version_check != '': |
| tables += f'{{\n{version_check} return (void *)table->{base_name};\n }}\n' |
| else: |
| tables += f'return (void *)table->{base_name};\n' |
| |
| if cur_cmd.protect is not None: |
| tables += '#endif // %s\n' % cur_cmd.protect |
| |
| tables += '\n' |
| tables += ' *found_name = false;\n' |
| tables += ' return NULL;\n' |
| tables += '}\n\n' |
| return tables |
| |
| # |
| # Create the appropriate trampoline (and possibly terminator) functions |
| def CreateTrampTermFuncs(self): |
| entries = [] |
| funcs = '' |
| cur_extension_name = '' |
| |
| # Some extensions have to be manually added. Skip those in the automatic |
| # generation. They will be manually added later. |
| manual_ext_commands = ['vkEnumeratePhysicalDeviceGroupsKHR', |
| 'vkGetPhysicalDeviceExternalImageFormatPropertiesNV', |
| 'vkGetPhysicalDeviceFeatures2KHR', |
| 'vkGetPhysicalDeviceProperties2KHR', |
| 'vkGetPhysicalDeviceFormatProperties2KHR', |
| 'vkGetPhysicalDeviceImageFormatProperties2KHR', |
| 'vkGetPhysicalDeviceQueueFamilyProperties2KHR', |
| 'vkGetPhysicalDeviceMemoryProperties2KHR', |
| 'vkGetPhysicalDeviceSparseImageFormatProperties2KHR', |
| 'vkGetPhysicalDeviceSurfaceCapabilities2KHR', |
| 'vkGetPhysicalDeviceSurfaceFormats2KHR', |
| 'vkGetPhysicalDeviceSurfaceCapabilities2EXT', |
| 'vkReleaseDisplayEXT', |
| 'vkAcquireXlibDisplayEXT', |
| 'vkGetRandROutputDisplayEXT', |
| 'vkGetPhysicalDeviceExternalBufferPropertiesKHR', |
| 'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR', |
| 'vkGetPhysicalDeviceExternalFencePropertiesKHR', |
| 'vkGetPhysicalDeviceDisplayProperties2KHR', |
| 'vkGetPhysicalDeviceDisplayPlaneProperties2KHR', |
| 'vkGetDisplayModeProperties2KHR', |
| 'vkGetDisplayPlaneCapabilities2KHR', |
| 'vkGetPhysicalDeviceSurfacePresentModes2EXT', |
| 'vkGetDeviceGroupSurfacePresentModes2EXT', |
| 'vkGetPhysicalDeviceToolPropertiesEXT'] |
| |
| for ext_cmd in self.ext_commands: |
| if (ext_cmd.ext_name in WSI_EXT_NAMES or |
| ext_cmd.ext_name in AVOID_EXT_NAMES or |
| ext_cmd.name in AVOID_CMD_NAMES or |
| ext_cmd.name in manual_ext_commands): |
| continue |
| |
| version = self.getAPIVersion(ext_cmd.ext_name) |
| if ext_cmd.ext_name != cur_extension_name: |
| if version: |
| funcs += '\n// ---- Core %s trampoline/terminators\n\n' % version.name |
| else: |
| funcs += '\n// ---- %s extension trampoline/terminators\n\n' % ext_cmd.ext_name |
| cur_extension_name = ext_cmd.ext_name |
| |
| if ext_cmd.protect is not None: |
| funcs += '#if defined(%s)\n' % ext_cmd.protect |
| |
| func_header = ext_cmd.cdecl.replace(";", " {\n") |
| tramp_header = func_header.replace("VKAPI_CALL vk", "VKAPI_CALL ") |
| return_prefix = ' ' |
| base_name = ext_cmd.name[2:] |
| has_surface = 0 |
| update_structure_surface = 0 |
| update_structure_string = '' |
| requires_terminator = 0 |
| surface_var_name = '' |
| phys_dev_var_name = '' |
| instance_var_name = '' |
| has_return_type = False |
| always_use_param_name = True |
| surface_type_to_replace = '' |
| surface_name_replacement = '' |
| physdev_type_to_replace = '' |
| physdev_name_replacement = '' |
| |
| for param in ext_cmd.params: |
| if param.type == 'VkSurfaceKHR': |
| has_surface = 1 |
| surface_var_name = param.name |
| requires_terminator = 1 |
| always_use_param_name = False |
| surface_type_to_replace = 'VkSurfaceKHR' |
| surface_name_replacement = 'icd_term->surface_list[icd_surface->surface_index]' |
| if param.type == 'VkPhysicalDeviceSurfaceInfo2KHR': |
| has_surface = 1 |
| surface_var_name = param.name + '->surface' |
| requires_terminator = 1 |
| update_structure_surface = 1 |
| update_structure_string = ' VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;\n' |
| update_structure_string += ' info_copy.surface = icd_term->surface_list[icd_surface->surface_index];\n' |
| always_use_param_name = False |
| surface_type_to_replace = 'VkPhysicalDeviceSurfaceInfo2KHR' |
| surface_name_replacement = '&info_copy' |
| if param.type == 'VkPhysicalDevice': |
| requires_terminator = 1 |
| phys_dev_var_name = param.name |
| always_use_param_name = False |
| physdev_type_to_replace = 'VkPhysicalDevice' |
| physdev_name_replacement = 'phys_dev_term->phys_dev' |
| if param.type == 'VkInstance': |
| requires_terminator = 1 |
| instance_var_name = param.name |
| |
| if (ext_cmd.return_type is not None): |
| return_prefix += 'return ' |
| has_return_type = True |
| |
| if (ext_cmd.handle_type == 'VkInstance' or ext_cmd.handle_type == 'VkPhysicalDevice' or |
| 'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or |
| ext_cmd.name in DEVICE_CMDS_NEED_TERM): |
| requires_terminator = 1 |
| |
| if requires_terminator == 1: |
| term_header = tramp_header.replace("VKAPI_CALL ", "VKAPI_CALL terminator_") |
| |
| funcs += tramp_header |
| |
| if ext_cmd.handle_type == 'VkPhysicalDevice': |
| funcs += ' const VkLayerInstanceDispatchTable *disp;\n' |
| funcs += ' VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(%s);\n' % (phys_dev_var_name) |
| funcs += ' if (VK_NULL_HANDLE == unwrapped_phys_dev) {\n' |
| funcs += ' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' |
| funcs += ' "%s: Invalid %s "\n' % (ext_cmd.name, phys_dev_var_name) |
| funcs += ' "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, phys_dev_var_name) |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| funcs += ' disp = loader_get_instance_layer_dispatch(%s);\n' % (phys_dev_var_name) |
| elif ext_cmd.handle_type == 'VkInstance': |
| funcs += ' struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name) |
| funcs += ' if (NULL == inst) {\n' |
| funcs += ' loader_log(\n' |
| funcs += ' NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' |
| funcs += ' "%s: Invalid instance [VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.name, instance_var_name) |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| funcs += '#error("Not implemented. Likely needs to be manually generated!");\n' |
| else: |
| funcs += ' const VkLayerDispatchTable *disp = loader_get_dispatch(' |
| funcs += ext_cmd.params[0].name |
| funcs += ');\n' |
| funcs += ' if (NULL == disp) {\n' |
| funcs += ' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' |
| funcs += ' "%s: Invalid %s "\n' % (ext_cmd.name, ext_cmd.params[0].name) |
| funcs += ' "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.params[0].name) |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| |
| if 'DebugMarkerSetObjectName' in ext_cmd.name: |
| funcs += ' VkDebugMarkerObjectNameInfoEXT local_name_info;\n' |
| funcs += ' memcpy(&local_name_info, pNameInfo, sizeof(VkDebugMarkerObjectNameInfoEXT));\n' |
| funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' |
| funcs += ' if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n' |
| funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->object;\n' |
| funcs += ' local_name_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' |
| funcs += ' }\n' |
| funcs += ' if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) {\n' |
| funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pNameInfo->object;\n' |
| funcs += ' local_name_info.object = (uint64_t)(uintptr_t)instance->instance;\n' |
| funcs += ' }\n' |
| elif 'DebugMarkerSetObjectTag' in ext_cmd.name: |
| funcs += ' VkDebugMarkerObjectTagInfoEXT local_tag_info;\n' |
| funcs += ' memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugMarkerObjectTagInfoEXT));\n' |
| funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' |
| funcs += ' if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT) {\n' |
| funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->object;\n' |
| funcs += ' local_tag_info.object = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' |
| funcs += ' }\n' |
| funcs += ' if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT) {\n' |
| funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pTagInfo->object;\n' |
| funcs += ' local_tag_info.object = (uint64_t)(uintptr_t)instance->instance;\n' |
| funcs += ' }\n' |
| elif 'SetDebugUtilsObjectName' in ext_cmd.name: |
| funcs += ' VkDebugUtilsObjectNameInfoEXT local_name_info;\n' |
| funcs += ' memcpy(&local_name_info, pNameInfo, sizeof(VkDebugUtilsObjectNameInfoEXT));\n' |
| funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' |
| funcs += ' if (pNameInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n' |
| funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pNameInfo->objectHandle;\n' |
| funcs += ' local_name_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' |
| funcs += ' }\n' |
| funcs += ' if (pNameInfo->objectType == VK_OBJECT_TYPE_INSTANCE) {\n' |
| funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pNameInfo->objectHandle;\n' |
| funcs += ' local_name_info.objectHandle = (uint64_t)(uintptr_t)instance->instance;\n' |
| funcs += ' }\n' |
| elif 'SetDebugUtilsObjectTag' in ext_cmd.name: |
| funcs += ' VkDebugUtilsObjectTagInfoEXT local_tag_info;\n' |
| funcs += ' memcpy(&local_tag_info, pTagInfo, sizeof(VkDebugUtilsObjectTagInfoEXT));\n' |
| funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' |
| funcs += ' if (pTagInfo->objectType == VK_OBJECT_TYPE_PHYSICAL_DEVICE) {\n' |
| funcs += ' struct loader_physical_device_tramp *phys_dev_tramp = (struct loader_physical_device_tramp *)(uintptr_t)pTagInfo->objectHandle;\n' |
| funcs += ' local_tag_info.objectHandle = (uint64_t)(uintptr_t)phys_dev_tramp->phys_dev;\n' |
| funcs += ' }\n' |
| funcs += ' if (pTagInfo->objectType == VK_OBJECT_TYPE_INSTANCE) {\n' |
| funcs += ' struct loader_instance* instance = (struct loader_instance *)(uintptr_t)pTagInfo->objectHandle;\n' |
| funcs += ' local_tag_info.objectHandle = (uint64_t)(uintptr_t)instance->instance;\n' |
| funcs += ' }\n' |
| |
| if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: |
| funcs += ' if (disp->' + base_name + ' != NULL) {\n' |
| funcs += ' ' |
| funcs += return_prefix |
| if ext_cmd.handle_type == 'VkInstance': |
| funcs += 'inst->' |
| funcs += 'disp->' |
| funcs += base_name |
| funcs += '(' |
| count = 0 |
| for param in ext_cmd.params: |
| if count != 0: |
| funcs += ', ' |
| |
| if param.type == 'VkPhysicalDevice': |
| funcs += 'unwrapped_phys_dev' |
| elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo': |
| funcs += '&local_name_info' |
| elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo': |
| funcs += '&local_tag_info' |
| else: |
| funcs += param.name |
| |
| count += 1 |
| funcs += ');\n' |
| if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: |
| if ext_cmd.return_type is not None: |
| funcs += ' } else {\n' |
| funcs += ' return VK_SUCCESS;\n' |
| funcs += ' }\n' |
| funcs += '}\n\n' |
| |
| funcs += term_header |
| if ext_cmd.handle_type == 'VkPhysicalDevice': |
| funcs += ' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)%s;\n' % (phys_dev_var_name) |
| funcs += ' struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;\n' |
| funcs += ' if (NULL == icd_term->dispatch.' |
| funcs += base_name |
| funcs += ') {\n' |
| fatal_error_bit = '' if ext_cmd.ext_type =='instance' and has_return_type else 'VULKAN_LOADER_FATAL_ERROR_BIT | ' |
| funcs += f' loader_log(icd_term->this_instance, {fatal_error_bit}VULKAN_LOADER_ERROR_BIT, 0,\n' |
| funcs += ' "ICD associated with VkPhysicalDevice does not support ' |
| funcs += base_name |
| funcs += '");\n' |
| |
| # 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 |
| # error here. |
| if ext_cmd.ext_type =='instance' and has_return_type: |
| funcs += ' return VK_ERROR_EXTENSION_NOT_PRESENT;\n' |
| else: |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| |
| if has_surface == 1: |
| funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(%s);\n' % (surface_var_name) |
| funcs += ' if (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' |
| |
| # If there's a structure with a surface, we need to update its internals with the correct surface for the ICD |
| if update_structure_surface == 1: |
| funcs += update_structure_string |
| |
| funcs += ' ' + return_prefix + 'icd_term->dispatch.' |
| funcs += base_name |
| funcs += '(' |
| count = 0 |
| for param in ext_cmd.params: |
| if count != 0: |
| funcs += ', ' |
| |
| if not always_use_param_name: |
| if surface_type_to_replace and surface_type_to_replace == param.type: |
| funcs += surface_name_replacement |
| elif physdev_type_to_replace and physdev_type_to_replace == param.type: |
| funcs += physdev_name_replacement |
| else: |
| funcs += param.name |
| else: |
| funcs += param.name |
| |
| count += 1 |
| funcs += ');\n' |
| if not has_return_type: |
| funcs += ' return;\n' |
| funcs += ' }\n' |
| |
| funcs += return_prefix |
| funcs += 'icd_term->dispatch.' |
| funcs += base_name |
| funcs += '(' |
| count = 0 |
| for param in ext_cmd.params: |
| if count != 0: |
| funcs += ', ' |
| |
| if param.type == 'VkPhysicalDevice': |
| funcs += 'phys_dev_term->phys_dev' |
| else: |
| funcs += param.name |
| |
| count += 1 |
| funcs += ');\n' |
| |
| |
| elif ext_cmd.handle_type == 'VkInstance': |
| funcs += ' struct loader_instance *inst = loader_get_instance(%s);\n' % (instance_var_name) |
| funcs += ' if (NULL == inst) {\n' |
| funcs += ' loader_log(\n' |
| funcs += ' NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' |
| funcs += ' "%s: Invalid instance [VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.name, instance_var_name) |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| funcs += '#error("Not implemented. Likely needs to be manually generated!");\n' |
| elif ext_cmd.ext_name in ['VK_EXT_debug_utils', 'VK_EXT_debug_marker']: |
| if ext_cmd.name in ['vkDebugMarkerSetObjectNameEXT', 'vkDebugMarkerSetObjectTagEXT', 'vkSetDebugUtilsObjectNameEXT' , 'vkSetDebugUtilsObjectTagEXT']: |
| |
| is_debug_utils = ext_cmd.ext_name == "VK_EXT_debug_utils" |
| debug_struct_name = ext_cmd.params[1].name |
| local_struct = 'local_name_info' if 'ObjectName' in ext_cmd.name else 'local_tag_info' |
| member_name = 'objectHandle' if is_debug_utils else 'object' |
| phys_dev_check = 'VK_OBJECT_TYPE_PHYSICAL_DEVICE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT' |
| surf_check = 'VK_OBJECT_TYPE_SURFACE_KHR' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT' |
| inst_check = 'VK_OBJECT_TYPE_INSTANCE' if is_debug_utils else 'VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT' |
| funcs += ' struct loader_device *dev;\n' |
| funcs += f' struct loader_icd_term *icd_term = loader_get_icd_and_device({ ext_cmd.params[0].name}, &dev);\n' |
| funcs += ' if (NULL == icd_term || NULL == dev) {\n' |
| 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' |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| funcs += f' { ext_cmd.params[1].type} {local_struct};\n' |
| funcs += f' memcpy(&{local_struct}, {debug_struct_name}, sizeof({ ext_cmd.params[1].type}));\n' |
| funcs += ' // If this is a physical device, we have to replace it with the proper one for the next call.\n' |
| funcs += f' if ({debug_struct_name}->objectType == {phys_dev_check}) {{\n' |
| funcs += f' struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t){debug_struct_name}->{member_name};\n' |
| funcs += f' {local_struct}.{member_name} = (uint64_t)(uintptr_t)phys_dev_term->phys_dev;\n' |
| 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' |
| funcs += f' }} else if ({debug_struct_name}->objectType == {surf_check}) {{\n' |
| funcs += ' if (NULL != dev && NULL != dev->loader_dispatch.core_dispatch.CreateSwapchainKHR) {\n' |
| funcs += f' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t){debug_struct_name}->{member_name};\n' |
| funcs += ' if (NULL != icd_term->surface_list.list && icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR)\n' |
| funcs += ' && icd_term->surface_list.list[icd_surface->surface_index]) {\n' |
| funcs += f' {local_struct}.{member_name} = (uint64_t)icd_term->surface_list.list[icd_surface->surface_index];\n' |
| funcs += ' }\n' |
| funcs += ' }\n' |
| funcs += ' // If this is an instance we have to replace it with the proper one for the next call.\n' |
| funcs += f' }} else if ({debug_struct_name}->objectType == {inst_check}) {{\n' |
| funcs += f' {local_struct}.{member_name} = (uint64_t)(uintptr_t)icd_term->instance;\n' |
| funcs += ' }\n' |
| funcs += ' // Exit early if the driver does not support the function - this can happen as a layer or the loader itself supports\n' |
| funcs += ' // debug utils but the driver does not.\n' |
| funcs += f' if (NULL == dev->loader_dispatch.extension_terminator_dispatch.{ext_cmd.name[2:]})\n return VK_SUCCESS;\n' |
| dispatch = 'dev->loader_dispatch.' |
| else: |
| funcs += f' struct loader_dev_dispatch_table *dispatch_table = loader_get_dev_dispatch({ext_cmd.params[0].name});\n' |
| funcs += ' if (NULL == dispatch_table) {\n' |
| 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' |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| funcs += ' // Only call down if the device supports the function\n' |
| funcs += f' if (NULL != dispatch_table->extension_terminator_dispatch.{base_name})\n ' |
| dispatch = 'dispatch_table->' |
| funcs += ' ' |
| if has_return_type: |
| funcs += 'return ' |
| funcs += f'{dispatch}extension_terminator_dispatch.{base_name}(' |
| count = 0 |
| for param in ext_cmd.params: |
| if count != 0: |
| funcs += ', ' |
| |
| if param.type == 'VkPhysicalDevice': |
| funcs += 'phys_dev_term->phys_dev' |
| elif param.type == 'VkSurfaceKHR': |
| funcs += 'icd_term->surface_list[icd_surface->surface_index]' |
| elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pNameInfo': |
| funcs += '&local_name_info' |
| elif ('DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name) and param.name == 'pTagInfo': |
| funcs += '&local_tag_info' |
| else: |
| funcs += param.name |
| count += 1 |
| |
| funcs += ');\n' |
| |
| else: |
| funcs += '#error("Unknown error path!");\n' |
| |
| funcs += '}\n\n' |
| else: |
| funcs += tramp_header |
| |
| funcs += ' const VkLayerDispatchTable *disp = loader_get_dispatch(' |
| funcs += ext_cmd.params[0].name |
| funcs += ');\n' |
| funcs += ' if (NULL == disp) {\n' |
| funcs += ' loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,\n' |
| funcs += ' "%s: Invalid %s "\n' % (ext_cmd.name, ext_cmd.params[0].name) |
| funcs += ' "[VUID-%s-%s-parameter]");\n' % (ext_cmd.name, ext_cmd.params[0].name) |
| funcs += ' abort(); /* Intentionally fail so user can correct issue. */\n' |
| funcs += ' }\n' |
| |
| if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: |
| funcs += ' if (disp->' + base_name + ' != NULL) {\n' |
| funcs += ' ' |
| funcs += return_prefix |
| funcs += 'disp->' |
| funcs += base_name |
| funcs += '(' |
| count = 0 |
| for param in ext_cmd.params: |
| if count != 0: |
| funcs += ', ' |
| funcs += param.name |
| count += 1 |
| funcs += ');\n' |
| if ext_cmd.ext_name in NULL_CHECK_EXT_NAMES: |
| if ext_cmd.return_type is not None: |
| funcs += ' } else {\n' |
| funcs += ' return VK_SUCCESS;\n' |
| funcs += ' }\n' |
| funcs += '}\n\n' |
| |
| if ext_cmd.protect is not None: |
| funcs += '#endif // %s\n' % ext_cmd.protect |
| |
| return funcs |
| |
| |
| # |
| # Create a function for the extension GPA call |
| def InstExtensionGPA(self): |
| entries = [] |
| gpa_func = '' |
| cur_extension_name = '' |
| |
| gpa_func += '// GPA helpers for extensions\n' |
| gpa_func += 'bool extension_instance_gpa(struct loader_instance *ptr_instance, const char *name, void **addr) {\n' |
| gpa_func += ' *addr = NULL;\n\n' |
| |
| for cur_cmd in self.ext_commands: |
| if (self.getAPIVersion(cur_cmd.ext_name) or |
| cur_cmd.ext_name in WSI_EXT_NAMES or |
| cur_cmd.ext_name in AVOID_EXT_NAMES or |
| cur_cmd.name in AVOID_CMD_NAMES ): |
| continue |
| |
| if cur_cmd.ext_name != cur_extension_name: |
| gpa_func += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| cur_extension_name = cur_cmd.ext_name |
| |
| if cur_cmd.protect is not None: |
| gpa_func += '#if defined(%s)\n' % cur_cmd.protect |
| |
| #base_name = cur_cmd.name[2:] |
| base_name = SHARED_ALIASES[cur_cmd.name] if cur_cmd.name in SHARED_ALIASES else cur_cmd.name[2:] |
| |
| if (cur_cmd.ext_type == 'instance'): |
| gpa_func += ' if (!strcmp("%s", name)) {\n' % (cur_cmd.name) |
| gpa_func += ' *addr = (ptr_instance->enabled_known_extensions.' |
| gpa_func += cur_cmd.ext_name[3:].lower() |
| gpa_func += ' == 1)\n' |
| gpa_func += ' ? (void *)%s\n' % (base_name) |
| gpa_func += ' : NULL;\n' |
| gpa_func += ' return true;\n' |
| gpa_func += ' }\n' |
| else: |
| gpa_func += ' if (!strcmp("%s", name)) {\n' % (cur_cmd.name) |
| gpa_func += ' *addr = (void *)%s;\n' % (base_name) |
| gpa_func += ' return true;\n' |
| gpa_func += ' }\n' |
| |
| if cur_cmd.protect is not None: |
| gpa_func += '#endif // %s\n' % cur_cmd.protect |
| |
| gpa_func += ' return false;\n' |
| gpa_func += '}\n\n' |
| |
| return gpa_func |
| |
| # |
| # Create the extension name init function |
| def InstantExtensionCreate(self): |
| entries = [] |
| entries = self.instanceExtensions |
| count = 0 |
| cur_extension_name = '' |
| |
| create_func = '' |
| create_func += '// A function that can be used to query enabled extensions during a vkCreateInstance call\n' |
| create_func += 'void extensions_create_instance(struct loader_instance *ptr_instance, const VkInstanceCreateInfo *pCreateInfo) {\n' |
| create_func += ' for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {\n' |
| for ext in entries: |
| if (self.getAPIVersion(ext.name) or ext.name in WSI_EXT_NAMES or |
| ext.name in AVOID_EXT_NAMES or ext.name in AVOID_CMD_NAMES or |
| ext.type == 'device' or ext.num_commands == 0): |
| continue |
| |
| if ext.name != cur_extension_name: |
| create_func += '\n // ---- %s extension commands\n' % ext.name |
| cur_extension_name = ext.name |
| |
| if ext.protect is not None: |
| create_func += '#if defined(%s)\n' % ext.protect |
| if count == 0: |
| create_func += ' if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], ' |
| else: |
| create_func += ' } else if (0 == strcmp(pCreateInfo->ppEnabledExtensionNames[i], ' |
| |
| create_func += ext.define + ')) {\n' |
| create_func += ' ptr_instance->enabled_known_extensions.' |
| create_func += ext.name[3:].lower() |
| create_func += ' = 1;\n' |
| |
| if ext.protect is not None: |
| create_func += '#endif // %s\n' % ext.protect |
| count += 1 |
| |
| create_func += ' }\n' |
| create_func += ' }\n' |
| create_func += '}\n\n' |
| return create_func |
| |
| # |
| # Create code to initialize a dispatch table from the appropriate list of |
| # extension entrypoints and return it as a string |
| def DeviceExtensionGetTerminator(self): |
| term_func = '' |
| |
| term_func += '// Some device commands still need a terminator because the loader needs to unwrap something about them.\n' |
| term_func += '// In many cases, the item needing unwrapping is a VkPhysicalDevice or VkSurfaceKHR object. But there may be other items\n' |
| term_func += '// in the future.\n' |
| term_func += 'PFN_vkVoidFunction get_extension_device_proc_terminator(struct loader_device *dev, const char *name, bool* found_name) {\n' |
| term_func += ''' *found_name = false; |
| if (!name || name[0] != 'v' || name[1] != 'k') { |
| return NULL; |
| } |
| name += 2; |
| ''' |
| last_protect = None |
| last_ext = None |
| for ext_cmd in self.ext_commands: |
| version = self.getAPIVersion(ext_cmd.ext_name) |
| if ext_cmd.name in DEVICE_CMDS_NEED_TERM: |
| if version: |
| term_func += f' // ---- Core {version.name} commands\n' |
| else: |
| last_protect = ext_cmd.protect |
| if ext_cmd.protect is not None: |
| term_func += f'#if defined({ext_cmd.protect})\n' |
| if (last_ext != ext_cmd.ext_name): |
| term_func += f' // ---- {ext_cmd.ext_name} extension commands\n' |
| last_ext = ext_cmd.ext_name |
| |
| term_func += f' if (!strcmp(name, "{ext_cmd.name[2:]}")) {{\n' |
| term_func += f' *found_name = true;\n' |
| if ext_cmd.require: |
| dep_expr = self.ConvertDependencyExpression(ext_cmd.require, lambda ext_name: f'dev->driver_extensions.{ext_name[3:].lower()}_enabled') |
| term_func += f' return (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled && ({dep_expr})) ?\n' |
| else: |
| term_func += f' return dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled ?\n' |
| term_func += f' (PFN_vkVoidFunction)terminator_{(ext_cmd.name[2:])} : NULL;\n' |
| term_func += f' }}\n' |
| |
| if last_protect is not None: |
| term_func += '#endif // %s\n' % last_protect |
| |
| term_func += ' return NULL;\n' |
| term_func += '}\n\n' |
| |
| return term_func |
| |
| # |
| # Create a dispatch table solely for device functions which have custom terminators |
| def OutputDeviceFunctionTerminatorDispatchTable(self): |
| term_func = '' |
| term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n' |
| term_func += '// device function. This is used in the terminators themselves.\n' |
| term_func += 'struct loader_device_terminator_dispatch {\n' |
| |
| last_protect = None |
| last_ext = None |
| for ext_cmd in self.ext_commands: |
| version = self.getAPIVersion(ext_cmd.ext_name) |
| if ext_cmd.name in DEVICE_CMDS_NEED_TERM: |
| if version: |
| term_func += f' // ---- Core {version.name} commands\n' |
| else: |
| last_protect = ext_cmd.protect |
| if ext_cmd.protect is not None: |
| term_func += f'#if defined({ext_cmd.protect})\n' |
| if (last_ext != ext_cmd.ext_name): |
| term_func += f' // ---- {ext_cmd.ext_name} extension commands\n' |
| last_ext = ext_cmd.ext_name |
| |
| term_func += f' PFN_{ext_cmd.name} {ext_cmd.name[2:]};\n' |
| |
| if last_protect is not None: |
| term_func += '#endif // %s\n' % last_protect |
| |
| term_func += '};\n\n' |
| |
| return term_func |
| |
| def OutputDeviceFunctionTrampolinePrototypes(self): |
| tramp_protos = '' |
| tramp_protos += '// These are prototypes for functions that need their trampoline called in all circumstances.\n' |
| tramp_protos += '// They are used in loader_lookup_device_dispatch_table but are defined afterwards.\n' |
| last_protect = None |
| last_ext = None |
| for ext_cmd in self.ext_commands: |
| version = self.getAPIVersion(ext_cmd.ext_name) |
| if ext_cmd.name in DEVICE_CMDS_MUST_USE_TRAMP: |
| if version: |
| tramp_protos += f' // ---- Core {version.name} commands\n' |
| else: |
| last_protect = ext_cmd.protect |
| if ext_cmd.protect is not None: |
| tramp_protos += f'#if defined({ext_cmd.protect})\n' |
| if (last_ext != ext_cmd.ext_name): |
| tramp_protos += f' // ---- {ext_cmd.ext_name} extension commands\n' |
| last_ext = ext_cmd.ext_name |
| |
| tramp_protos += f'{ext_cmd.cdecl.replace("VKAPI_CALL vk", "VKAPI_CALL ")}\n' |
| |
| if last_protect is not None: |
| tramp_protos += '#endif // %s\n' % last_protect |
| tramp_protos += '\n' |
| return tramp_protos |
| |
| # |
| # Create code to initialize a dispatch table from the appropriate list of |
| # extension entrypoints and return it as a string |
| def InitDeviceFunctionTerminatorDispatchTable(self): |
| term_func = '' |
| |
| term_func += '// Functions that required a terminator need to have a separate dispatch table which contains their corresponding\n' |
| term_func += '// device function. This is used in the terminators themselves.\n' |
| term_func += 'void init_extension_device_proc_terminator_dispatch(struct loader_device *dev) {\n' |
| term_func += ' struct loader_device_terminator_dispatch* dispatch = &dev->loader_dispatch.extension_terminator_dispatch;\n' |
| term_func += ' PFN_vkGetDeviceProcAddr gpda = (PFN_vkGetDeviceProcAddr)dev->phys_dev_term->this_icd_term->dispatch.GetDeviceProcAddr;\n' |
| last_protect = None |
| last_ext = None |
| for ext_cmd in self.ext_commands: |
| version = self.getAPIVersion(ext_cmd.ext_name) |
| if ext_cmd.name in DEVICE_CMDS_NEED_TERM: |
| if version: |
| term_func += f' // ---- Core {version.name} commands\n' |
| else: |
| last_protect = ext_cmd.protect |
| if ext_cmd.protect is not None: |
| term_func += f'#if defined({ext_cmd.protect})\n' |
| if (last_ext != ext_cmd.ext_name): |
| term_func += f' // ---- {ext_cmd.ext_name} extension commands\n' |
| last_ext = ext_cmd.ext_name |
| |
| |
| if ext_cmd.require: |
| dep_expr = self.ConvertDependencyExpression(ext_cmd.require, lambda ext_name: f'dev->driver_extensions.{ext_name[3:].lower()}_enabled') |
| term_func += f' if (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled && ({dep_expr}))\n' |
| term_func += f' dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n' |
| else: |
| term_func += f' if (dev->driver_extensions.{ext_cmd.ext_name[3:].lower()}_enabled)\n' |
| term_func += f' dispatch->{ext_cmd.name[2:]} = (PFN_{(ext_cmd.name)})gpda(dev->icd_device, "{(ext_cmd.name)}");\n' |
| |
| if last_protect is not None: |
| term_func += '#endif // %s\n' % last_protect |
| |
| term_func += '}\n\n' |
| |
| return term_func |
| |
| # |
| # Create code to initialize a dispatch table from the appropriate list of |
| # core and extension entrypoints and return it as a string |
| def InitInstLoaderExtensionDispatchTable(self): |
| commands = [] |
| table = '' |
| cur_extension_name = '' |
| |
| table += '// This table contains the loader\'s instance dispatch table, which contains\n' |
| table += '// default functions if no instance layers are activated. This contains\n' |
| table += '// pointers to "terminator functions".\n' |
| table += 'const VkLayerInstanceDispatchTable instance_disp = {\n' |
| |
| for x in range(0, 2): |
| if x == 0: |
| commands = self.core_commands |
| else: |
| commands = self.ext_commands |
| |
| for cur_cmd in commands: |
| version = self.getAPIVersion(cur_cmd.ext_name) |
| if cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice': |
| if cur_cmd.ext_name != cur_extension_name: |
| if version: |
| table += '\n // ---- Core %s commands\n' % version.name |
| else: |
| table += '\n // ---- %s extension commands\n' % cur_cmd.ext_name |
| cur_extension_name = cur_cmd.ext_name |
| |
| # Remove 'vk' from proto name |
| base_name = cur_cmd.name[2:] |
| aliased_name = SHARED_ALIASES[cur_cmd.name][2:] if cur_cmd.name in SHARED_ALIASES else base_name |
| |
| if (base_name == 'CreateInstance' or base_name == 'CreateDevice' or |
| base_name == 'EnumerateInstanceExtensionProperties' or |
| base_name == 'EnumerateInstanceLayerProperties' or |
| base_name == 'EnumerateInstanceVersion'): |
| continue |
| |
| if cur_cmd.protect is not None: |
| table += '#if defined(%s)\n' % cur_cmd.protect |
| |
| if base_name == 'GetInstanceProcAddr': |
| table += ' .%s = %s,\n' % (base_name, cur_cmd.name) |
| else: |
| table += ' .%s = terminator_%s,\n' % (base_name, aliased_name) |
| |
| if cur_cmd.protect is not None: |
| table += '#endif // %s\n' % cur_cmd.protect |
| table += '};\n\n' |
| |
| return table |
| |
| # |
| # Create the extension name whitelist array |
| def OutputInstantExtensionWhitelistArray(self): |
| extensions = self.instanceExtensions |
| |
| table = '' |
| table += '// A null-terminated list of all of the instance extensions supported by the loader.\n' |
| table += '// If an instance extension name is not in this list, but it is exported by one or more of the\n' |
| table += '// ICDs detected by the loader, then the extension name not in the list will be filtered out\n' |
| table += '// before passing the list of extensions to the application.\n' |
| table += 'const char *const LOADER_INSTANCE_EXTENSIONS[] = {\n' |
| for ext in extensions: |
| if ext.type == 'device' or self.getAPIVersion(ext.name): |
| continue |
| |
| if ext.protect is not None: |
| table += '#if defined(%s)\n' % ext.protect |
| table += ' ' |
| table += ext.define + ',\n' |
| |
| if ext.protect is not None: |
| table += '#endif // %s\n' % ext.protect |
| table += ' NULL };\n' |
| return table |
| |