Files
third_party_vulkan-loader/scripts/loader_extension_generator.py
T
Mark Young 60386cb67f Fix loader phys dev termin for physical device extensions.
Fix some loader terminator functions for instance physical device
functions (that were pre-Vulkan 1.1).  At that point in the API, we
didn't treat VkPhysicalDevices like VkDevices.  Now, you must first
query the device for extension support for even VkPhysicalDevice calls.
Back then, the loader had to emulate the functionality.

Added tests to validate many of these functions.
2022-01-07 16:56:38 -07:00

1619 lines
84 KiB
Python

#!/usr/bin/python3 -i
#
# Copyright (c) 2015-2021 The Khronos Group Inc.
# Copyright (c) 2015-2021 Valve Corporation
# Copyright (c) 2015-2021 LunarG, Inc.
# Copyright (c) 2015-2017 Google Inc.
#
# 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']
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']
# 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']
#
# 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-2021 The Khronos Group Inc.\n'
copyright += ' * Copyright (c) 2015-2021 Valve Corporation\n'
copyright += ' * Copyright (c) 2015-2021 LunarG, Inc.\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 = ''
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 += 'typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);\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()
elif self.genOpts.filename == 'vk_loader_extensions.c':
file_data += self.OutputUtilitiesInSource()
file_data += self.OutputIcdDispatchTableInit()
file_data += self.OutputLoaderDispatchTables()
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()
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
#
# 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 'extension' in require_node.attrib:
require = require_node.attrib['extension']
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))
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 'VK_VERSION_' in extension_name:
self.core_commands.append(
self.CommandData(name=name, ext_name=extension_name,
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 'VK_VERSION_' in extension_name:
self.core_commands.append(
self.CommandData(name=name, ext_name=extension_name,
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)
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 *pName);\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_icd_term *icd_term, VkInstance inst,\n'
protos += ' const PFN_vkGetInstanceProcAddr fp_gipa);\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);\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, NULL);\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:
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 'VK_VERSION_' in cur_cmd.ext_name:
table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
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 += '#ifdef %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:
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 'VK_VERSION_' in cur_cmd.ext_name:
table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
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 += '#ifdef %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
#
# Create a dispatch table from the appropriate list and return it as a string
def OutputIcdDispatchTable(self):
commands = []
table = ''
cur_extension_name = ''
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:
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 or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and
(cur_cmd.name != 'vkGetInstanceProcAddr' and cur_cmd.name != 'vkEnumerateDeviceLayerProperties')):
if cur_cmd.ext_name != cur_extension_name:
if 'VK_VERSION_' in cur_cmd.ext_name:
table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
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 += '#ifdef %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_icd_term *icd_term, VkInstance inst,\n'
table += ' const PFN_vkGetInstanceProcAddr fp_gipa) {\n'
table += '\n'
table += '#define LOOKUP_GIPA(func, required) \\\n'
table += ' do { \\\n'
table += ' icd_term->dispatch.func = (PFN_vk##func)fp_gipa(inst, "vk" #func); \\\n'
table += ' if (!icd_term->dispatch.func && required) { \\\n'
table += ' loader_log((struct loader_instance *)inst, VULKAN_LOADER_WARN_BIT, 0, \\\n'
table += ' loader_platform_get_proc_address_error("vk" #func)); \\\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:
is_inst_handle_type = cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice'
if ((is_inst_handle_type or cur_cmd.name in DEVICE_CMDS_NEED_TERM) and (cur_cmd.name not in skip_gipa_commands)):
if cur_cmd.ext_name != cur_extension_name:
if 'VK_VERSION_' in cur_cmd.ext_name:
table += '\n // ---- Core %s\n' % cur_cmd.ext_name[11:]
required = cur_cmd.ext_name == 'VK_VERSION_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 += '#ifdef %s\n' % cur_cmd.protect
# 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 += ' LOOKUP_GIPA(%s, %s);\n' % (base_name, 'true' if required else 'false')
if cur_cmd.protect is not None:
table += '#endif // %s\n' % cur_cmd.protect
table += '\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 += 'union loader_instance_extension_enables {\n'
union += ' struct {\n'
for ext in extensions:
if ('VK_VERSION_' in ext.name or ext.name in WSI_EXT_NAMES or
ext.type == 'device' or ext.num_commands == 0):
continue
union += ' uint8_t %s : 1;\n' % ext.name[3:].lower()
union += ' };\n'
union += ' uint64_t padding[4];\n'
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:
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 += '#ifdef %s\n' % cur_cmd.protect
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 += ' table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n'
tables += ' for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) dev_table->ext_dispatch.dev_ext[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:
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 'VK_VERSION_' in cur_cmd.ext_name:
tables += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
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 += '#ifdef %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) {\n'
tables += ' if (!name || name[0] != \'v\' || name[1] != \'k\') return NULL;\n'
tables += '\n'
tables += ' name += 2;\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:
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 'VK_VERSION_' in cur_cmd.ext_name:
tables += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
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:]
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 += '#ifdef %s\n' % cur_cmd.protect
tables += ' if (!strcmp(name, "%s")) return (void *)table->%s;\n' % (base_name, base_name)
if cur_cmd.protect is not None:
tables += '#endif // %s\n' % cur_cmd.protect
tables += '\n'
if x == 1:
tables += ' *found_name = false;\n'
tables += ' return NULL;\n'
tables += '}\n\n'
return tables
#
# Create the appropriate trampoline (and possibly terminator) functinos
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
if ext_cmd.ext_name != cur_extension_name:
if 'VK_VERSION_' in ext_cmd.ext_name:
funcs += '\n// ---- Core %s trampoline/terminators\n\n' % ext_cmd.ext_name[11:]
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 += '#ifdef %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_surface->real_icd_surfaces[icd_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_surface->real_icd_surfaces[icd_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, VK_DEBUG_REPORT_ERROR_BIT_EXT, 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, VK_DEBUG_REPORT_ERROR_BIT_EXT, 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, VK_DEBUG_REPORT_ERROR_BIT_EXT, 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'
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'
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'
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'
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'
funcs += ' loader_log(icd_term->this_instance, 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_INITIALIZATION_FAILED;\n'
funcs += ' }\n'
if has_surface == 1:
funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(%s);\n' % (surface_var_name)
funcs += ' uint8_t icd_index = phys_dev_term->icd_index;\n'
funcs += ' if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)icd_surface->real_icd_surfaces[icd_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 has_surface == 1 and not (ext_cmd.handle_type == 'VkPhysicalDevice' or ext_cmd.handle_type == 'VkInstance'):
funcs += ' uint32_t icd_index = 0;\n'
funcs += ' struct loader_device *dev;\n'
funcs += ' struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);\n'
funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.%s) {\n' % base_name
funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)%s;\n' % (surface_var_name)
funcs += ' if (NULL != icd_surface->real_icd_surfaces && (VkSurfaceKHR)NULL != icd_surface->real_icd_surfaces[icd_index]) {\n'
funcs += ' %sicd_term->dispatch.%s(' % (return_prefix, base_name)
count = 0
for param in ext_cmd.params:
if count != 0:
funcs += ', '
if param.type == 'VkSurfaceKHR':
funcs += 'icd_surface->real_icd_surfaces[icd_index]'
else:
funcs += param.name
count += 1
funcs += ');\n'
if not has_return_type:
funcs += ' return;\n'
funcs += ' }\n'
funcs += ' %sicd_term->dispatch.%s(' % (return_prefix, base_name)
count = 0
for param in ext_cmd.params:
if count != 0:
funcs += ', '
funcs += param.name
count += 1
funcs += ');\n'
funcs += ' }\n'
if has_return_type:
funcs += ' return VK_SUCCESS;\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, VK_DEBUG_REPORT_ERROR_BIT_EXT, 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 'DebugMarkerSetObject' in ext_cmd.name or 'SetDebugUtilsObject' in ext_cmd.name or 'DebugUtilsLabel' in ext_cmd.name:
funcs += ' uint32_t icd_index = 0;\n'
funcs += ' struct loader_device *dev;\n'
funcs += ' struct loader_icd_term *icd_term = loader_get_icd_and_device(%s, &dev, &icd_index);\n' % (ext_cmd.params[0].name)
funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.'
funcs += base_name
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_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->object;\n'
funcs += ' local_name_info.object = (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 += ' } else if (pNameInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->object;\n'
funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
funcs += ' local_name_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
funcs += ' }\n'
funcs += ' }\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_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->object;\n'
funcs += ' local_tag_info.object = (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 += ' } else if (pTagInfo->objectType == VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT) {\n'
funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->object;\n'
funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
funcs += ' local_tag_info.object = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
funcs += ' }\n'
funcs += ' }\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_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pNameInfo->objectHandle;\n'
funcs += ' local_name_info.objectHandle = (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 += ' } else if (pNameInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pNameInfo->objectHandle;\n'
funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
funcs += ' local_name_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
funcs += ' }\n'
funcs += ' }\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_term *phys_dev_term = (struct loader_physical_device_term *)(uintptr_t)pTagInfo->objectHandle;\n'
funcs += ' local_tag_info.objectHandle = (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 += ' } else if (pTagInfo->objectType == VK_OBJECT_TYPE_SURFACE_KHR) {\n'
funcs += ' if (NULL != icd_term && NULL != icd_term->dispatch.CreateSwapchainKHR) {\n'
funcs += ' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pTagInfo->objectHandle;\n'
funcs += ' if (NULL != icd_surface->real_icd_surfaces) {\n'
funcs += ' local_tag_info.objectHandle = (uint64_t)icd_surface->real_icd_surfaces[icd_index];\n'
funcs += ' }\n'
funcs += ' }\n'
funcs += ' }\n'
funcs += ' '
if has_return_type:
funcs += 'return '
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'
elif param.type == 'VkSurfaceKHR':
funcs += 'icd_surface->real_icd_surfaces[icd_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'
if has_return_type:
funcs += ' } else {\n'
funcs += ' return VK_SUCCESS;\n'
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, VK_DEBUG_REPORT_ERROR_BIT_EXT, 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 += 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 ('VK_VERSION_' in 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 += '#ifdef %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 ('VK_VERSION_' in 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 += '#ifdef %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 = ''
cur_extension_name = ''
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 *pName) {\n'
term_func += ' PFN_vkVoidFunction addr = NULL;\n'
count = 0
is_extension = False
last_protect = None
for ext_cmd in self.ext_commands:
if ext_cmd.name in DEVICE_CMDS_NEED_TERM:
if ext_cmd.ext_name != cur_extension_name:
if count > 0:
count = 0;
term_func += ' }\n'
if is_extension:
term_func += ' }\n'
is_extension = False
if 'VK_VERSION_' in ext_cmd.ext_name:
term_func += '\n // ---- Core %s commands\n' % ext_cmd.ext_name[11:]
else:
last_protect = ext_cmd.protect
if ext_cmd.protect is not None:
term_func += '#ifdef %s\n' % ext_cmd.protect
term_func += '\n // ---- %s extension commands\n' % ext_cmd.ext_name
if ext_cmd.require:
term_func += ' if (dev->extensions.%s_enabled && dev->extensions.%s_enabled) {\n' % (ext_cmd.ext_name[3:].lower(), ext_cmd.require[3:].lower())
else:
term_func += ' if (dev->extensions.%s_enabled) {\n' % ext_cmd.ext_name[3:].lower()
is_extension = True
cur_extension_name = ext_cmd.ext_name
if count == 0:
term_func += ' if'
else:
term_func += ' } else if'
term_func += '(!strcmp(pName, "%s")) {\n' % (ext_cmd.name)
term_func += ' addr = (PFN_vkVoidFunction)terminator_%s;\n' % (ext_cmd.name[2:])
count += 1
if count > 0:
term_func += ' }\n'
if is_extension:
term_func += ' }\n'
if last_protect is not None:
term_func += '#endif // %s\n' % ext_cmd.protect
term_func += ' return addr;\n'
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:
if cur_cmd.handle_type == 'VkInstance' or cur_cmd.handle_type == 'VkPhysicalDevice':
if cur_cmd.ext_name != cur_extension_name:
if 'VK_VERSION_' in cur_cmd.ext_name:
table += '\n // ---- Core %s commands\n' % cur_cmd.ext_name[11:]
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 += '#ifdef %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 'VK_VERSION_' in ext.name:
continue
if ext.protect is not None:
table += '#ifdef %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