[Mesa-dev] [PATCH] radv: port to using updated anv entrypoint/extension generator.

Dave Airlie airlied at gmail.com
Tue Oct 17 05:36:53 UTC 2017


From: Dave Airlie <airlied at redhat.com>

This ports radv to using the anv entrypoint/extension generator
code.

No differences on enabled extensions list in vulkaninfo.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 src/amd/vulkan/.gitignore              |   1 +
 src/amd/vulkan/Makefile.am             |   9 +-
 src/amd/vulkan/Makefile.sources        |   3 +-
 src/amd/vulkan/radv_device.c           | 271 +----------------------
 src/amd/vulkan/radv_entrypoints_gen.py | 381 ++++++++++++++++-----------------
 src/amd/vulkan/radv_extensions.py      | 278 ++++++++++++++++++++++++
 src/amd/vulkan/radv_private.h          |  11 +-
 7 files changed, 480 insertions(+), 474 deletions(-)
 create mode 100644 src/amd/vulkan/radv_extensions.py

diff --git a/src/amd/vulkan/.gitignore b/src/amd/vulkan/.gitignore
index 2a42d7f..7c02e42 100644
--- a/src/amd/vulkan/.gitignore
+++ b/src/amd/vulkan/.gitignore
@@ -1,6 +1,7 @@
 # Generated source files
 /radv_entrypoints.c
 /radv_entrypoints.h
+/radv_extensions.c
 /radv_timestamp.h
 /dev_icd.json
 /vk_format_table.c
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index 19ec3f4..7364e54 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -107,12 +107,19 @@ libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES)
 
 vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
 
-radv_entrypoints.c: radv_entrypoints_gen.py $(vulkan_api_xml)
+radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml)
 	$(MKDIR_GEN)
 	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py \
 		--xml $(vulkan_api_xml) --outdir $(builddir)
 radv_entrypoints.h: radv_entrypoints.c
 
+radv_extensions.c: radv_extensions.py \
+		 $(vulkan_api_xml)
+	$(MKDIR_GEN)
+	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_extensions.py \
+		--xml $(vulkan_api_xml) \
+		--out $@
+
 vk_format_table.c: vk_format_table.py \
 		   vk_format_parse.py \
                    vk_format_layout.csv
diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources
index fbdb797..c9d172c 100644
--- a/src/amd/vulkan/Makefile.sources
+++ b/src/amd/vulkan/Makefile.sources
@@ -77,5 +77,6 @@ VULKAN_WSI_X11_FILES := \
 
 VULKAN_GENERATED_FILES := \
 	radv_entrypoints.c \
-	radv_entrypoints.h
+	radv_entrypoints.h \
+	radv_extensions.c
 
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index b2aef2a..b9cd676 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -76,198 +76,6 @@ radv_get_device_uuid(struct radeon_info *info, void *uuid)
 	ac_compute_device_uuid(info, uuid, VK_UUID_SIZE);
 }
 
