[Mesa-dev] [PATCH 4/4] radv: Integrate with common generators.

Bas Nieuwenhuizen bas at basnieuwenhuizen.nl
Tue Aug 7 23:14:34 UTC 2018


Replace some functions to use the anv idioms. However, I did not
introduce dispatch tables in the instance/device since that seemed
like overkill.
---
 src/amd/vulkan/Android.mk              |  16 +-
 src/amd/vulkan/Makefile.am             |  29 +-
 src/amd/vulkan/meson.build             |  91 +++--
 src/amd/vulkan/radv_device.c           |  56 ++-
 src/amd/vulkan/radv_entrypoints_gen.py | 462 +------------------------
 src/amd/vulkan/radv_extensions.py      | 236 +------------
 src/amd/vulkan/radv_extensions_gen.py  |  44 +++
 src/amd/vulkan/radv_icd.py             |   1 +
 src/amd/vulkan/radv_private.h          |   9 +-
 src/amd/vulkan/radv_wsi.c              |   6 +-
 10 files changed, 211 insertions(+), 739 deletions(-)
 create mode 100644 src/amd/vulkan/radv_extensions_gen.py

diff --git a/src/amd/vulkan/Android.mk b/src/amd/vulkan/Android.mk
index cee3744f40b..a6aae160e0b 100644
--- a/src/amd/vulkan/Android.mk
+++ b/src/amd/vulkan/Android.mk
@@ -83,24 +83,34 @@ LOCAL_GENERATED_SOURCES += $(intermediates)/vk_format_table.c
 
 RADV_ENTRYPOINTS_SCRIPT := $(MESA_TOP)/src/amd/vulkan/radv_entrypoints_gen.py
 RADV_EXTENSIONS_SCRIPT := $(MESA_TOP)/src/amd/vulkan/radv_extensions.py
+RADV_EXTENSIONS_GEN_SCRIPT := $(MESA_TOP)/src/amd/vulkan/radv_extensions_gen.py
 VK_FORMAT_TABLE_SCRIPT := $(MESA_TOP)/src/amd/vulkan/vk_format_table.py
 VK_FORMAT_PARSE_SCRIPT := $(MESA_TOP)/src/amd/vulkan/vk_format_parse.py
 
+vulkan_api_generators_py := \
+	$(MESA_TOP)/src/vulkan/util/vk_entrypoints_gen.py \
+	$(MESA_TOP)/src/vulkan/util/vk_extensions_gen.py \
+	$(MESA_TOP)/src/vulkan/util/vk_extensions.py
+
 vulkan_api_xml = $(MESA_TOP)/src/vulkan/registry/vk.xml
 vk_format_layout_csv = $(MESA_TOP)/src/amd/vulkan/vk_format_layout.csv
 
 $(intermediates)/radv_entrypoints.c: $(RADV_ENTRYPOINTS_SCRIPT) \
 					$(RADV_EXTENSIONS_SCRIPT) \
-					$(vulkan_api_xml)
+					$(vulkan_api_xml) \
+					$(vulkan_api_generators_py)
 	@mkdir -p $(dir $@)
+	PYTHONPATH=$(MESA_TOP)/src/vulkan/util \
 	$(MESA_PYTHON2) $(RADV_ENTRYPOINTS_SCRIPT) \
 		--xml $(vulkan_api_xml) \
 		--outdir $(dir $@)
 
 $(intermediates)/radv_entrypoints.h: $(intermediates)/radv_entrypoints.c
 
-$(intermediates)/radv_extensions.c: $(RADV_EXTENSIONS_SCRIPT) $(vulkan_api_xml)
-	@mkdir -p $(dir $@)
+$(intermediates)/radv_extensions.c: $(RADV_EXTENSIONS_GEN_SCRIPT) $(RADV_EXTENSIONS_SCRIPT) \
+					$(vulkan_api_xml) $(vulkan_api_generators_py)
+	@mkdir -p $(dir $@)\
+	PYTHONPATH=$(MESA_TOP)/src/vulkan/util \
 	$(MESA_PYTHON2) $(RADV_EXTENSIONS_SCRIPT) \
 		--xml $(vulkan_api_xml) \
 		--out-c $@ \
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index e7ccc58a28e..88e5b1de2fd 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -21,6 +21,11 @@
 
 include Makefile.sources
 
+vulkan_api_generators_py = \
+	$(top_srcdir)/src/vulkan/util/vk_entrypoints_gen.py \
+	$(top_srcdir)/src/vulkan/util/vk_extensions_gen.py \
+	$(top_srcdir)/src/vulkan/util/vk_extensions.py
+
 noinst_HEADERS = \
 	$(top_srcdir)/include/vulkan/vk_platform.h \
 	$(top_srcdir)/include/vulkan/vulkan_core.h \
