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->apiVersion = client_version;
|
||||||
instance->enabled_extensions = enabled_extensions;
|
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;
|
instance->physicalDeviceCount = -1;
|
||||||
|
|
||||||
result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
|
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++) {
|
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];
|
device->dispatch.entrypoints[i] = genX_table->entrypoints[i];
|
||||||
else
|
} else {
|
||||||
device->dispatch.entrypoints[i] = anv_dispatch_table.entrypoints[i];
|
device->dispatch.entrypoints[i] = anv_dispatch_table.entrypoints[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -164,6 +164,36 @@ static const struct anv_entrypoint entrypoints[] = {
|
|||||||
};
|
};
|
||||||
% endfor
|
% 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))
|
static void * __attribute__ ((noinline))
|
||||||
anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
|
anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index)
|
||||||
{
|
{
|
||||||
@@ -279,6 +309,9 @@ class Entrypoint(object):
|
|||||||
self.guard = guard
|
self.guard = guard
|
||||||
self.enabled = False
|
self.enabled = False
|
||||||
self.num = None
|
self.num = None
|
||||||
|
# Extensions which require this entrypoint
|
||||||
|
self.core_version = None
|
||||||
|
self.extension = None
|
||||||
|
|
||||||
def prefixed_name(self, prefix):
|
def prefixed_name(self, prefix):
|
||||||
assert self.name.startswith('vk')
|
assert self.name.startswith('vk')
|
||||||
@@ -303,24 +336,34 @@ def get_entrypoints(doc, entrypoints_to_defines, start_index):
|
|||||||
enabled_commands = set()
|
enabled_commands = set()
|
||||||
for feature in doc.findall('./feature'):
|
for feature in doc.findall('./feature'):
|
||||||
assert feature.attrib['api'] == 'vulkan'
|
assert feature.attrib['api'] == 'vulkan'
|
||||||
if VkVersion(feature.attrib['number']) > MAX_API_VERSION:
|
version = VkVersion(feature.attrib['number'])
|
||||||
|
if version > MAX_API_VERSION:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for command in feature.findall('./require/command'):
|
for command in feature.findall('./require/command'):
|
||||||
e = entrypoints[command.attrib['name']]
|
e = entrypoints[command.attrib['name']]
|
||||||
e.enabled = True
|
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'):
|
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
|
continue
|
||||||
|
|
||||||
if extension.attrib['supported'] != 'vulkan':
|
if extension.attrib['supported'] != 'vulkan':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
ext = supported_exts[ext_name]
|
||||||
|
ext.type = extension.attrib['type']
|
||||||
|
|
||||||
for command in extension.findall('./require/command'):
|
for command in extension.findall('./require/command'):
|
||||||
e = entrypoints[command.attrib['name']]
|
e = entrypoints[command.attrib['name']]
|
||||||
e.enabled = True
|
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]
|
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);
|
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,
|
void *anv_lookup_entrypoint(const struct gen_device_info *devinfo,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user