From ae18c53ba6e0cb0b54a6e76caf6fbfa8a180c076 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Sat, 13 Oct 2018 12:16:14 -0500 Subject: [PATCH] anv: Split dispatch tables into device and instance There's no reason why we need generate trampoline functions for instance functions or carry N copies of the instance dispatch table around for every hardware generation. Splitting the tables and being more conservative shaves about 34K off .text and about 4K off .data when built with clang. Before splitting dispatch tables: text data bss dec hex filename 3224305 286216 8960 3519481 35b3f9 _install/lib64/libvulkan_intel.so After splitting dispatch tables: text data bss dec hex filename 3190325 282232 8960 3481517 351fad _install/lib64/libvulkan_intel.so Reviewed-by: Lionel Landwerlin --- src/intel/vulkan/anv_device.c | 61 ++++-- src/intel/vulkan/anv_entrypoints_gen.py | 242 +++++++++++++++++------- src/intel/vulkan/anv_private.h | 18 +- 3 files changed, 230 insertions(+), 91 deletions(-) diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index 6a24d1086d8..a2551452eb1 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -637,14 +637,28 @@ VkResult anv_CreateInstance( /* Vulkan requires that entrypoints for extensions which have not been * enabled must not be advertised. */ - if (!anv_entrypoint_is_enabled(i, instance->app_info.api_version, - &instance->enabled_extensions, NULL)) { + if (!anv_instance_entrypoint_is_enabled(i, instance->app_info.api_version, + &instance->enabled_extensions)) { instance->dispatch.entrypoints[i] = NULL; - } else if (anv_dispatch_table.entrypoints[i] != NULL) { - instance->dispatch.entrypoints[i] = anv_dispatch_table.entrypoints[i]; } else { instance->dispatch.entrypoints[i] = - anv_tramp_dispatch_table.entrypoints[i]; + anv_instance_dispatch_table.entrypoints[i]; + } + } + + for (unsigned i = 0; i < ARRAY_SIZE(instance->device_dispatch.entrypoints); i++) { + /* Vulkan requires that entrypoints for extensions which have not been + * enabled must not be advertised. + */ + if (!anv_device_entrypoint_is_enabled(i, instance->app_info.api_version, + &instance->enabled_extensions, NULL)) { + instance->device_dispatch.entrypoints[i] = NULL; + } else if (anv_device_dispatch_table.entrypoints[i] != NULL) { + instance->device_dispatch.entrypoints[i] = + anv_device_dispatch_table.entrypoints[i]; + } else { + instance->device_dispatch.entrypoints[i] = + anv_tramp_device_dispatch_table.entrypoints[i]; } } @@ -1349,11 +1363,15 @@ PFN_vkVoidFunction anv_GetInstanceProcAddr( if (instance == NULL) return NULL; - int idx = anv_get_entrypoint_index(pName); - if (idx < 0) - return NULL; + int idx = anv_get_instance_entrypoint_index(pName); + if (idx >= 0) + return instance->dispatch.entrypoints[idx]; + + idx = anv_get_device_entrypoint_index(pName); + if (idx >= 0) + return instance->device_dispatch.entrypoints[idx]; - return instance->dispatch.entrypoints[idx]; + return NULL; } /* With version 1+ of the loader interface the ICD should expose @@ -1381,7 +1399,7 @@ PFN_vkVoidFunction anv_GetDeviceProcAddr( if (!device || !pName) return NULL; - int idx = anv_get_entrypoint_index(pName); + int idx = anv_get_device_entrypoint_index(pName); if (idx < 0) return NULL; @@ -1531,25 +1549,25 @@ VkResult anv_EnumerateDeviceExtensionProperties( static void anv_device_init_dispatch(struct anv_device *device) { - const struct anv_dispatch_table *genX_table; + const struct anv_device_dispatch_table *genX_table; switch (device->info.gen) { case 11: - genX_table = &gen11_dispatch_table; + genX_table = &gen11_device_dispatch_table; break; case 10: - genX_table = &gen10_dispatch_table; + genX_table = &gen10_device_dispatch_table; break; case 9: - genX_table = &gen9_dispatch_table; + genX_table = &gen9_device_dispatch_table; break; case 8: - genX_table = &gen8_dispatch_table; + genX_table = &gen8_device_dispatch_table; break; case 7: if (device->info.is_haswell) - genX_table = &gen75_dispatch_table; + genX_table = &gen75_device_dispatch_table; else - genX_table = &gen7_dispatch_table; + genX_table = &gen7_device_dispatch_table; break; default: unreachable("unsupported gen\n"); @@ -1559,14 +1577,15 @@ anv_device_init_dispatch(struct anv_device *device) /* Vulkan requires that entrypoints for extensions which have not been * enabled must not be advertised. */ - if (!anv_entrypoint_is_enabled(i, device->instance->app_info.api_version, - &device->instance->enabled_extensions, - &device->enabled_extensions)) { + if (!anv_device_entrypoint_is_enabled(i, device->instance->app_info.api_version, + &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 { - device->dispatch.entrypoints[i] = anv_dispatch_table.entrypoints[i]; + device->dispatch.entrypoints[i] = + anv_device_dispatch_table.entrypoints[i]; } } } diff --git a/src/intel/vulkan/anv_entrypoints_gen.py b/src/intel/vulkan/anv_entrypoints_gen.py index e6cd9bbf0a9..beb658b8660 100644 --- a/src/intel/vulkan/anv_entrypoints_gen.py +++ b/src/intel/vulkan/anv_entrypoints_gen.py @@ -50,11 +50,11 @@ LAYERS = [ TEMPLATE_H = Template("""\ /* This file generated from ${filename}, don't edit directly. */ -struct anv_dispatch_table { +struct anv_instance_dispatch_table { union { - void *entrypoints[${len(entrypoints)}]; + void *entrypoints[${len(instance_entrypoints)}]; struct { - % for e in entrypoints: + % for e in instance_entrypoints: % if e.guard is not None: #ifdef ${e.guard} PFN_${e.name} ${e.name}; @@ -69,12 +69,45 @@ struct anv_dispatch_table { }; }; +struct anv_device_dispatch_table { + union { + void *entrypoints[${len(device_entrypoints)}]; + struct { + % for e in device_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 + }; + }; +}; + +extern const struct anv_instance_dispatch_table anv_instance_dispatch_table; %for layer in LAYERS: -extern const struct anv_dispatch_table ${layer}_dispatch_table; +extern const struct anv_device_dispatch_table ${layer}_device_dispatch_table; %endfor -extern const struct anv_dispatch_table anv_tramp_dispatch_table; +extern const struct anv_device_dispatch_table anv_tramp_device_dispatch_table; -% for e in entrypoints: +% for e in instance_entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + ${e.return_type} ${e.prefixed_name('anv')}(${e.decl_params()}); + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor + +% for e in device_entrypoints: % if e.alias: <% continue %> % endif @@ -129,13 +162,14 @@ struct string_map_entry { * store the index into this big string. */ -static const char strings[] = +<%def name="strmap(strmap, prefix)"> +static const char ${prefix}_strings[] = % for s in strmap.sorted_strings: "${s.string}\\0" % endfor ; -static const struct string_map_entry string_map_entries[] = { +static const struct string_map_entry ${prefix}_string_map_entries[] = { % for s in strmap.sorted_strings: { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */ % endfor @@ -150,14 +184,14 @@ static const struct string_map_entry string_map_entries[] = { */ #define none 0xffff -static const uint16_t string_map[${strmap.hash_size}] = { +static const uint16_t ${prefix}_string_map[${strmap.hash_size}] = { % for e in strmap.mapping: ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' }, % endfor }; static int -string_map_lookup(const char *str) +${prefix}_string_map_lookup(const char *str) { static const uint32_t prime_factor = ${strmap.prime_factor}; static const uint32_t prime_step = ${strmap.prime_step}; @@ -172,25 +206,54 @@ string_map_lookup(const char *str) h = hash; while (1) { - i = string_map[h & ${strmap.hash_mask}]; + i = ${prefix}_string_map[h & ${strmap.hash_mask}]; if (i == none) return -1; - e = &string_map_entries[i]; - if (e->hash == hash && strcmp(str, strings + e->name) == 0) + e = &${prefix}_string_map_entries[i]; + if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0) return e->num; h += prime_step; } return -1; } + + +${strmap(instance_strmap, 'instance')} +${strmap(device_strmap, 'device')} /* 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 e in instance_entrypoints: + % if e.alias: + <% continue %> + % endif + % if e.guard is not None: +#ifdef ${e.guard} + % endif + ${e.return_type} ${e.prefixed_name('anv')}(${e.decl_params()}) __attribute__ ((weak)); + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor + +const struct anv_instance_dispatch_table anv_instance_dispatch_table = { +% for e in instance_entrypoints: + % if e.guard is not None: +#ifdef ${e.guard} + % endif + .${e.name} = ${e.prefixed_name('anv')}, + % if e.guard is not None: +#endif // ${e.guard} + % endif +% endfor +}; + % for layer in LAYERS: - % for e in entrypoints: + % for e in device_entrypoints: % if e.alias: <% continue %> % endif @@ -203,8 +266,8 @@ string_map_lookup(const char *str) % endif % endfor - const struct anv_dispatch_table ${layer}_dispatch_table = { - % for e in entrypoints: + const struct anv_device_dispatch_table ${layer}_device_dispatch_table = { + % for e in device_entrypoints: % if e.guard is not None: #ifdef ${e.guard} % endif @@ -219,8 +282,8 @@ string_map_lookup(const char *str) /** Trampoline entrypoints for all device functions */ -% for e in entrypoints: - % if e.alias or not e.is_device_entrypoint(): +% for e in device_entrypoints: + % if e.alias: <% continue %> % endif % if e.guard is not None: @@ -247,11 +310,8 @@ string_map_lookup(const char *str) % endif % endfor -const struct anv_dispatch_table anv_tramp_dispatch_table = { -% for e in entrypoints: - % if not e.is_device_entrypoint(): - <% continue %> - % endif +const struct anv_device_dispatch_table anv_tramp_device_dispatch_table = { +% for e in device_entrypoints: % if e.guard is not None: #ifdef ${e.guard} % endif @@ -269,26 +329,22 @@ const struct anv_dispatch_table anv_tramp_dispatch_table = { * 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) +anv_instance_entrypoint_is_enabled(int index, uint32_t core_version, + const struct anv_instance_extension_table *instance) { switch (index) { -% for e in entrypoints: +% for e in instance_entrypoints: case ${e.num}: /* ${e.name} */ % if e.core_version: - % if e.is_device_entrypoint(): - return ${e.core_version.c_vk_version()} <= core_version; - % else: - return !device && ${e.core_version.c_vk_version()} <= core_version; - % endif + return ${e.core_version.c_vk_version()} <= core_version; % elif e.extensions: % for ext in e.extensions: - % if ext.type == 'instance': - if (!device && instance->${ext.name[3:]}) return true; + % if ext.type == 'instance': + if (instance->${ext.name[3:]}) return true; % else: - if (!device || device->${ext.name[3:]}) return true; + /* All device extensions are considered enabled at the instance level */ + return true; % endif % endfor return false; @@ -301,32 +357,74 @@ anv_entrypoint_is_enabled(int index, uint32_t core_version, } } -static void * __attribute__ ((noinline)) -anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index) +/** 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_device_entrypoint_is_enabled(int index, uint32_t core_version, + const struct anv_instance_extension_table *instance, + const struct anv_device_extension_table *device) { - if (devinfo == NULL) { - return anv_dispatch_table.entrypoints[index]; + switch (index) { +% for e in device_entrypoints: + case ${e.num}: + /* ${e.name} */ + % if e.core_version: + return ${e.core_version.c_vk_version()} <= core_version; + % elif e.extensions: + % for ext in e.extensions: + % if ext.type == 'instance': + <% assert False %> + % else: + if (!device || device->${ext.name[3:]}) return true; + % endif + % endfor + return false; + % else: + return true; + % endif +% endfor + default: + return false; } +} + +int +anv_get_instance_entrypoint_index(const char *name) +{ + return instance_string_map_lookup(name); +} + +int +anv_get_device_entrypoint_index(const char *name) +{ + return device_string_map_lookup(name); +} - const struct anv_dispatch_table *genX_table; +static void * __attribute__ ((noinline)) +anv_resolve_device_entrypoint(const struct gen_device_info *devinfo, uint32_t index) +{ + const struct anv_device_dispatch_table *genX_table; switch (devinfo->gen) { case 11: - genX_table = &gen11_dispatch_table; + genX_table = &gen11_device_dispatch_table; break; case 10: - genX_table = &gen10_dispatch_table; + genX_table = &gen10_device_dispatch_table; break; case 9: - genX_table = &gen9_dispatch_table; + genX_table = &gen9_device_dispatch_table; break; case 8: - genX_table = &gen8_dispatch_table; + genX_table = &gen8_device_dispatch_table; break; case 7: if (devinfo->is_haswell) - genX_table = &gen75_dispatch_table; + genX_table = &gen75_device_dispatch_table; else - genX_table = &gen7_dispatch_table; + genX_table = &gen7_device_dispatch_table; break; default: unreachable("unsupported gen\\n"); @@ -335,22 +433,21 @@ anv_resolve_entrypoint(const struct gen_device_info *devinfo, uint32_t index) if (genX_table->entrypoints[index]) return genX_table->entrypoints[index]; else - return anv_dispatch_table.entrypoints[index]; -} - -int -anv_get_entrypoint_index(const char *name) -{ - return string_map_lookup(name); + return anv_device_dispatch_table.entrypoints[index]; } void * anv_lookup_entrypoint(const struct gen_device_info *devinfo, const char *name) { - int idx = anv_get_entrypoint_index(name); - if (idx < 0) - return NULL; - return anv_resolve_entrypoint(devinfo, idx); + int idx = anv_get_instance_entrypoint_index(name); + if (idx >= 0) + return anv_instance_dispatch_table.entrypoints[idx]; + + idx = anv_get_device_entrypoint_index(name); + if (idx >= 0) + return anv_resolve_device_entrypoint(devinfo, idx); + + return NULL; }""", output_encoding='utf-8') U32_MASK = 2**32 - 1 @@ -554,23 +651,40 @@ def main(): EntrypointParam('VkImage', 'pImage', 'VkImage* pImage') ])) - strmap = StringIntMap() - for num, e in enumerate(entrypoints): - strmap.add_string(e.name, num) + device_entrypoints = [] + instance_entrypoints = [] + for e in entrypoints: + if e.is_device_entrypoint(): + device_entrypoints.append(e) + else: + instance_entrypoints.append(e) + + device_strmap = StringIntMap() + for num, e in enumerate(device_entrypoints): + device_strmap.add_string(e.name, num) + e.num = num + device_strmap.bake() + + instance_strmap = StringIntMap() + for num, e in enumerate(instance_entrypoints): + instance_strmap.add_string(e.name, num) e.num = num - strmap.bake() + instance_strmap.bake() # For outputting entrypoints.h we generate a anv_EntryPoint() prototype # per entry point. try: with open(os.path.join(args.outdir, 'anv_entrypoints.h'), 'wb') as f: - f.write(TEMPLATE_H.render(entrypoints=entrypoints, + f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints, + device_entrypoints=device_entrypoints, LAYERS=LAYERS, filename=os.path.basename(__file__))) with open(os.path.join(args.outdir, 'anv_entrypoints.c'), 'wb') as f: - f.write(TEMPLATE_C.render(entrypoints=entrypoints, + f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints, + device_entrypoints=device_entrypoints, LAYERS=LAYERS, - strmap=strmap, + instance_strmap=instance_strmap, + device_strmap=device_strmap, filename=os.path.basename(__file__))) except Exception: # In the even there's an error this imports some helpers from mako diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 5b4c286bf38..599b903f25c 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -903,7 +903,8 @@ struct anv_instance { struct anv_app_info app_info; struct anv_instance_extension_table enabled_extensions; - struct anv_dispatch_table dispatch; + struct anv_instance_dispatch_table dispatch; + struct anv_device_dispatch_table device_dispatch; int physicalDeviceCount; struct anv_physical_device physicalDevice; @@ -986,7 +987,7 @@ struct anv_device { bool can_chain_batches; bool robust_buffer_access; struct anv_device_extension_table enabled_extensions; - struct anv_dispatch_table dispatch; + struct anv_device_dispatch_table dispatch; pthread_mutex_t vma_mutex; struct util_vma_heap vma_lo; @@ -3242,12 +3243,17 @@ struct anv_query_pool { struct anv_bo bo; }; -int anv_get_entrypoint_index(const char *name); +int anv_get_instance_entrypoint_index(const char *name); +int anv_get_device_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); +anv_instance_entrypoint_is_enabled(int index, uint32_t core_version, + const struct anv_instance_extension_table *instance); + +bool +anv_device_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