@@ -138,17 +143,20 @@ libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES)
 
 vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
 
-radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml)
+radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml) \
+		    $(vulkan_api_generators_py)
 	$(MKDIR_GEN)
-	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py \
+	$(AM_V_GEN) PYTHONPATH=$(top_srcdir)/src/vulkan/util \
+	$(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)
+radv_extensions.c: radv_extensions_gen.py radv_extensions.py \
+		   $(vulkan_api_xml) $(vulkan_api_generators_py)
 	$(MKDIR_GEN)
-	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_extensions.py \
+	$(AM_V_GEN) PYTHONPATH=$(top_srcdir)/src/vulkan/util \
+	$(PYTHON2) $(srcdir)/radv_extensions_gen.py \
 		--xml $(vulkan_api_xml) \
 		--out-c radv_extensions.c \
 		--out-h radv_extensions.h
@@ -164,6 +172,7 @@ CLEANFILES = $(BUILT_SOURCES) dev_icd.json radeon_icd. at host_cpu@.json
 EXTRA_DIST = \
 	$(top_srcdir)/include/vulkan/vk_icd.h \
 	radv_entrypoints_gen.py \
+	radv_extensions_gen.py \
 	radv_extensions.py \
 	radv_icd.py \
 	vk_format_layout.csv \
@@ -189,12 +198,14 @@ icdconf_DATA = radeon_icd. at host_cpu@.json
 # The following is used for development purposes, by setting VK_ICD_FILENAMES.
 noinst_DATA = dev_icd.json
 
-dev_icd.json : radv_extensions.py radv_icd.py
-	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_icd.py \
+dev_icd.json : radv_extensions.py radv_icd.py  $(vulkan_api_generators_py)
+	$(AM_V_GEN) PYTHONPATH=$(top_srcdir)/src/vulkan/util \
+	$(PYTHON2) $(srcdir)/radv_icd.py \
 		--lib-path="${abs_top_builddir}/${LIB_DIR}" --out $@
 
-radeon_icd. at host_cpu@.json : radv_extensions.py radv_icd.py
-	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_icd.py \
+radeon_icd. at host_cpu@.json : radv_extensions.py radv_icd.py  $(vulkan_api_generators_py)
+	$(AM_V_GEN) PYTHONPATH=$(top_srcdir)/src/vulkan/util \
+	$(PYTHON2) $(srcdir)/radv_icd.py \
 		--lib-path="${libdir}" --out $@
 
 include $(top_srcdir)/install-lib-links.mk
diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
index 9f2842182e7..da5055b0693 100644
--- a/src/amd/vulkan/meson.build
+++ b/src/amd/vulkan/meson.build
@@ -18,25 +18,72 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
+radv_extensions_py = files('radv_extensions.py')
+
 radv_entrypoints = custom_target(
   'radv_entrypoints.[ch]',
   input : ['radv_entrypoints_gen.py', vk_api_xml],
   output : ['radv_entrypoints.h', 'radv_entrypoints.c'],
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--outdir',
-    meson.current_build_dir()
+    'env', 'PYTHONPATH=@0@'.format(join_paths(meson.source_root(), 'src/vulkan/util/')),
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@',
+    '--outdir', meson.current_build_dir(),
   ],
-  depend_files : files('radv_extensions.py'),
+  depend_files : [radv_extensions_py, vk_api_generators_py],
 )
 
 radv_extensions_c = custom_target(
   'radv_extensions.c',
-  input : ['radv_extensions.py', vk_api_xml],
-  output : ['radv_extensions.c', 'radv_extensions.h'],
+  input : ['radv_extensions_gen.py', vk_api_xml],
+  output : 'radv_extensions.c',
+  command : [
+   'env', 'PYTHONPATH=@0@'.format(join_paths(meson.source_root(), 'src/vulkan/util/')),
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@',
+    '--out-c', '@OUTPUT@',
+  ],
+  depend_files : [radv_extensions_py, vk_api_generators_py],
+)
+
+radv_extensions_h = custom_target(
+  'radv_extensions.h',
+  input : ['radv_extensions_gen.py', vk_api_xml],
+  output : 'radv_extensions.h',
+  command : [
+    'env', 'PYTHONPATH=@0@'.format(join_paths(meson.source_root(), 'src/vulkan/util/')),
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@',
+    '--out-h', '@OUTPUT@',
+  ],
+  depend_files : [radv_extensions_py, vk_api_generators_py],
+)
+
+radeon_icd = custom_target(
+  'radeon_icd',
+  input : 'radv_icd.py',
+  output : 'radeon_icd. at 0@.json'.format(host_machine.cpu()),
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--out-c', '@OUTPUT0@',
-    '--out-h', '@OUTPUT1@'
+    'env', 'PYTHONPATH=@0@'.format(join_paths(meson.source_root(), 'src/vulkan/util/')),
+    prog_python2, '@INPUT@',
+    '--lib-path', join_paths(get_option('prefix'), get_option('libdir')),
+    '--out', '@OUTPUT@',
   ],
