anv: Only advertise enabled entrypoints
The Vulkan spec annoyingly requires us to track what core version and what all extensions are enabled and only advertise those entrypoints. Any call to vkGet*ProcAddr for an entrypoint for an extension the client has not explicitly enabled is supposed to return NULL. Reviewed-by: Samuel Iglesias Gonsálvez <siglesias@igalia.com>
This commit is contained in:
@@ -574,7 +574,19 @@ VkResult anv_CreateInstance(
|
||||
|
||||
instance->apiVersion = client_version;
|
||||
instance->enabled_extensions = enabled_extensions;
|
||||
instance->dispatch = anv_dispatch_table;
|
||||
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(instance->dispatch.entrypoints); i++) {
|
||||
/* Vulkan requires that entrypoints for extensions which have not been
|
||||
* enabled must not be advertised.
|
||||
*/
|
||||
if (!anv_entrypoint_is_enabled(i, instance->apiVersion,
|
||||
&instance->enabled_extensions, NULL)) {
|
||||
instance->dispatch.entrypoints[i] = NULL;
|
||||
} else {
|
||||
instance->dispatch.entrypoints[i] = anv_dispatch_table.entrypoints[i];
|
||||
}
|
||||
}
|
||||
|
||||
instance->physicalDeviceCount = -1;
|
||||
|
||||
result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
|
||||
@@ -1289,10 +1301,18 @@ anv_device_init_dispatch(struct anv_device *device)
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(device->dispatch.entrypoints); i++) {
|
||||
if (genX_table->entrypoints[i])
|
||||
/* Vulkan requires that entrypoints for extensions which have not been
|
||||
* enabled must not be advertised.
|
||||
*/
|
||||
if (!anv_entrypoint_is_enabled(i, device->instance->apiVersion,
|
||||
&device->instance->enabled_extensions,
|
||||
&device->enabled_extensions)) {
|
||||
device->dispatch.entrypoints[i] = NULL;
|
||||
} else if (genX_table->entrypoints[i]) {
|
||||
device->dispatch.entrypoints[i] = genX_table->entrypoints[i];
|
||||
else
|
||||
} else {
|
||||
device->dispatch.entrypoints[i] = anv_dispatch_table.entrypoints[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -164,6 +164,36 @@ static const struct anv_entrypoint entrypoints[] = {
|
||||
};
|
||||
% endfor
|
||||
|
||||
/** Return true if the core version or extension in which the given entrypoint
|
||||
* is defined is enabled.
|
||||
*
|
||||
* If device is NULL, all device extensions are considered enabled.
|
||||
*/
|
||||
bool
|
||||
anv_entrypoint_is_enabled(int index, uint32_t core_version,
|
||||
const struct anv_instance_extension_table *instance,
|
||||
const struct anv_device_extension_table *device)
|
||||
{
|
||||
switch (index) {
|
||||
% for e in entrypoints:
|
||||
case ${e.num}:
|
||||
% if e.core_version:
|
||||
return ${e.core_version.c_vk_version()} <= core_version;
|
||||
% elif e.extension:
|
||||
% if e.extension.type == 'instance':
|
||||
return instance->${e.extension.name[3:]};
|
||||
% else:
|
||||
return !device || device->${e.extension.name[3:]};
|
||||
% endif
|
||||
% else:
|
||||
return true;
|
||||
% endif
|
||||
% endfor
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void * __attribute__ ((noinline))
|
||||
anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
|
||||
{
|
||||
@@ -279,6 +309,9 @@ class Entrypoint(object):
|
||||
self.guard = guard
|
||||
self.enabled = False
|
||||
self.num = None
|
||||
# Extensions which require this entrypoint
|
||||
self.core_version = None
|
||||
self.extension = None
|
||||
|
||||
def prefixed_name(self, prefix):
|
||||
assert self.name.startswith('vk')
|
||||
@@ -303,24 +336,34 @@ def get_entrypoints(doc, entrypoints_to_defines, start_index):
|
||||
enabled_commands = set()
|
||||
for feature in doc.findall('./feature'):
|
||||
assert feature.attrib['api'] == 'vulkan'
|
||||
if VkVersion(feature.attrib['number']) > MAX_API_VERSION:
|
||||
version = VkVersion(feature.attrib['number'])
|
||||
if version > MAX_API_VERSION:
|
||||
continue
|
||||
|
||||
for command in feature.findall('./require/command'):
|
||||
e = entrypoints[command.attrib['name']]
|
||||
e.enabled = True
|
||||
assert e.core_version is None
|
||||
e.core_version = version
|
||||
|
||||
supported = set(ext.name for ext in EXTENSIONS)
|
||||
supported_exts = dict((ext.name, ext) for ext in EXTENSIONS)
|
||||
for extension in doc.findall('.extensions/extension'):
|
||||
if extension.attrib['name'] not in supported:
|
||||
ext_name = extension.attrib['name']
|
||||
if ext_name not in supported_exts:
|
||||
continue
|
||||
|
||||
if extension.attrib['supported'] != 'vulkan':
|
||||
continue
|
||||
|
||||
ext = supported_exts[ext_name]
|
||||
ext.type = extension.attrib['type']
|
||||
|
||||
for command in extension.findall('./require/command'):
|
||||
e = entrypoints[command.attrib['name']]
|
||||
e.enabled = True
|
||||
assert e.core_version is None
|
||||
assert e.extension is None
|
||||
e.extension = ext
|
||||
|
||||
return [e for e in entrypoints.itervalues() if e.enabled]
|
||||
|
||||
|
@@ -2820,6 +2820,11 @@ struct anv_query_pool {
|
||||
|
||||
int anv_get_entrypoint_index(const char *name);
|
||||
|
||||
bool
|
||||
anv_entrypoint_is_enabled(int index, uint32_t core_version,
|
||||
const struct anv_instance_extension_table *instance,
|
||||
const struct anv_device_extension_table *device);
|
||||
|
||||
void *anv_lookup_entrypoint(const struct gen_device_info *devinfo,
|
||||
const char *name);
|
||||
|
||||
|
Reference in New Issue
Block a user