-static const VkExtensionProperties instance_extensions[] = {
-	{
-		.extensionName = VK_KHR_SURFACE_EXTENSION_NAME,
-		.specVersion = 25,
-	},
-#ifdef VK_USE_PLATFORM_XCB_KHR
-	{
-		.extensionName = VK_KHR_XCB_SURFACE_EXTENSION_NAME,
-		.specVersion = 6,
-	},
-#endif
-#ifdef VK_USE_PLATFORM_XLIB_KHR
-	{
-		.extensionName = VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
-		.specVersion = 6,
-	},
-#endif
-#ifdef VK_USE_PLATFORM_WAYLAND_KHR
-	{
-		.extensionName = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
-		.specVersion = 6,
-	},
-#endif
-	{
-		.extensionName = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-};
-
-static const VkExtensionProperties common_device_extensions[] = {
-	{
-		.extensionName = VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_MAINTENANCE1_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_SWAPCHAIN_EXTENSION_NAME,
-		.specVersion = 68,
-	},
-	{
-		.extensionName = VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_MAINTENANCE2_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-};
-
-static const VkExtensionProperties rasterization_order_extension[] ={
-	{
-		.extensionName = VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-};
-
-static const VkExtensionProperties ext_sema_device_extensions[] = {
-	{
-		.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-	{
-		.extensionName = VK_KHX_MULTIVIEW_EXTENSION_NAME,
-		.specVersion = 1,
-	},
-};
-
-static VkResult
-radv_extensions_register(struct radv_instance *instance,
-			struct radv_extensions *extensions,
-			const VkExtensionProperties *new_ext,
-			uint32_t num_ext)
-{
-	size_t new_size;
-	VkExtensionProperties *new_ptr;
-
-	assert(new_ext && num_ext > 0);
-
-	if (!new_ext)
-		return VK_ERROR_INITIALIZATION_FAILED;
-
-	new_size = (extensions->num_ext + num_ext) * sizeof(VkExtensionProperties);
-	new_ptr = vk_realloc(&instance->alloc, extensions->ext_array,
-				new_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-
-	/* Old array continues to be valid, update nothing */
-	if (!new_ptr)
-		return VK_ERROR_OUT_OF_HOST_MEMORY;
-
-	memcpy(&new_ptr[extensions->num_ext], new_ext,
-		num_ext * sizeof(VkExtensionProperties));
-	extensions->ext_array = new_ptr;
-	extensions->num_ext += num_ext;
-
-	return VK_SUCCESS;
-}
-
-static void
-radv_extensions_finish(struct radv_instance *instance,
-			struct radv_extensions *extensions)
-{
-	assert(extensions);
-
-	if (!extensions)
-		radv_loge("Attemted to free invalid extension struct\n");
-
-	if (extensions->ext_array)
-		vk_free(&instance->alloc, extensions->ext_array);
-}
-
-static bool
-is_extension_enabled(const VkExtensionProperties *extensions,
-			size_t num_ext,
-			const char *name)
-{
-	assert(extensions && name);
-
-	for (uint32_t i = 0; i < num_ext; i++) {
-		if (strcmp(name, extensions[i].extensionName) == 0)
-			return true;
-	}
-
-	return false;
-}
-
 static const char *
 get_chip_name(enum radeon_family family)
 {
@@ -364,31 +172,6 @@ radv_physical_device_init(struct radv_physical_device *device,
 	disk_cache_format_hex_id(buf, device->cache_uuid, VK_UUID_SIZE);
 	device->disk_cache = disk_cache_create("radv", buf, shader_env_flags);
 
-	result = radv_extensions_register(instance,
-					&device->extensions,
-					common_device_extensions,
-					ARRAY_SIZE(common_device_extensions));
-	if (result != VK_SUCCESS)
-		goto fail;
-
-	if (device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2) {
-		result = radv_extensions_register(instance,
-						&device->extensions,
-						rasterization_order_extension,
-						ARRAY_SIZE(rasterization_order_extension));
-		if (result != VK_SUCCESS)
-			goto fail;
-	}
-
-	if (device->rad_info.has_syncobj) {
-		result = radv_extensions_register(instance,
-						  &device->extensions,
-						  ext_sema_device_extensions,
-						  ARRAY_SIZE(ext_sema_device_extensions));
-		if (result != VK_SUCCESS)
-			goto fail;
-	}
-
 	fprintf(stderr, "WARNING: radv is not a conformant vulkan implementation, testing use only.\n");
 	device->name = get_chip_name(device->rad_info.family);
 
@@ -416,7 +199,6 @@ fail:
 static void
 radv_physical_device_finish(struct radv_physical_device *device)
 {
-	radv_extensions_finish(device->instance, &device->extensions);
 	radv_finish_wsi(device);
 	device->ws->destroy(device->ws);
 	disk_cache_destroy(device->disk_cache);
@@ -515,9 +297,8 @@ VkResult radv_CreateInstance(
 	}
 
 	for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-		if (!is_extension_enabled(instance_extensions,
-					ARRAY_SIZE(instance_extensions),
-					pCreateInfo->ppEnabledExtensionNames[i]))
+	        const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
+		if (!radv_instance_extension_supported(ext_name))
 			return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT);
 	}
 
@@ -851,7 +632,7 @@ void radv_GetPhysicalDeviceProperties(
 	};
 
 	*pProperties = (VkPhysicalDeviceProperties) {
-		.apiVersion = VK_MAKE_VERSION(1, 0, 42),
+		.apiVersion = radv_physical_device_api_version(pdevice),
 		.driverVersion = vk_get_driver_version(),
 		.vendorID = ATI_VENDOR_ID,
 		.deviceID = pdevice->rad_info.pci_id,
@@ -1141,9 +922,8 @@ VkResult radv_CreateDevice(
 	struct radv_device *device;
 
 	for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
-		if (!is_extension_enabled(physical_device->extensions.ext_array,
-					physical_device->extensions.num_ext,
-					pCreateInfo->ppEnabledExtensionNames[i]))
+		const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
+		if (!radv_physical_device_extension_supported(physical_device, ext_name))
 			return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT);
 	}
 
@@ -1331,47 +1111,6 @@ void radv_DestroyDevice(
 	vk_free(&device->alloc, device);
 }
 
-VkResult radv_EnumerateInstanceExtensionProperties(
-	const char*                                 pLayerName,
-	uint32_t*                                   pPropertyCount,
-	VkExtensionProperties*                      pProperties)
-{
-	if (pProperties == NULL) {
-		*pPropertyCount = ARRAY_SIZE(instance_extensions);
-		return VK_SUCCESS;
-	}
-
-	*pPropertyCount = MIN2(*pPropertyCount, ARRAY_SIZE(instance_extensions));
-	typed_memcpy(pProperties, instance_extensions, *pPropertyCount);
-
-	if (*pPropertyCount < ARRAY_SIZE(instance_extensions))
-		return VK_INCOMPLETE;
-
-	return VK_SUCCESS;
-}
-
-VkResult radv_EnumerateDeviceExtensionProperties(
-	VkPhysicalDevice                            physicalDevice,
-	const char*                                 pLayerName,
-	uint32_t*                                   pPropertyCount,
-	VkExtensionProperties*                      pProperties)
-{
-	RADV_FROM_HANDLE(radv_physical_device, pdevice, physicalDevice);
-
-	if (pProperties == NULL) {
-		*pPropertyCount = pdevice->extensions.num_ext;
-		return VK_SUCCESS;
-	}
-
-	*pPropertyCount = MIN2(*pPropertyCount, pdevice->extensions.num_ext);
-	typed_memcpy(pProperties, pdevice->extensions.ext_array, *pPropertyCount);
-
-	if (*pPropertyCount < pdevice->extensions.num_ext)
-		return VK_INCOMPLETE;
-
-	return VK_SUCCESS;
-}
-
 VkResult radv_EnumerateInstanceLayerProperties(
 	uint32_t*                                   pPropertyCount,
 	VkLayerProperties*                          pProperties)
diff --git a/src/amd/vulkan/radv_entrypoints_gen.py b/src/amd/vulkan/radv_entrypoints_gen.py
index 713a98f..f8f99d0 100644
--- a/src/amd/vulkan/radv_entrypoints_gen.py
+++ b/src/amd/vulkan/radv_entrypoints_gen.py
@@ -25,214 +25,184 @@
 import argparse
 import functools
 import os
-import textwrap
 import xml.etree.cElementTree as et
 
 from mako.template import Template
 
-MAX_API_VERSION = 1.0
-
-SUPPORTED_EXTENSIONS = [
-    'VK_AMD_draw_indirect_count',
-    'VK_NV_dedicated_allocation',
-    'VK_KHR_descriptor_update_template',
-    'VK_KHR_get_physical_device_properties2',
-    'VK_KHR_incremental_present',
-    'VK_KHR_maintenance1',
-    'VK_KHR_push_descriptor',
-    'VK_KHR_sampler_mirror_clamp_to_edge',
-    'VK_KHR_shader_draw_parameters',
-    'VK_KHR_surface',
-    'VK_KHR_swapchain',
-    'VK_KHR_wayland_surface',
-    'VK_KHR_xcb_surface',
-    'VK_KHR_xlib_surface',
-    'VK_KHR_get_memory_requirements2',
-    'VK_KHR_dedicated_allocation',
-    'VK_KHR_external_memory_capabilities',
-    'VK_KHR_external_memory',
-    'VK_KHR_external_memory_fd',
-    'VK_KHR_storage_buffer_storage_class',
-    'VK_KHR_variable_pointers',
-    'VK_KHR_external_semaphore_capabilities',
-    'VK_KHR_external_semaphore',
-    'VK_KHR_external_semaphore_fd',
-    'VK_KHR_bind_memory2',
-    'VK_KHR_maintenance2',
-]
+from radv_extensions import *
 
 # We generate a static hash table for entry point lookup
 # (vkGetProcAddress). We use a linear congruential generator for our hash
 # function and a power-of-two size table. The prime numbers are determined
 # experimentally.
 
-TEMPLATE_H = Template(textwrap.dedent("""\
-    /* This file generated from ${filename}, don't edit directly. */
-
-    struct radv_dispatch_table {
-       union {
-          void *entrypoints[${len(entrypoints)}];
-          struct {
-          % for _, name, _, _, _, guard in entrypoints:
-            % if guard is not None:
-    #ifdef ${guard}
-              PFN_vk${name} ${name};
-    #else
-              void *${name};
-    # endif
-            % else:
-              PFN_vk${name} ${name};
-            % endif
-          % endfor
-          };
-       };
-    };
-
-    % for type_, name, args, num, h, guard in entrypoints:
-      % if guard is not None:
-    #ifdef ${guard}
-      % endif
-      ${type_} radv_${name}(${args});
-      % if guard is not None:
-    #endif // ${guard}
-      % endif
-    % endfor
-    """), output_encoding='utf-8')
-
-TEMPLATE_C = Template(textwrap.dedent(u"""\
-    /*
-     * Copyright © 2015 Intel Corporation
-     *
-     * Permission is hereby granted, free of charge, to any person obtaining a
-     * copy of this software and associated documentation files (the "Software"),
-     * to deal in the Software without restriction, including without limitation
-     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
-     * and/or sell copies of the Software, and to permit persons to whom the
-     * Software is furnished to do so, subject to the following conditions:
-     *
-     * The above copyright notice and this permission notice (including the next
-     * paragraph) shall be included in all copies or substantial portions of the
-     * Software.
-     *
-     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-     * IN THE SOFTWARE.
-     */
-
-    /* This file generated from ${filename}, don't edit directly. */
-
-    #include "radv_private.h"
-
-    struct radv_entrypoint {
-       uint32_t name;
-       uint32_t hash;
-    };
-
-    /* We use a big string constant to avoid lots of reloctions from the entry
-     * point table to lots of little strings. The entries in the entry point table
-     * store the index into this big string.
-     */
-
-    static const char strings[] =
-    % for _, name, _, _, _, _ in entrypoints:
-        "vk${name}\\0"
-    % endfor
-    ;
-
-    static const struct radv_entrypoint entrypoints[] = {
-    % for _, _, _, num, h, _ in entrypoints:
-        { ${offsets[num]}, ${'{:0=#8x}'.format(h)} },
-    % endfor
-    };
-
-    /* Weak aliases for all potential implementations. These will resolve to
-     * NULL if they're not defined, which lets the resolve_entrypoint() function
-     * either pick the correct entry point.
-     */
-
-    % for layer in ['radv']:
-      % for type_, name, args, _, _, guard in entrypoints:
-        % if guard is not None:
-    #ifdef ${guard}
-        % endif
-        ${type_} ${layer}_${name}(${args}) __attribute__ ((weak));
-        % if guard is not None:
-    #endif // ${guard}
-        % endif
-      % endfor
+TEMPLATE_H = Template("""\
+/* This file generated from ${filename}, don't edit directly. */
 
-      const struct radv_dispatch_table ${layer}_layer = {
-      % for _, name, args, _, _, guard in entrypoints:
-        % if guard is not None:
-    #ifdef ${guard}
-        % endif
-        .${name} = ${layer}_${name},
+struct radv_dispatch_table {
+   union {
+      void *entrypoints[${len(entrypoints)}];
+      struct {
+      % for _, name, _, _, _, guard in entrypoints:
         % if guard is not None:
-    #endif // ${guard}
-        % endif
-      % endfor
-      };
-    % endfor
-
-    static void * __attribute__ ((noinline))
-    radv_resolve_entrypoint(uint32_t index)
-    {
-       return radv_layer.entrypoints[index];
-    }
-
-    /* Hash table stats:
-     * size ${hash_size} entries
-     * collisions entries:
-    % for i in xrange(10):
-     *     ${i}${'+' if i == 9 else ''}     ${collisions[i]}
-    % endfor
-     */
-
-    #define none ${'{:#x}'.format(none)}
-    static const uint16_t map[] = {
-    % for i in xrange(0, hash_size, 8):
-      % for j in xrange(i, i + 8):
-        ## This is 6 because the 0x is counted in the length
-        % if mapping[j] & 0xffff == 0xffff:
-          none,
+#ifdef ${guard}
+          PFN_vk${name} ${name};
+#else
+          void *${name};
+# endif
         % else:
-          ${'{:0=#6x}'.format(mapping[j] & 0xffff)},
+          PFN_vk${name} ${name};
         % endif
       % endfor
-    % endfor
-    };
-
-    void *
-    radv_lookup_entrypoint(const char *name)
-    {
-       static const uint32_t prime_factor = ${prime_factor};
-       static const uint32_t prime_step = ${prime_step};
-       const struct radv_entrypoint *e;
-       uint32_t hash, h, i;
-       const char *p;
-
-       hash = 0;
-       for (p = name; *p; p++)
-          hash = hash * prime_factor + *p;
-
-       h = hash;
-       do {
-          i = map[h & ${hash_mask}];
-          if (i == none)
-             return NULL;
-          e = &entrypoints[i];
-          h += prime_step;
-       } while (e->hash != hash);
-
-       if (strcmp(name, strings + e->name) != 0)
-          return NULL;
-
-       return radv_resolve_entrypoint(i);
-    }"""), output_encoding='utf-8')
+      };
+   };
+};
+
+% for type_, name, args, num, h, guard in entrypoints:
+  % if guard is not None:
+#ifdef ${guard}
+  % endif
+  ${type_} radv_${name}(${args});
+  % if guard is not None:
+#endif // ${guard}
+  % endif
+% endfor
+""", output_encoding='utf-8')
+
+TEMPLATE_C = Template(u"""\
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This file generated from ${filename}, don't edit directly. */
+
+#include "radv_private.h"
+
+struct radv_entrypoint {
+   uint32_t name;
+   uint32_t hash;
+};
+
+/* We use a big string constant to avoid lots of reloctions from the entry
+ * point table to lots of little strings. The entries in the entry point table
+ * store the index into this big string.
+ */
+
+static const char strings[] =
+% for _, name, _, _, _, _ in entrypoints:
+    "vk${name}\\0"
+% endfor
+;
+
+static const struct radv_entrypoint entrypoints[] = {
+% for _, name, _, num, h, _ in entrypoints:
+    [${num}] = { ${offsets[num]}, ${'{:0=#8x}'.format(h)} }, /* vk${name} */
+% endfor
+};
+
+/* Weak aliases for all potential implementations. These will resolve to
+ * NULL if they're not defined, which lets the resolve_entrypoint() function
+ * either pick the correct entry point.
+ */
+
+% for layer in ['radv']:
+  % for type_, name, args, _, _, guard in entrypoints:
+    % if guard is not None:
+#ifdef ${guard}
+    % endif
+    ${type_} ${layer}_${name}(${args}) __attribute__ ((weak));
+    % if guard is not None:
+#endif // ${guard}
+    % endif
+  % endfor
+
+  const struct radv_dispatch_table ${layer}_layer = {
+  % for _, name, args, _, _, guard in entrypoints:
+    % if guard is not None:
+#ifdef ${guard}
+    % endif
+    .${name} = ${layer}_${name},
+    % if guard is not None:
+#endif // ${guard}
+    % endif
+  % endfor
+  };
+% endfor
+
+static void * __attribute__ ((noinline))
+radv_resolve_entrypoint(uint32_t index)
+{
+   return radv_layer.entrypoints[index];
+}
+
+/* Hash table stats:
+ * size ${hash_size} entries
+ * collisions entries:
+% for i in xrange(10):
+ *     ${i}${'+' if i == 9 else ''}     ${collisions[i]}
+% endfor
+ */
+
+#define none ${'{:#x}'.format(none)}
+static const uint16_t map[] = {
+% for i in xrange(0, hash_size, 8):
+  % for j in xrange(i, i + 8):
+    ## This is 6 because the 0x is counted in the length
+    % if mapping[j] & 0xffff == 0xffff:
+      none,
+    % else:
+      ${'{:0=#6x}'.format(mapping[j] & 0xffff)},
+    % endif
+  % endfor
+% endfor
+};
+
+void *
+radv_lookup_entrypoint(const char *name)
+{
+   static const uint32_t prime_factor = ${prime_factor};
+   static const uint32_t prime_step = ${prime_step};
+   const struct radv_entrypoint *e;
+   uint32_t hash, h, i;
+   const char *p;
+
+   hash = 0;
+   for (p = name; *p; p++)
+      hash = hash * prime_factor + *p;
+
+   h = hash;
+   do {
+      i = map[h & ${hash_mask}];
+      if (i == none)
+         return NULL;
+      e = &entrypoints[i];
+      h += prime_step;
+   } while (e->hash != hash);
+
+   if (strcmp(name, strings + e->name) != 0)
+      return NULL;
+
+   return radv_resolve_entrypoint(i);
+}""", output_encoding='utf-8')
 
 NONE = 0xffff
 HASH_SIZE = 256
@@ -249,28 +219,29 @@ def cal_hash(name):
         lambda h, c: (h * PRIME_FACTOR + ord(c)) & U32_MASK, name, 0)
 
 
-def get_entrypoints(doc, entrypoints_to_defines):
+def get_entrypoints(doc, entrypoints_to_defines, start_index):
     """Extract the entry points from the registry."""
     entrypoints = []
 
     enabled_commands = set()
     for feature in doc.findall('./feature'):
         assert feature.attrib['api'] == 'vulkan'
-        if float(feature.attrib['number']) > MAX_API_VERSION:
+        if VkVersion(feature.attrib['number']) > MAX_API_VERSION:
             continue
 
         for command in feature.findall('./require/command'):
             enabled_commands.add(command.attrib['name'])
 
+    supported = set(ext.name for ext in EXTENSIONS)
     for extension in doc.findall('.extensions/extension'):
-        if extension.attrib['name'] not in SUPPORTED_EXTENSIONS:
+        if extension.attrib['name'] not in supported:
             continue
 
         assert extension.attrib['supported'] == 'vulkan'
         for command in extension.findall('./require/command'):
             enabled_commands.add(command.attrib['name'])
 
-    index = 0
+    index = start_index
     for command in doc.findall('./commands/command'):
         type = command.find('./proto/type').text
         fullname = command.find('./proto/name').text
@@ -339,12 +310,22 @@ def main():
     parser = argparse.ArgumentParser()
     parser.add_argument('--outdir', help='Where to write the files.',
                         required=True)
-    parser.add_argument('--xml', help='Vulkan API XML file.', required=True)
+    parser.add_argument('--xml',
+                        help='Vulkan API XML file.',
+                        required=True,
+                        action='append',
+                        dest='xml_files')
     args = parser.parse_args()
 
-    doc = et.parse(args.xml)
-    entrypoints = get_entrypoints(doc, get_entrypoints_defines(doc))
+    entrypoints = []
+
+    for filename in args.xml_files:
+        doc = et.parse(filename)
+        entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc),
+                                       start_index=len(entrypoints))
 
+    # For outputting entrypoints.h we generate a radv_EntryPoint() prototype
+    # per entry point.
     with open(os.path.join(args.outdir, 'radv_entrypoints.h'), 'wb') as f:
         f.write(TEMPLATE_H.render(entrypoints=entrypoints,
                                   filename=os.path.basename(__file__)))
diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
new file mode 100644
index 0000000..0c916c3
--- /dev/null
+++ b/src/amd/vulkan/radv_extensions.py
@@ -0,0 +1,278 @@
+COPYRIGHT = """\
+/*
+ * Copyright 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+"""
+
+import argparse
+import copy
+import re
+import xml.etree.cElementTree as et
+
+from mako.template import Template
+
+MAX_API_VERSION = '1.0.57'
+
+class Extension:
+    def __init__(self, name, ext_version, enable):
+        self.name = name
+        self.ext_version = int(ext_version)
+        if enable is True:
+            self.enable = 'true';
+        elif enable is False:
+            self.enable = 'false';
+        else:
+            self.enable = enable;
+
+# On Android, we disable all surface and swapchain extensions. Android's Vulkan
+# loader implements VK_KHR_surface and VK_KHR_swapchain, and applications
+# cannot access the driver's implementation. Moreoever, if the driver exposes
+# the those extension strings, then tests dEQP-VK.api.info.instance.extensions
+# and dEQP-VK.api.info.device fail due to the duplicated strings.
+EXTENSIONS = [
+    Extension('VK_KHR_bind_memory2',                      1, True),
+    Extension('VK_KHR_dedicated_allocation',              1, True),
+    Extension('VK_KHR_descriptor_update_template',        1, True),
+    Extension('VK_KHR_external_memory',                   1, True),
+    Extension('VK_KHR_external_memory_capabilities',      1, True),
+    Extension('VK_KHR_external_memory_fd',                1, True),
+    Extension('VK_KHR_external_semaphore',                1, 'device->rad_info.has_syncobj'),
+    Extension('VK_KHR_external_semaphore_capabilities',   1, True),
+    Extension('VK_KHR_external_semaphore_fd',             1, 'device->rad_info.has_syncobj'),
+    Extension('VK_KHR_get_memory_requirements2',          1, True),
+    Extension('VK_KHR_get_physical_device_properties2',   1, True),
+    Extension('VK_KHR_image_format_list',                 1, True),
+    Extension('VK_KHR_incremental_present',               1, True),
+    Extension('VK_KHR_maintenance1',                      1, True),
+    Extension('VK_KHR_maintenance2',                      1, True),
+    Extension('VK_KHR_push_descriptor',                   1, True),
+    Extension('VK_KHR_relaxed_block_layout',              1, True),
+    Extension('VK_KHR_sampler_mirror_clamp_to_edge',      1, True),
+    Extension('VK_KHR_shader_draw_parameters',            1, True),
+    Extension('VK_KHR_storage_buffer_storage_class',      1, True),
+    Extension('VK_KHR_surface',                          25, 'RADV_HAS_SURFACE'),
+    Extension('VK_KHR_swapchain',                        68, 'RADV_HAS_SURFACE'),
+    Extension('VK_KHR_variable_pointers',                 1, True),
+    Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
+    Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
+    Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
+    Extension('VK_KHX_multiview',                         1, 'device->rad_info.has_syncobj'),
+    Extension('VK_EXT_debug_report',                      8, True),
+    Extension('VK_AMD_draw_indirect_count',               1, True),
+    Extension('VK_AMD_rasterization_order',               1, 'device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2'),
+]
+
+class VkVersion:
+    def __init__(self, string):
+        split = string.split('.')
+        self.major = int(split[0])
+        self.minor = int(split[1])
+        if len(split) > 2:
+            assert len(split) == 3
+            self.patch = int(split[2])
+        else:
+            self.patch = None
+
+        # Sanity check.  The range bits are required by the definition of the
+        # VK_MAKE_VERSION macro
+        assert self.major < 1024 and self.minor < 1024
+        assert self.patch is None or self.patch < 4096
+        assert(str(self) == string)
+
+    def __str__(self):
+        ver_list = [str(self.major), str(self.minor)]
+        if self.patch is not None:
+            ver_list.append(str(self.patch))
+        return '.'.join(ver_list)
+
+    def c_vk_version(self):
+        ver_list = [str(self.major), str(self.minor), str(self.patch)]
+        return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')'
+
+    def __int_ver(self):
+        # This is just an expansion of VK_VERSION
+        patch = self.patch if self.patch is not None else 0
+        return (self.major << 22) | (self.minor << 12) | patch
+
+    def __cmp__(self, other):
+        # If only one of them has a patch version, "ignore" it by making
+        # other's patch version match self.
+        if (self.patch is None) != (other.patch is None):
+            other = copy.copy(other)
+            other.patch = self.patch
+
+        return self.__int_ver().__cmp__(other.__int_ver())
+
+MAX_API_VERSION = VkVersion(MAX_API_VERSION)
+
+def _init_exts_from_xml(xml):
+    """ Walk the Vulkan XML and fill out extra extension information. """
+
+    xml = et.parse(xml)
+
+    ext_name_map = {}
+    for ext in EXTENSIONS:
+        ext_name_map[ext.name] = ext
+
+    for ext_elem in xml.findall('.extensions/extension'):
+        ext_name = ext_elem.attrib['name']
+        if ext_name not in ext_name_map:
+            continue
+
+        # Workaround for VK_ANDROID_native_buffer. Its <extension> element in
+        # vk.xml lists it as supported="disabled" and provides only a stub
+        # definition.  Its <extension> element in Mesa's custom
+        # vk_android_native_buffer.xml, though, lists it as
+        # supported='android-vendor' and fully defines the extension. We want
+        # to skip the <extension> element in vk.xml.
+        if ext_elem.attrib['supported'] == 'disabled':
+            assert ext_name == 'VK_ANDROID_native_buffer'
+            continue
+
+        ext = ext_name_map[ext_name]
+        ext.type = ext_elem.attrib['type']
+
+_TEMPLATE = Template(COPYRIGHT + """
+#include "radv_private.h"
+
+#include "vk_util.h"
+
+/* Convert the VK_USE_PLATFORM_* defines to booleans */
+%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
+#ifdef VK_USE_PLATFORM_${platform}_KHR
+#   undef VK_USE_PLATFORM_${platform}_KHR
+#   define VK_USE_PLATFORM_${platform}_KHR true
+#else
+#   define VK_USE_PLATFORM_${platform}_KHR false
+#endif
+%endfor
+
+/* And ANDROID too */
+#ifdef ANDROID
+#   undef ANDROID
+#   define ANDROID true
+#else
+#   define ANDROID false
+#endif
+
+#define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
+                         VK_USE_PLATFORM_XCB_KHR || \\
+                         VK_USE_PLATFORM_XLIB_KHR)
+
+bool
+radv_instance_extension_supported(const char *name)
+{
+%for ext in instance_extensions:
+    if (strcmp(name, "${ext.name}") == 0)
+        return ${ext.enable};
+%endfor
+    return false;
+}
+
+VkResult radv_EnumerateInstanceExtensionProperties(
+    const char*                                 pLayerName,
+    uint32_t*                                   pPropertyCount,
+    VkExtensionProperties*                      pProperties)
+{
+    VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
+
+%for ext in instance_extensions:
+    if (${ext.enable}) {
+        vk_outarray_append(&out, prop) {
+            *prop = (VkExtensionProperties) {
+                .extensionName = "${ext.name}",
+                .specVersion = ${ext.ext_version},
+            };
+        }
+    }
+%endfor
+
+    return vk_outarray_status(&out);
+}
+
+uint32_t
+radv_physical_device_api_version(struct radv_physical_device *dev)
+{
+    return ${MAX_API_VERSION.c_vk_version()};
+}
+
+bool
+radv_physical_device_extension_supported(struct radv_physical_device *device,
+                                        const char *name)
+{
+%for ext in device_extensions:
+    if (strcmp(name, "${ext.name}") == 0)
+        return ${ext.enable};
+%endfor
+    return false;
+}
+
+VkResult radv_EnumerateDeviceExtensionProperties(
+    VkPhysicalDevice                            physicalDevice,
+    const char*                                 pLayerName,
+    uint32_t*                                   pPropertyCount,
+    VkExtensionProperties*                      pProperties)
+{
+    RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
+    VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
+    (void)device;
+
+%for ext in device_extensions:
+    if (${ext.enable}) {
+        vk_outarray_append(&out, prop) {
+            *prop = (VkExtensionProperties) {
+                .extensionName = "${ext.name}",
+                .specVersion = ${ext.ext_version},
+            };
+        }
+    }
+%endfor
+
+    return vk_outarray_status(&out);
+}
+""")
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--out', help='Output C file.', required=True)
+    parser.add_argument('--xml',
+                        help='Vulkan API XML file.',
+                        required=True,
+                        action='append',
+                        dest='xml_files')
+    args = parser.parse_args()
+
+    for filename in args.xml_files:
+        _init_exts_from_xml(filename)
+
+    for ext in EXTENSIONS:
+        assert ext.type == 'instance' or ext.type == 'device'
+
+    template_env = {
+        'MAX_API_VERSION': MAX_API_VERSION,
+        'instance_extensions': [e for e in EXTENSIONS if e.type == 'instance'],
+        'device_extensions': [e for e in EXTENSIONS if e.type == 'device'],
+    }
+
+    with open(args.out, 'w') as f:
+        f.write(_TEMPLATE.render(**template_env))
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index 70c5c70..ad9ea5e 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -253,11 +253,6 @@ void radv_loge_v(const char *format, va_list va);
 
 void *radv_lookup_entrypoint(const char *name);
 
-struct radv_extensions {
-	VkExtensionProperties       *ext_array;
-	uint32_t                    num_ext;
-};
-
 struct radv_physical_device {
 	VK_LOADER_DATA                              _loader_data;
 
@@ -273,7 +268,6 @@ struct radv_physical_device {
 
 	int local_fd;
 	struct wsi_device                       wsi_device;
-	struct radv_extensions                      extensions;
 
 	bool has_rbplus; /* if RB+ register exist */
 	bool rbplus_allowed; /* if RB+ is allowed */
@@ -301,6 +295,11 @@ struct radv_instance {
 VkResult radv_init_wsi(struct radv_physical_device *physical_device);
 void radv_finish_wsi(struct radv_physical_device *physical_device);
 
+bool radv_instance_extension_supported(const char *name);
+uint32_t radv_physical_device_api_version(struct radv_physical_device *dev);
+bool radv_physical_device_extension_supported(struct radv_physical_device *dev,
+					      const char *name);
+
 struct cache_entry;
 
 struct radv_pipeline_cache {
-- 
2.9.5



More information about the mesa-dev mailing list