blob: 9fae8faa1051c8dc5823d52cf50f4c108efa4f14 [file] [log] [blame]
#!/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