zink: move extension function verification to when it is used

Some vulkan functions are not loaded when the corresponding features are
not enabled, but the verifier checks for *all* functions, so make the
verifier more forgiving and use a stub to catch when we actually use a
function that is not loaded.

Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11328>
This commit is contained in:
Hoe Hao Cheng 2021-06-12 00:36:32 +08:00 committed by Marge Bot
parent a0122385f0
commit b5d344c3af
4 changed files with 113 additions and 20 deletions

View file

@ -268,9 +268,20 @@ struct zink_device_info {
bool
zink_get_physical_device_info(struct zink_screen *screen);
bool
void
zink_verify_device_extensions(struct zink_screen *screen);
/* stub functions that get inserted into the dispatch table if they are not
* properly loaded.
*/
%for ext in extensions:
%if registry.in_registry(ext.name):
%for cmd in registry.get_registry_entry(ext.name).device_commands:
void zink_stub_${cmd.lstrip("vk")}(void);
%endfor
%endif
%endfor
#endif
"""
@ -443,7 +454,7 @@ fail:
return false;
}
bool
void
zink_verify_device_extensions(struct zink_screen *screen)
{
%for ext in extensions:
@ -451,16 +462,45 @@ zink_verify_device_extensions(struct zink_screen *screen)
if (screen->info.have_${ext.name_with_vendor()}) {
%for cmd in registry.get_registry_entry(ext.name).device_commands:
if (!screen->vk.${cmd.lstrip("vk")}) {
mesa_loge("ZINK: GetDeviceProcAddr failed: ${cmd}\\n");
return false;
#ifndef NDEBUG
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")};
#else
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded;
#endif
}
%endfor
}
%endif
%endfor
return true;
}
#ifndef NDEBUG
/* generated stub functions */
## remember the stub functions that are already generated
<% generated_funcs = set() %>
%for ext in extensions:
%if registry.in_registry(ext.name):
%for cmd in registry.get_registry_entry(ext.name).device_commands:
##
## some functions are added by multiple extensions, which creates duplication
## and thus redefinition of stubs (eg. vkCmdPushDescriptorSetWithTemplateKHR)
##
%if cmd in generated_funcs:
<% continue %>
%else:
<% generated_funcs.add(cmd) %>
%endif
void
zink_stub_${cmd.lstrip("vk")}()
{
mesa_loge("ZINK: ${cmd} is not loaded properly!");
abort();
}
%endfor
%endif
%endfor
#endif
"""
@ -531,7 +571,7 @@ if __name__ == "__main__":
lookup.put_string("helpers", include_template)
with open(header_path, "w") as header_file:
header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions).strip()
header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip()
header = replace_code(header, replacement)
print(header, file=header_file)

View file

@ -87,9 +87,23 @@ struct zink_instance_info {
VkInstance
zink_create_instance(struct zink_instance_info *instance_info);
bool
void
zink_verify_instance_extensions(struct zink_screen *screen);
/* stub functions that get inserted into the dispatch table if they are not
* properly loaded.
*/
%for ext in extensions:
%if registry.in_registry(ext.name):
%for cmd in registry.get_registry_entry(ext.name).instance_commands:
void zink_stub_${cmd.lstrip("vk")}(void);
%endfor
%for cmd in registry.get_registry_entry(ext.name).pdevice_commands:
void zink_stub_${cmd.lstrip("vk")}(void);
%endfor
%endif
%endfor
#endif
"""
@ -218,7 +232,7 @@ zink_create_instance(struct zink_instance_info *instance_info)
return instance;
}
bool
void
zink_verify_instance_extensions(struct zink_screen *screen)
{
%for ext in extensions:
@ -226,22 +240,51 @@ zink_verify_instance_extensions(struct zink_screen *screen)
if (screen->instance_info.have_${ext.name_with_vendor()}) {
%for cmd in registry.get_registry_entry(ext.name).instance_commands:
if (!screen->vk.${cmd.lstrip("vk")}) {
mesa_loge("ZINK: GetInstanceProcAddr failed: ${cmd}\\n");
return false;
#ifndef NDEBUG
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")};
#else
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded;
#endif
}
%endfor
%for cmd in registry.get_registry_entry(ext.name).pdevice_commands:
if (!screen->vk.${cmd.lstrip("vk")}) {
mesa_loge("ZINK: GetInstanceProcAddr failed: ${cmd}\\n");
return false;
#ifndef NDEBUG
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")};
#else
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded;
#endif
}
%endfor
}
%endif
%endfor
return true;
}
#ifndef NDEBUG
/* generated stub functions */
## see zink_device_info.py for why this is needed
<% generated_funcs = set() %>
%for ext in extensions:
%if registry.in_registry(ext.name):
%for cmd in registry.get_registry_entry(ext.name).instance_commands + registry.get_registry_entry(ext.name).pdevice_commands:
%if cmd in generated_funcs:
<% continue %>
%else:
<% generated_funcs.add(cmd) %>
%endif
void
zink_stub_${cmd.lstrip("vk")}()
{
mesa_loge("ZINK: ${cmd} is not loaded properly!");
abort();
}
%endfor
%endif
%endfor
#endif
"""
@ -298,7 +341,7 @@ if __name__ == "__main__":
exit(1)
with open(header_path, "w") as header_file:
header = Template(header_code).render(extensions=extensions, layers=layers).strip()
header = Template(header_code).render(extensions=extensions, layers=layers, registry=registry).strip()
header = replace_code(header, replacement)
print(header, file=header_file)

View file

@ -1586,8 +1586,7 @@ zink_internal_create_screen(const struct pipe_screen_config *config)
vk_instance_dispatch_table_load(&screen->vk.instance, &vkGetInstanceProcAddr, screen->instance);
vk_physical_device_dispatch_table_load(&screen->vk.physical_device, &vkGetInstanceProcAddr, screen->instance);
if (!zink_verify_instance_extensions(screen))
goto fail;
zink_verify_instance_extensions(screen);
if (screen->instance_info.have_EXT_debug_utils &&
(zink_debug & ZINK_DEBUG_VALIDATION) && !create_debug(screen))
@ -1628,8 +1627,7 @@ zink_internal_create_screen(const struct pipe_screen_config *config)
vk_device_dispatch_table_load(&screen->vk.device, &vkGetDeviceProcAddr, screen->dev);
if (!zink_verify_device_extensions(screen))
goto fail;
zink_verify_device_extensions(screen);
if (screen->info.have_EXT_calibrated_timestamps && !check_have_device_time(screen))
goto fail;
@ -1775,3 +1773,12 @@ zink_drm_create_screen(int fd, const struct pipe_screen_config *config)
return &ret->base;
}
void zink_stub_function_not_loaded()
{
/* this will be used by the zink_verify_*_extensions() functions on a
* release build
*/
mesa_loge("ZINK: a Vulkan function was called without being loaded");
abort();
}

View file

@ -265,4 +265,7 @@ zink_screen_update_pipeline_cache(struct zink_screen *screen);
void
zink_screen_init_descriptor_funcs(struct zink_screen *screen, bool fallback);
void
zink_stub_function_not_loaded(void);
#endif