mirror of
https://github.com/openharmony/third_party_vulkan-loader.git
synced 2026-07-20 20:15:56 -04:00
035140a542
Validate the Vulkan dispatchable handles (VkInstance, VkPhysicalDevice, etc) for any trampoline functions the loader uses to query the dispatch table from. This is so we can at least report errors before something bad happens. Also, add tests to the test framework to catch this case. Right now they simply check to make sure we aborted, but they don't know why the loader aborted. Eventually, we need to come back and check the loader messages and make sure it aborted for the reasons we want. Fix a generator warning in dispatch_table_helper_generator.py where a compare was the wrong type. Fixes GH Issue #64.
261 lines
12 KiB
Python
261 lines
12 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-2021 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 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 *
|
|
|
|
return_type_table = {"VkResult": "VK_SUCCESS",
|
|
"uint32_t": "0",
|
|
"uint64_t": "0L",
|
|
"VkDeviceAddress": "0L",
|
|
"VkDeviceSize": "0L"}
|
|
|
|
#
|
|
# DispatchTableHelperOutputGeneratorOptions - subclass of GeneratorOptions.
|
|
class DispatchTableHelperOutputGeneratorOptions(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,
|
|
apicall = '',
|
|
apientry = '',
|
|
apientryp = '',
|
|
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.genFuncPointers = genFuncPointers
|
|
self.prefixText = None
|
|
self.apicall = apicall
|
|
self.apientry = apientry
|
|
self.apientryp = apientryp
|
|
self.alignFuncParam = alignFuncParam
|
|
#
|
|
# DispatchTableHelperOutputGenerator - subclass of OutputGenerator.
|
|
# Generates dispatch table helper header files for LVL
|
|
class DispatchTableHelperOutputGenerator(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.instance_dispatch_list = [] # List of entries for instance dispatch list
|
|
self.device_dispatch_list = [] # List of entries for device dispatch list
|
|
self.dev_ext_stub_list = [] # List of stub functions for device extension functions
|
|
self.device_extension_list = [] # List of device extension functions
|
|
self.extension_type = ''
|
|
#
|
|
# Called once at the beginning of each run
|
|
def beginFile(self, genOpts):
|
|
OutputGenerator.beginFile(self, genOpts)
|
|
write("#pragma once", file=self.outFile)
|
|
# 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 dispatch_helper_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: Courtney Goeltzenleuchter <courtney@LunarG.com>\n'
|
|
copyright += ' * Author: Jon Ashburn <jon@lunarg.com>\n'
|
|
copyright += ' * Author: Mark Lobodzinski <mark@lunarg.com>\n'
|
|
copyright += ' */\n'
|
|
|
|
preamble = ''
|
|
preamble += '#include <vulkan/vulkan.h>\n'
|
|
preamble += '#include <vulkan/vk_layer.h>\n'
|
|
preamble += '#include <string.h>\n'
|
|
preamble += '#include "vk_layer_dispatch_table.h"\n'
|
|
|
|
write(copyright, file=self.outFile)
|
|
write(preamble, file=self.outFile)
|
|
#
|
|
# Write generate and write dispatch tables to output file
|
|
def endFile(self):
|
|
device_table = ''
|
|
instance_table = ''
|
|
|
|
device_table += self.OutputDispatchTableHelper('device')
|
|
instance_table += self.OutputDispatchTableHelper('instance')
|
|
|
|
for stub in self.dev_ext_stub_list:
|
|
write(stub, file=self.outFile)
|
|
write("\n\n", file=self.outFile)
|
|
write(device_table, file=self.outFile);
|
|
write("\n", file=self.outFile)
|
|
write(instance_table, file=self.outFile);
|
|
|
|
# Finish processing in superclass
|
|
OutputGenerator.endFile(self)
|
|
#
|
|
# Processing at beginning of each feature or extension
|
|
def beginFeature(self, interface, emit):
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
self.featureExtraProtect = GetFeatureProtect(interface)
|
|
self.extension_type = interface.get('type')
|
|
|
|
#
|
|
# Process commands, adding to appropriate dispatch tables
|
|
def genCmd(self, cmdinfo, name, alias):
|
|
OutputGenerator.genCmd(self, cmdinfo, name, alias)
|
|
|
|
avoid_entries = ['vkCreateInstance',
|
|
'vkCreateDevice']
|
|
# Get first param type
|
|
params = cmdinfo.elem.findall('param')
|
|
info = self.getTypeNameTuple(params[0])
|
|
|
|
if name not in avoid_entries:
|
|
self.AddCommandToDispatchList(name, info[0], self.featureExtraProtect, cmdinfo)
|
|
|
|
#
|
|
# Determine if this API should be ignored or added to the instance or device dispatch table
|
|
def AddCommandToDispatchList(self, name, handle_type, protect, cmdinfo):
|
|
handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
|
|
if handle is None:
|
|
return
|
|
if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr':
|
|
self.device_dispatch_list.append((name, self.featureExtraProtect))
|
|
if "VK_VERSION" not in self.featureName and self.extension_type == 'device':
|
|
self.device_extension_list.append(name)
|
|
# Build up stub function
|
|
decl = self.makeCDecls(cmdinfo.elem)[1]
|
|
return_type = cmdinfo.elem.find('proto/type').text
|
|
return_statement = "" # default type is void, so no return type
|
|
try:
|
|
return_statement = 'return ' + return_type_table[return_type] + ';'
|
|
except KeyError:
|
|
if return_type != "void":
|
|
raise AssertionError("return_type_table does not contain all possible types. Add an entry for `" + return_type + "`.")
|
|
decl = decl.split('*PFN_vk')[1]
|
|
decl = decl.replace(')(', '(')
|
|
decl = 'static VKAPI_ATTR ' + return_type + ' VKAPI_CALL Stub' + decl
|
|
func_body = ' { ' + return_statement + ' };'
|
|
decl = decl.replace (';', func_body)
|
|
if self.featureExtraProtect is not None:
|
|
self.dev_ext_stub_list.append('#ifdef %s' % self.featureExtraProtect)
|
|
self.dev_ext_stub_list.append(decl)
|
|
if self.featureExtraProtect is not None:
|
|
self.dev_ext_stub_list.append('#endif // %s' % self.featureExtraProtect)
|
|
else:
|
|
self.instance_dispatch_list.append((name, self.featureExtraProtect))
|
|
return
|
|
#
|
|
# 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)
|
|
#
|
|
# Create a dispatch table from the appropriate list and return it as a string
|
|
def OutputDispatchTableHelper(self, table_type):
|
|
entries = []
|
|
table = ''
|
|
if table_type == 'device':
|
|
entries = self.device_dispatch_list
|
|
table += 'static inline void layer_init_device_dispatch_table(VkDevice device, VkLayerDispatchTable *table, PFN_vkGetDeviceProcAddr gpa) {\n'
|
|
table += ' memset(table, 0, sizeof(*table));\n'
|
|
table += ' table->magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;\n\n'
|
|
table += ' // Device function pointers\n'
|
|
else:
|
|
entries = self.instance_dispatch_list
|
|
table += 'static inline void layer_init_instance_dispatch_table(VkInstance instance, VkLayerInstanceDispatchTable *table, PFN_vkGetInstanceProcAddr gpa) {\n'
|
|
table += ' memset(table, 0, sizeof(*table));\n\n'
|
|
table += ' // Instance function pointers\n'
|
|
|
|
for item in entries:
|
|
# Remove 'vk' from proto name
|
|
base_name = item[0][2:]
|
|
|
|
if item[1] is not None:
|
|
table += '#ifdef %s\n' % item[1]
|
|
|
|
# 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 (table_type == 'device' and base_name == 'GetDeviceProcAddr'):
|
|
table += ' table->GetDeviceProcAddr = gpa;\n'
|
|
elif (table_type != 'device' and base_name == 'GetInstanceProcAddr'):
|
|
table += ' table->GetInstanceProcAddr = gpa;\n'
|
|
else:
|
|
table += ' table->%s = (PFN_%s) gpa(%s, "%s");\n' % (base_name, item[0], table_type, item[0])
|
|
if item[0] in self.device_extension_list:
|
|
stub_check = ' if (table->%s == nullptr) { table->%s = (PFN_%s)Stub%s; }\n' % (base_name, base_name, item[0], base_name)
|
|
table += stub_check
|
|
if item[1] is not None:
|
|
table += '#endif // %s\n' % item[1]
|
|
|
|
table += '}'
|
|
return table
|