From 1f79d986afa5a92d7c7d85882714c7feeddc5d14 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 16 Jan 2018 18:08:09 -0800 Subject: [PATCH] anv: Only advertise enabled entrypoints MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- src/intel/vulkan/anv_device.c | 26 +++++++++++-- src/intel/vulkan/anv_entrypoints_gen.py | 49 +++++++++++++++++++++++-- src/intel/vulkan/anv_private.h | 5 +++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index e70ddf17998..8fcc73eaba1 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -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]; + } } } diff --git a/src/intel/vulkan/anv_entrypoints_gen.py b/src/intel/vulkan/anv_entrypoints_gen.py index ccbc2ffb5e5..32359b6b713 100644 --- a/src/intel/vulkan/anv_entrypoints_gen.py +++ b/src/intel/vulkan/anv_entrypoints_gen.py @@ -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] diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 45dbcfdcb63..a8b3820ffe1 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -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); -- 2.30.2