a/bindings: Generate code to verify paths for promoted core paths

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2194>
This commit is contained in:
Christoph Haag 2024-03-04 18:35:03 +01:00 committed by Marge Bot
parent 7cf457d894
commit cdbf4ef26a
2 changed files with 55 additions and 27 deletions

View file

@ -441,7 +441,7 @@ header = '''// Copyright 2020-2022, Collabora, Ltd.
func_start = ''' func_start = '''
bool bool
{name}(const struct oxr_extension_status *exts, const char *str, size_t length) {name}(const struct oxr_extension_status *exts, XrVersion openxr_version, const char *str, size_t length)
{{ {{
''' '''
@ -459,6 +459,21 @@ if_strcmp = '''{exttab}if (strcmp(str, "{check}") == 0) {{
{exttab}\t\t\treturn true; {exttab}\t\t\treturn true;
{exttab}\t\t}} else ''' {exttab}\t\t}} else '''
def check_promoted(openxr_version_promoted):
# If required version is 0.0, we can skip checking that the instance uses a more recent version
return openxr_version_promoted is not None and openxr_version_promoted["major"] != '0' and openxr_version_promoted["minor"] != '0'
def write_verify_switch_body(f, dict_of_lists, profile, profile_name, ext_name, tab_char):
"""Generate function to check if a string is in a set of strings.
Input is a file to write the code into, a dict where keys are length and
the values are lists of strings of that length. And a suffix if any."""
f.write(f"{tab_char}\tswitch (length) {{\n")
for length in dict_of_lists:
f.write(f"{tab_char}\tcase {str(length)}:\n\t\t")
for path in dict_of_lists[length]:
f.write(if_strcmp.format(exttab=tab_char, check=path))
f.write(f"{tab_char}{{\n{tab_char}\t\t\tbreak;\n{tab_char}\t\t}}\n")
f.write(f"{tab_char}\tdefault: break;\n{tab_char}\t}}\n")
def write_verify_func_switch(f, dict_of_lists, profile, profile_name, ext_name): def write_verify_func_switch(f, dict_of_lists, profile, profile_name, ext_name):
"""Generate function to check if a string is in a set of strings. """Generate function to check if a string is in a set of strings.
@ -467,29 +482,30 @@ def write_verify_func_switch(f, dict_of_lists, profile, profile_name, ext_name):
if len(dict_of_lists) == 0: if len(dict_of_lists) == 0:
return return
if profile.extension_name is not None: is_ext = ext_name is not None and len(ext_name) > 0
f.write(f'#ifdef OXR_HAVE_{profile.extension_name}\n') is_promoted = check_promoted(profile.openxr_version_promoted)
f.write(f"\t// generated from: {profile_name}\n") f.write(f"\t// generated from: {profile_name}\n")
is_ext = ext_name is not None and len(ext_name) > 0
ext_tab = "" # Example: pico neo 3 can be enabled by either enabling XR_BD_controller_interaction ext or using OpenXR 1.1+.
# Disabling OXR_HAVE_BD_controller_interaction should NOT remove pico neo from OpenXR 1.1+ (it makes "exts->BD_controller_interaction" invalid C code).
# Therefore separate code blocks for ext and version checks generated to avoid ifdef hell.
if is_ext: if is_ext:
f.write(f'#ifdef OXR_HAVE_{profile.extension_name}\n')
f.write(f"\tif (exts->{ext_name}) {{\n") f.write(f"\tif (exts->{ext_name}) {{\n")
ext_tab = "\t" write_verify_switch_body(f, dict_of_lists, profile, profile_name, ext_name, '\t')
f.write("\t}\n")
f.write(f'#endif // OXR_HAVE_{profile.extension_name}\n')
f.write(f"{ext_tab}\tswitch (length) {{\n") # The split into "is_promoted" and "not is_ext and not is_promoted" cases is not strictly necessary as we could generate the version check for both cases.
for length in dict_of_lists: # For the "not is_ext and not is_promoted" case this would generate "if (openxr_version >= XR_MAKE_VERSION(0, 0, 0))", which we avoid doing here by this split.
f.write(f"{ext_tab}\tcase {str(length)}:\n\t\t") if is_promoted:
for path in dict_of_lists[length]: f.write(f'\tif (openxr_version >= XR_MAKE_VERSION({profile.openxr_version_promoted["major"]}, {profile.openxr_version_promoted["minor"]}, 0)) {{\n')
f.write(if_strcmp.format(exttab=ext_tab, check=path)) write_verify_switch_body(f, dict_of_lists, profile, profile_name, ext_name, '\t')
f.write(f"{ext_tab}{{\n{ext_tab}\t\t\tbreak;\n{ext_tab}\t\t}}\n")
f.write(f"{ext_tab}\tdefault: break;\n{ext_tab}\t}}\n")
if is_ext:
f.write("\t}\n") f.write("\t}\n")
if profile.extension_name is not None: if not is_ext and not is_promoted:
f.write(f'#endif // OXR_HAVE_{profile.extension_name}\n') write_verify_switch_body(f, dict_of_lists, profile, profile_name, ext_name, '')
def write_verify_func_body(f, profile, dict_name): def write_verify_func_body(f, profile, dict_name):
if profile is None or dict_name is None or len(dict_name) == 0: if profile is None or dict_name is None or len(dict_name) == 0:
@ -516,8 +532,18 @@ def generate_verify_functions(f, profile):
f.write(f''' f.write(f'''
void void
oxr_verify_{profile.validation_func_name}_ext(const struct oxr_extension_status *extensions, bool *out_supported, bool *out_enabled) oxr_verify_{profile.validation_func_name}_ext(const struct oxr_extension_status *extensions, XrVersion openxr_version, bool *out_supported, bool *out_enabled)
{{''') {{
''')
is_promoted = check_promoted(profile.openxr_version_promoted)
if is_promoted:
f.write(f'\tif (openxr_version >= XR_MAKE_VERSION({profile.openxr_version_promoted["major"]}, {profile.openxr_version_promoted["minor"]}, 0)) {{\n')
f.write(f'\t\t*out_supported = true;\n')
f.write(f'\t\t*out_enabled = true;\n')
f.write(f'\t\treturn;\n')
f.write(f'\t}}')
if profile.extension_name is not None: if profile.extension_name is not None:
f.write(f''' f.write(f'''
#ifdef OXR_HAVE_{profile.extension_name} #ifdef OXR_HAVE_{profile.extension_name}
@ -776,6 +802,8 @@ def generate_bindings_h(file, b):
#include "xrt/xrt_defines.h" #include "xrt/xrt_defines.h"
typedef uint64_t XrPath; // OpenXR typedef typedef uint64_t XrPath; // OpenXR typedef
typedef uint64_t XrVersion; // OpenXR typedef
struct oxr_extension_status; struct oxr_extension_status;
/** /**
@ -792,8 +820,8 @@ void oxr_get_interaction_profile_path_cache(XrPath **out_path_cache[{len(b.profi
for profile in b.profiles: for profile in b.profiles:
for fn_suffix in fn_prefixes: for fn_suffix in fn_prefixes:
f.write( f.write(
f"\nbool\noxr_verify_{profile.validation_func_name}{fn_suffix}(const struct oxr_extension_status *extensions, const char *str, size_t length);\n") f"\nbool\noxr_verify_{profile.validation_func_name}{fn_suffix}(const struct oxr_extension_status *extensions, XrVersion openxr_major_minor, const char *str, size_t length);\n")
f.write(f'''\nvoid\noxr_verify_{profile.validation_func_name}_ext(const struct oxr_extension_status *extensions, bool *out_supported, bool *out_enabled);\n''') f.write(f'''\nvoid\noxr_verify_{profile.validation_func_name}_ext(const struct oxr_extension_status *extensions, XrVersion openxr_version, bool *out_supported, bool *out_enabled);\n''')
f.write(f''' f.write(f'''
#define PATHS_PER_BINDING_TEMPLATE 16 #define PATHS_PER_BINDING_TEMPLATE 16
@ -826,8 +854,8 @@ struct binding_template
\tenum xrt_output_name output; \tenum xrt_output_name output;
}}; }};
typedef bool (*path_verify_fn_t)(const struct oxr_extension_status *extensions, const char *, size_t); typedef bool (*path_verify_fn_t)(const struct oxr_extension_status *extensions, XrVersion openxr_version, const char *, size_t);
typedef void (*ext_verify_fn_t)(const struct oxr_extension_status *extensions, bool *out_supported, bool *out_enabled); typedef void (*ext_verify_fn_t)(const struct oxr_extension_status *extensions, XrVersion openxr_version, bool *out_supported, bool *out_enabled);
struct profile_template struct profile_template
{{ {{

View file

@ -53,7 +53,7 @@ process_dpad(struct oxr_logger *log,
dpad->binding); dpad->binding);
} }
if (!dpad_emulator_fn(&inst->extensions, str, length)) { if (!dpad_emulator_fn(&inst->extensions, inst->openxr_version.major_minor, str, length)) {
return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED, return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED,
"(%s->binding == \"%s\") is not a valid dpad binding path for profile \"%s\"", prefix, "(%s->binding == \"%s\") is not a valid dpad binding path for profile \"%s\"", prefix,
str, ip_str); str, ip_str);
@ -248,7 +248,7 @@ oxr_xrSuggestInteractionProfileBindings(XrInstance instance,
bool ext_supported; bool ext_supported;
bool ext_enabled; bool ext_enabled;
ext_verify_fn(&inst->extensions, &ext_supported, &ext_enabled); ext_verify_fn(&inst->extensions, inst->openxr_version.major_minor, &ext_supported, &ext_enabled);
if (!ext_supported) { if (!ext_supported) {
return oxr_error( return oxr_error(
&log, XR_ERROR_PATH_UNSUPPORTED, &log, XR_ERROR_PATH_UNSUPPORTED,
@ -286,12 +286,12 @@ oxr_xrSuggestInteractionProfileBindings(XrInstance instance,
i, s->binding); i, s->binding);
} }
if (subpath_fn(&inst->extensions, str, length)) { if (subpath_fn(&inst->extensions, inst->openxr_version.major_minor, str, length)) {
continue; continue;
} }
#ifdef XR_EXT_dpad_binding #ifdef XR_EXT_dpad_binding
if (dpad_path_fn(&inst->extensions, str, length)) { if (dpad_path_fn(&inst->extensions, inst->openxr_version.major_minor, str, length)) {
if (!has_dpad) { if (!has_dpad) {
return oxr_error( return oxr_error(
&log, XR_ERROR_PATH_UNSUPPORTED, &log, XR_ERROR_PATH_UNSUPPORTED,