summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Ekstrand <jason.ekstrand@intel.com>2018-01-16 18:08:09 -0800
committerJason Ekstrand <jason.ekstrand@intel.com>2018-01-23 00:15:40 -0800
commit1f79d986afa5a92d7c7d85882714c7feeddc5d14 (patch)
tree013cbf83e968096832e9b06047679a7f5370a18e
parente3d27542aec33c7e0c2048a46a8a3cf71f09e907 (diff)
downloadmesa-1f79d986afa5a92d7c7d85882714c7feeddc5d14.tar.gz
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>
-rw-r--r--src/intel/vulkan/anv_device.c26
-rw-r--r--src/intel/vulkan/anv_entrypoints_gen.py49
-rw-r--r--src/intel/vulkan/anv_private.h5
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);