+  depend_files : [radv_extensions_py, vk_api_generators_py],
+  build_by_default : true,
+  install_dir : with_vulkan_icd_dir,
+  install : true,
+)
+
+radv_dev_icd = custom_target(
+  'radv_dev_icd',
+  input : 'radv_icd.py',
+  output : 'dev_icd. at 0@.json'.format(host_machine.cpu()),
+  command : [
+    'env', 'PYTHONPATH=@0@'.format(join_paths(meson.source_root(), 'src/vulkan/util/')),
+    prog_python2, '@INPUT@', '--lib-path', meson.current_build_dir(),
+    '--out', '@OUTPUT@'
+  ],
+  depend_files : [radv_extensions_py, vk_api_generators_py],
+  build_by_default : true,
+  install : false,
 )
 
 vk_format_table_c = custom_target(
@@ -129,7 +176,7 @@ endif
 
 libvulkan_radeon = shared_library(
   'vulkan_radeon',
-  [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
+  [libradv_files, radv_entrypoints, radv_extensions_c, radv_extensions_h, vk_format_table_c],
   include_directories : [
     inc_common, inc_amd, inc_amd_common, inc_compiler, inc_vulkan_util,
     inc_vulkan_wsi,
@@ -147,31 +194,3 @@ libvulkan_radeon = shared_library(
   link_args : [ld_args_bsymbolic, ld_args_gc_sections],
   install : true,
 )
-
-radeon_icd = custom_target(
-  'radeon_icd',
-  input : 'radv_icd.py',
-  output : 'radeon_icd. at 0@.json'.format(host_machine.cpu()),
-  command : [
-    prog_python2, '@INPUT@',
-    '--lib-path', join_paths(get_option('prefix'), get_option('libdir')),
-    '--out', '@OUTPUT@',
-  ],
-  depend_files : files('radv_extensions.py'),
-  build_by_default : true,
-  install_dir : with_vulkan_icd_dir,
-  install : true,
-)
-
-radv_dev_icd = custom_target(
-  'radv_dev_icd',
-  input : 'radv_icd.py',
-  output : 'dev_icd.json',
-  command : [
-    prog_python2, '@INPUT@', '--lib-path', meson.current_build_dir(),
-    '--out', '@OUTPUT@'
-  ],
-  depend_files : files('radv_extensions.py'),
-  build_by_default : true,
-  install : false,
-)
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index 33f24b9d302..3c1de690ade 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -354,7 +354,7 @@ radv_physical_device_init(struct radv_physical_device *device,
 		(device->instance->perftest_flags & RADV_PERFTEST_DCC_MSAA);
 
 	radv_physical_device_init_mem_types(device);
-	radv_fill_device_extension_table(device, &device->supported_extensions);
+	radv_physical_device_get_supported_extensions(device, &device->supported_extensions);
 
 	result = radv_init_wsi(device);
 	if (result != VK_SUCCESS) {
@@ -540,7 +540,7 @@ VkResult radv_CreateInstance(
 		const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
 		int index = radv_get_instance_extension_index(ext_name);
 
-		if (index < 0 || !radv_supported_instance_extensions.extensions[index]) {
+		if (index < 0 || !radv_instance_extensions_supported.extensions[index]) {
 			vk_free2(&default_alloc, pAllocator, instance);
 			return vk_error(instance, VK_ERROR_EXTENSION_NOT_PRESENT);
 		}
@@ -2677,7 +2677,7 @@ VkResult radv_EnumerateInstanceExtensionProperties(
 	VK_OUTARRAY_MAKE(out, pProperties, pPropertyCount);
 
 	for (int i = 0; i < RADV_INSTANCE_EXTENSION_COUNT; i++) {
-		if (radv_supported_instance_extensions.extensions[i]) {
+		if (radv_instance_extensions_supported.extensions[i]) {
 			vk_outarray_append(&out, prop) {
 				*prop = radv_instance_extensions[i];
 			}
@@ -2713,10 +2713,35 @@ PFN_vkVoidFunction radv_GetInstanceProcAddr(
 {
 	RADV_FROM_HANDLE(radv_instance, instance, _instance);
 
-	return radv_lookup_entrypoint_checked(pName,
-	                                      instance ? instance->apiVersion : 0,
-	                                      instance ? &instance->enabled_extensions : NULL,
-	                                      NULL);
+	/* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly
+	 * when we have to return valid function pointers, NULL, or it's left
+	 * undefined.  See the table for exact details.
+	 */
+	if (pName == NULL)
+		return NULL;
+
+#define LOOKUP_RADV_ENTRYPOINT(entrypoint) \
+	if (strcmp(pName, "vk" #entrypoint) == 0) \
+		return (PFN_vkVoidFunction)radv_##entrypoint
+
+	LOOKUP_RADV_ENTRYPOINT(EnumerateInstanceExtensionProperties);
+	LOOKUP_RADV_ENTRYPOINT(EnumerateInstanceLayerProperties);
+	LOOKUP_RADV_ENTRYPOINT(EnumerateInstanceVersion);
+	LOOKUP_RADV_ENTRYPOINT(CreateInstance);
+
+#undef LOOKUP_RADV_ENTRYPOINT
+
+	if (instance == NULL)
+		return NULL;
+
+	int idx = radv_get_entrypoint_index(pName);
+	if (idx < 0)
+		return NULL;
+
+	if (!radv_entrypoint_is_enabled(idx, instance->apiVersion, &instance->enabled_extensions, NULL))
+		return NULL;
+
+	return radv_dispatch_table.entrypoints[idx];
 }
 
 /* The loader wants us to expose a second GetInstanceProcAddr function
@@ -2741,10 +2766,19 @@ PFN_vkVoidFunction radv_GetDeviceProcAddr(
 {
 	RADV_FROM_HANDLE(radv_device, device, _device);
 
-	return radv_lookup_entrypoint_checked(pName,
-	                                      device->instance->apiVersion,
-	                                      &device->instance->enabled_extensions,
-	                                      &device->enabled_extensions);
+	if (!device || !pName)
+		return NULL;
+
+	int idx = radv_get_entrypoint_index(pName);
+	if (idx < 0)
+		return NULL;
+
+	if (!radv_entrypoint_is_enabled(idx, device->instance->apiVersion,
+	                                &device->instance->enabled_extensions,
+	                                &device->enabled_extensions))
+		return NULL;
+
+	return radv_dispatch_table.entrypoints[idx];
 }
 
 bool radv_get_memory_fd(struct radv_device *device,
diff --git a/src/amd/vulkan/radv_entrypoints_gen.py b/src/amd/vulkan/radv_entrypoints_gen.py
index 377b544c2aa..46a12c50e75 100644
--- a/src/amd/vulkan/radv_entrypoints_gen.py
+++ b/src/amd/vulkan/radv_entrypoints_gen.py
@@ -23,454 +23,20 @@
 #
 
 import argparse
-import functools
-import math
 import os
-import xml.etree.cElementTree as et
 
-from collections import OrderedDict, namedtuple
-from mako.template import Template
-
-from radv_extensions import *
+from radv_extensions import MAX_API_VERSION, EXTENSIONS
+import vk_entrypoints_gen
 
 # 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.
 
-# We currently don't use layers in radv, but keeping the ability for anv
-# anyways, so we can use it for device groups.
 LAYERS = [
-    'radv'
+    'radv',
 ]
 
-TEMPLATE_H = Template("""\
-/* This file generated from ${filename}, don't edit directly. */
-
-struct radv_dispatch_table {
-   union {
-      void *entrypoints[${len(entrypoints)}];
-      struct {
-      % for e in entrypoints:
-        % if e.guard is not None:
-#ifdef ${e.guard}
-          PFN_${e.name} ${e.name};
-#else
-          void *${e.name};
-# endif
-        % else:
-          PFN_${e.name} ${e.name};
-        % endif
-      % endfor
-      };
-   };
-};
-
-% for e in entrypoints:
-  % if e.alias:
-    <% continue %>
-  % endif
-  % if e.guard is not None:
-#ifdef ${e.guard}
-  % endif
-  % for layer in LAYERS:
-  ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()});
-  % endfor
-  % if e.guard is not None:
-#endif // ${e.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 string_map_entry {
-   uint32_t name;
-   uint32_t hash;
-   uint32_t num;
-};
-
-/* We use a big string constant to avoid lots of relocations 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 s in strmap.sorted_strings:
-    "${s.string}\\0"
-% endfor
-;
-
-static const struct string_map_entry string_map_entries[] = {
-% for s in strmap.sorted_strings:
-    { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */
-% endfor
-};
-
-/* Hash table stats:
- * size ${len(strmap.sorted_strings)} entries
- * collisions entries:
-% for i in range(10):
- *     ${i}${'+' if i == 9 else ' '}     ${strmap.collisions[i]}
-% endfor
- */
-
-#define none 0xffff
-static const uint16_t string_map[${strmap.hash_size}] = {
-% for e in strmap.mapping:
-    ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },
-% 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 LAYERS:
-  % for e in entrypoints:
-    % if e.alias:
-      <% continue %>
-    % endif
-    % if e.guard is not None:
-#ifdef ${e.guard}
-    % endif
-    ${e.return_type} ${e.prefixed_name(layer)}(${e.decl_params()}) __attribute__ ((weak));
-    % if e.guard is not None:
-#endif // ${e.guard}
-    % endif
-  % endfor
-
-  const struct radv_dispatch_table ${layer}_layer = {
-  % for e in entrypoints:
-    % if e.guard is not None:
-#ifdef ${e.guard}
-    % endif
-    .${e.name} = ${e.prefixed_name(layer)},
-    % if e.guard is not None:
-#endif // ${e.guard}
-    % endif
-  % endfor
-  };
-% endfor
-
-static void * __attribute__ ((noinline))
-radv_resolve_entrypoint(uint32_t index)
-{
-   return radv_layer.entrypoints[index];
-}
-
-/** Return true if the core version or extension in which the given entrypoint
- * is defined is enabled.
- *
- * If instance is NULL, we only allow the 3 commands explicitly allowed by the vk
- * spec.
- *
- * If device is NULL, all device extensions are considered enabled.
- */
-static bool
-radv_entrypoint_is_enabled(int index, uint32_t core_version,
-                          const struct radv_instance_extension_table *instance,
-                          const struct radv_device_extension_table *device)
-{
-   switch (index) {
-% for e in entrypoints:
-   case ${e.num}:
-   % if not e.device_command:
-      if (device) return false;
-   % endif
-   % if e.name == 'vkCreateInstance' or e.name == 'vkEnumerateInstanceExtensionProperties' or e.name == 'vkEnumerateInstanceLayerProperties' or e.name == 'vkEnumerateInstanceVersion':
-      return !device;
-   % elif e.core_version:
-      return instance && ${e.core_version.c_vk_version()} <= core_version;
-   % elif e.extensions:
-      % for ext in e.extensions:
-         % if ext.type == 'instance':
-      if (instance && instance->${ext.name[3:]}) return true;
-         % else:
-      if (instance && (!device || device->${ext.name[3:]})) return true;
-         % endif
-      %endfor
-      return false;
-   % else:
-      return instance;
-   % endif
-% endfor
-   default:
-      return false;
-   }
-}
-
-static int
-radv_lookup_entrypoint(const char *name)
-{
-   static const uint32_t prime_factor = ${strmap.prime_factor};
-   static const uint32_t prime_step = ${strmap.prime_step};
-   const struct string_map_entry *e;
-   uint32_t hash, h;
-   uint16_t i;
-   const char *p;
-
-   hash = 0;
-   for (p = name; *p; p++)
-       hash = hash * prime_factor + *p;
-
-   h = hash;
-   while (1) {
-       i = string_map[h & ${strmap.hash_mask}];
-       if (i == none)
-          return -1;
-       e = &string_map_entries[i];
-       if (e->hash == hash && strcmp(name, strings + e->name) == 0)
-           return e->num;
-       h += prime_step;
-   }
-
-   return -1;
-}
-
-void *
-radv_lookup_entrypoint_unchecked(const char *name)
-{
-   int index = radv_lookup_entrypoint(name);
-   if (index < 0)
-      return NULL;
-   return radv_resolve_entrypoint(index);
-}
-
-void *
-radv_lookup_entrypoint_checked(const char *name,
-                               uint32_t core_version,
-                               const struct radv_instance_extension_table *instance,
-                               const struct radv_device_extension_table *device)
-{
-   int index = radv_lookup_entrypoint(name);
-   if (index < 0 || !radv_entrypoint_is_enabled(index, core_version, instance, device))
-      return NULL;
-   return radv_resolve_entrypoint(index);
-}""", output_encoding='utf-8')
-
-U32_MASK = 2**32 - 1
-
-PRIME_FACTOR = 5024183
-PRIME_STEP = 19
-
-def round_to_pow2(x):
-    return 2**int(math.ceil(math.log(x, 2)))
-
-class StringIntMapEntry(object):
-    def __init__(self, string, num):
-        self.string = string
-        self.num = num
-
-        # Calculate the same hash value that we will calculate in C.
-        h = 0
-        for c in string:
-            h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK
-        self.hash = h
-
-        self.offset = None
-
-class StringIntMap(object):
-    def __init__(self):
-        self.baked = False
-        self.strings = dict()
-
-    def add_string(self, string, num):
-        assert not self.baked
-        assert string not in self.strings
-        assert num >= 0 and num < 2**31
-        self.strings[string] = StringIntMapEntry(string, num)
-
-    def bake(self):
-        self.sorted_strings = \
-            sorted(self.strings.values(), key=lambda x: x.string)
-        offset = 0
-        for entry in self.sorted_strings:
-            entry.offset = offset
-            offset += len(entry.string) + 1
-
-        # Save off some values that we'll need in C
-        self.hash_size = round_to_pow2(len(self.strings) * 1.25)
-        self.hash_mask = self.hash_size - 1
-        self.prime_factor = PRIME_FACTOR
-        self.prime_step = PRIME_STEP
-
-        self.mapping = [-1] * self.hash_size
-        self.collisions = [0] * 10
-        for idx, s in enumerate(self.sorted_strings):
-            level = 0
-            h = s.hash
-            while self.mapping[h & self.hash_mask] >= 0:
-                h = h + PRIME_STEP
-                level = level + 1
-            self.collisions[min(level, 9)] += 1
-            self.mapping[h & self.hash_mask] = idx
-
-EntrypointParam = namedtuple('EntrypointParam', 'type name decl')
-
-class EntrypointBase(object):
-    def __init__(self, name):
-        self.name = name
-        self.alias = None
-        self.guard = None
-        self.enabled = False
-        self.num = None
-        # Extensions which require this entrypoint
-        self.core_version = None
-        self.extensions = []
-
-class Entrypoint(EntrypointBase):
-    def __init__(self, name, return_type, params, guard = None):
-        super(Entrypoint, self).__init__(name)
-        self.return_type = return_type
-        self.params = params
-        self.guard = guard
-        self.device_command = len(params) > 0 and (params[0].type == 'VkDevice' or params[0].type == 'VkQueue' or params[0].type == 'VkCommandBuffer')
-
-    def prefixed_name(self, prefix):
-        assert self.name.startswith('vk')
-        return prefix + '_' + self.name[2:]
-
-    def decl_params(self):
-        return ', '.join(p.decl for p in self.params)
-
-    def call_params(self):
-        return ', '.join(p.name for p in self.params)
-
-class EntrypointAlias(EntrypointBase):
-    def __init__(self, name, entrypoint):
-        super(EntrypointAlias, self).__init__(name)
-        self.alias = entrypoint
-        self.device_command = entrypoint.device_command
-
-    def prefixed_name(self, prefix):
-        return self.alias.prefixed_name(prefix)
-
-def get_entrypoints(doc, entrypoints_to_defines, start_index):
-    """Extract the entry points from the registry."""
-    entrypoints = OrderedDict()
-
-    for command in doc.findall('./commands/command'):
-       if 'alias' in command.attrib:
-           alias = command.attrib['name']
-           target = command.attrib['alias']
-           entrypoints[alias] = EntrypointAlias(alias, entrypoints[target])
-       else:
-           name = command.find('./proto/name').text
-           ret_type = command.find('./proto/type').text
-           params = [EntrypointParam(
-               type = p.find('./type').text,
-               name = p.find('./name').text,
-               decl = ''.join(p.itertext())
-           ) for p in command.findall('./param')]
-           guard = entrypoints_to_defines.get(name)
-           # They really need to be unique
-           assert name not in entrypoints
-           entrypoints[name] = Entrypoint(name, ret_type, params, guard)
-
-    for feature in doc.findall('./feature'):
-        assert feature.attrib['api'] == 'vulkan'
-        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_exts = dict((ext.name, ext) for ext in EXTENSIONS)
-    for extension in doc.findall('.extensions/extension'):
-        ext_name = extension.attrib['name']
-        if ext_name not in supported_exts:
-            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
-            e.extensions.append(ext)
-
-    # if the base command is not supported by the driver yet, don't alias aliases
-    for e in entrypoints.values():
-        if e.alias and not e.alias.enabled:
-            e_clone = copy.deepcopy(e.alias)
-            e_clone.enabled = True
-            e_clone.name = e.name
-            entrypoints[e.name] = e_clone
-
-    return [e for e in entrypoints.values() if e.enabled]
-
-
-def get_entrypoints_defines(doc):
-    """Maps entry points to extension defines."""
-    entrypoints_to_defines = {}
-
-    for extension in doc.findall('./extensions/extension[@protect]'):
-        define = extension.attrib['protect']
-
-        for entrypoint in extension.findall('./require/command'):
-            fullname = entrypoint.attrib['name']
-            entrypoints_to_defines[fullname] = define
-
-    for extension in doc.findall('./extensions/extension[@platform]'):
-        platform = extension.attrib['platform']
-        ext = '_KHR'
-        if platform.upper() == 'XLIB_XRANDR':
-            ext = '_EXT'
-        define = 'VK_USE_PLATFORM_' + platform.upper() + ext
-
-        for entrypoint in extension.findall('./require/command'):
-            fullname = entrypoint.attrib['name']
-            entrypoints_to_defines[fullname] = define
-
-    return entrypoints_to_defines
-
-
-def gen_code(entrypoints):
-    """Generate the C code."""
-    strmap = StringIntMap()
-    for e in entrypoints:
-        strmap.add_string(e.name, e.num)
-    strmap.bake()
-
-    return TEMPLATE_C.render(entrypoints=entrypoints,
-                             LAYERS=LAYERS,
-                             strmap=strmap,
-                             filename=os.path.basename(__file__))
-
-
 def main():
     parser = argparse.ArgumentParser()
     parser.add_argument('--outdir', help='Where to write the files.',
@@ -482,24 +48,10 @@ def main():
                         dest='xml_files')
     args = parser.parse_args()
 
-    entrypoints = []
-
-    for filename in args.xml_files:
-        doc = et.parse(filename)
-        entrypoints += get_entrypoints(doc, get_entrypoints_defines(doc),
-                                       start_index=len(entrypoints))
-
-    for num, e in enumerate(entrypoints):
-        e.num = num
-
-    # 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,
-                                  LAYERS=LAYERS,
-                                  filename=os.path.basename(__file__)))
-    with open(os.path.join(args.outdir, 'radv_entrypoints.c'), 'wb') as f:
-        f.write(gen_code(entrypoints))
+    vk_entrypoints_gen.generate_entrypoints(MAX_API_VERSION, EXTENSIONS, LAYERS, 'radv', args.xml_files,
+                                            os.path.join(args.outdir, 'radv_entrypoints.c'),
+                                            os.path.join(args.outdir, 'radv_entrypoints.h'),
+                                            generate_trampolines=False)
 
 
 if __name__ == '__main__':
diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index 8b5eee867ac..b5a17b364a2 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -24,25 +24,20 @@ COPYRIGHT = """\
  */
 """
 
-import argparse
-import copy
-import re
-import xml.etree.cElementTree as et
+from vk_extensions import ApiVersion, Extension, VkVersion
 
-from mako.template import Template
+API_PATCH_VERSION = 80
 
-MAX_API_VERSION = '1.1.70'
+# Supported API versions.  Each one is the maximum patch version for the given
+# version.  Version come in increasing order and each version is available if
+# it's provided "enable" condition is true and all previous versions are
+# available.
+API_VERSIONS = [
+    ApiVersion('1.0',   True),
+    ApiVersion('1.1',   '!ANDROID && device->rad_info.has_syncobj_wait_for_submit'),
+]
 
-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;
+MAX_API_VERSION = None # Computed later
 
 # On Android, we disable all surface and swapchain extensions. Android's Vulkan
 # loader implements VK_KHR_surface and VK_KHR_swapchain, and applications
@@ -114,206 +109,9 @@ EXTENSIONS = [
     Extension('VK_AMD_shader_trinary_minmax',             1, True),
 ]
 
-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):
-        patch = self.patch if self.patch is not None else 0
-        ver_list = [str(self.major), str(self.minor), str(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 __gt__(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() > 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
-
-        ext = ext_name_map[ext_name]
-        ext.type = ext_elem.attrib['type']
-
-_TEMPLATE_H = Template(COPYRIGHT + """
-#ifndef RADV_EXTENSIONS_H
-#define RADV_EXTENSIONS_H
-
-enum {
-   RADV_INSTANCE_EXTENSION_COUNT = ${len(instance_extensions)},
-   RADV_DEVICE_EXTENSION_COUNT = ${len(device_extensions)},
-};
-
-struct radv_instance_extension_table {
-   union {
-      bool extensions[RADV_INSTANCE_EXTENSION_COUNT];
-      struct {
-%for ext in instance_extensions:
-        bool ${ext.name[3:]};
-%endfor
-      };
-   };
-};
-
-struct radv_device_extension_table {
-   union {
-      bool extensions[RADV_DEVICE_EXTENSION_COUNT];
-      struct {
-%for ext in device_extensions:
-        bool ${ext.name[3:]};
-%endfor
-      };
-   };
-};
-
-extern const VkExtensionProperties radv_instance_extensions[RADV_INSTANCE_EXTENSION_COUNT];
-extern const VkExtensionProperties radv_device_extensions[RADV_DEVICE_EXTENSION_COUNT];
-extern const struct radv_instance_extension_table radv_supported_instance_extensions;
-
-
-struct radv_physical_device;
-
-void radv_fill_device_extension_table(const struct radv_physical_device *device,
-                                      struct radv_device_extension_table* table);
-#endif
-""")
-
-_TEMPLATE_C = Template(COPYRIGHT + """
-#include "radv_private.h"
-
-#include "vk_util.h"
-
-/* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
-#ifdef VK_USE_PLATFORM_${platform}
-#   undef VK_USE_PLATFORM_${platform}
-#   define VK_USE_PLATFORM_${platform} true
-#else
-#   define VK_USE_PLATFORM_${platform} 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 || \\
-                         VK_USE_PLATFORM_DISPLAY_KHR)
-
-
-const VkExtensionProperties radv_instance_extensions[RADV_INSTANCE_EXTENSION_COUNT] = {
-%for ext in instance_extensions:
-   {"${ext.name}", ${ext.ext_version}},
-%endfor
-};
-
-const VkExtensionProperties radv_device_extensions[RADV_DEVICE_EXTENSION_COUNT] = {
-%for ext in device_extensions:
-   {"${ext.name}", ${ext.ext_version}},
-%endfor
-};
-
-const struct radv_instance_extension_table radv_supported_instance_extensions = {
-%for ext in instance_extensions:
-   .${ext.name[3:]} = ${ext.enable},
-%endfor
-};
-
-void radv_fill_device_extension_table(const struct radv_physical_device *device,
-                                      struct radv_device_extension_table* table)
-{
-%for ext in device_extensions:
-   table->${ext.name[3:]} = ${ext.enable};
-%endfor
-}
-
-VkResult radv_EnumerateInstanceVersion(
-    uint32_t*                                   pApiVersion)
-{
-    *pApiVersion = ${MAX_API_VERSION.c_vk_version()};
-    return VK_SUCCESS;
-}
-
-uint32_t
-radv_physical_device_api_version(struct radv_physical_device *dev)
-{
-    if (!ANDROID && dev->rad_info.has_syncobj_wait_for_submit)
-        return VK_MAKE_VERSION(1, 1, 70);
-    return VK_MAKE_VERSION(1, 0, 68);
-}
-""")
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--out-c', help='Output C file.', required=True)
-    parser.add_argument('--out-h', help='Output H 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_c, 'w') as f:
-        f.write(_TEMPLATE_C.render(**template_env))
-    with open(args.out_h, 'w') as f:
-        f.write(_TEMPLATE_H.render(**template_env))
+MAX_API_VERSION = VkVersion('0.0.0')
+for version in API_VERSIONS:
+    version.version = VkVersion(version.version)
+    version.version.patch = API_PATCH_VERSION
+    assert version.version > MAX_API_VERSION
+    MAX_API_VERSION = version.version
diff --git a/src/amd/vulkan/radv_extensions_gen.py b/src/amd/vulkan/radv_extensions_gen.py
new file mode 100644
index 00000000000..071e175ad9e
--- /dev/null
+++ b/src/amd/vulkan/radv_extensions_gen.py
@@ -0,0 +1,44 @@
+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
+
+from radv_extensions import *
+import vk_extensions_gen
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--out-c', help='Output C file.')
+    parser.add_argument('--out-h', help='Output H file.')
+    parser.add_argument('--xml',
+                        help='Vulkan API XML file.',
+                        required=True,
+                        action='append',
+                        dest='xml_files')
+    args = parser.parse_args()
+
+    vk_extensions_gen.generate_extensions(MAX_API_VERSION, API_VERSIONS, EXTENSIONS, 'radv', 
+                                          args.xml_files, args.out_c, args.out_h)
diff --git a/src/amd/vulkan/radv_icd.py b/src/amd/vulkan/radv_icd.py
index cc86bbfa56c..5b1a0237d09 100644
--- a/src/amd/vulkan/radv_icd.py
+++ b/src/amd/vulkan/radv_icd.py
@@ -20,6 +20,7 @@
 # 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 json
 import os.path
 
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index a187f76be49..36101db52c3 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -267,11 +267,10 @@ void radv_logi_v(const char *format, va_list va);
 		return;					\
 	} while (0)
 
-void *radv_lookup_entrypoint_unchecked(const char *name);
-void *radv_lookup_entrypoint_checked(const char *name,
-                                    uint32_t core_version,
-                                    const struct radv_instance_extension_table *instance,
-                                    const struct radv_device_extension_table *device);
+int radv_get_entrypoint_index(const char *name);
+bool radv_entrypoint_is_enabled(int index, uint32_t core_version,
+                                const struct radv_instance_extension_table *instance,
+				const struct radv_device_extension_table *device);
 
 struct radv_physical_device {
 	VK_LOADER_DATA                              _loader_data;
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index 20484177135..73994bcc358 100644
--- a/src/amd/vulkan/radv_wsi.c
+++ b/src/amd/vulkan/radv_wsi.c
@@ -32,7 +32,11 @@
 static PFN_vkVoidFunction
 radv_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName)
 {
-	return radv_lookup_entrypoint_unchecked(pName);
+	int idx = radv_get_entrypoint_index(pName);
+	if (idx < 0)
+		return NULL;
+
+	return radv_dispatch_table.entrypoints[idx];
 }
 
 VkResult
-- 
2.18.0



More information about the mesa-dev mailing list