From 4c82af83c4f80dbe4fd607c94c2a5bc54590cb1d Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sun, 28 Dec 2025 21:15:42 +0000 Subject: [PATCH] st/oxr: Improve oxr_bindings generation to use template files Part-of: --- .../oxr/oxr_bindings/CMakeLists.txt | 6 +- .../oxr/oxr_bindings/oxr_bindings.py | 172 ++++-------------- .../oxr_generated_bindings.c.template | 25 +++ .../oxr_generated_bindings.h.template | 97 ++++++++++ 4 files changed, 164 insertions(+), 136 deletions(-) create mode 100644 src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.c.template create mode 100644 src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.h.template diff --git a/src/xrt/state_trackers/oxr/oxr_bindings/CMakeLists.txt b/src/xrt/state_trackers/oxr/oxr_bindings/CMakeLists.txt index 07c2cf601..80592e090 100644 --- a/src/xrt/state_trackers/oxr/oxr_bindings/CMakeLists.txt +++ b/src/xrt/state_trackers/oxr/oxr_bindings/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright 2019-2025, Collabora, Ltd. +# Copyright 2025-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: BSL-1.0 # Binding generation: pass filename to generate @@ -14,7 +15,10 @@ function(oxr_bindings_gen output) ${CMAKE_CURRENT_SOURCE_DIR}/oxr_bindings.py ${AUX_BINDINGS_DIR}/bindings.json "${CMAKE_CURRENT_BINARY_DIR}/${output}" COMMAND_EXPAND_LISTS VERBATIM - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/oxr_bindings.py + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/oxr_bindings.py + ${CMAKE_CURRENT_SOURCE_DIR}/oxr_generated_bindings.c.template + ${CMAKE_CURRENT_SOURCE_DIR}/oxr_generated_bindings.h.template ${AUX_BINDINGS_DIR}/bindings.json COMMENT "Generating ${output}" ) diff --git a/src/xrt/state_trackers/oxr/oxr_bindings/oxr_bindings.py b/src/xrt/state_trackers/oxr/oxr_bindings/oxr_bindings.py index f4d914725..4b3885e44 100755 --- a/src/xrt/state_trackers/oxr/oxr_bindings/oxr_bindings.py +++ b/src/xrt/state_trackers/oxr/oxr_bindings/oxr_bindings.py @@ -7,6 +7,7 @@ from bindings import * import argparse +import os from operator import attrgetter from string import Template @@ -165,10 +166,9 @@ def get_verify_functions(profile): return ret -def generate_profile_template(profile): - """Generate a single profile_template entry. Returns a list of lines.""" +def generate_profile_template_entry(profile): + """Generate a single profile_template entry. Returns a string.""" lines = [] - hw_name = str(profile.name.split("/")[-1]) vendor_name = str(profile.name.split("/")[-2]) fname = vendor_name + "_" + hw_name + "_profile.json" @@ -284,142 +284,45 @@ def generate_profile_template(profile): lines.append('\t}, // /profile_template') - return lines + return '\n'.join(lines) -def generate_bindings_c(file, b): +def generate_bindings_c(output, b): """Generate the file to verify subpaths on a interaction profile.""" - lines = [] + script_dir = os.path.dirname(os.path.abspath(__file__)) + template_file = os.path.join(script_dir, 'oxr_generated_bindings.c.template') - lines.extend([ - header.format(brief='Generated bindings data', group='oxr_main'), - '#include "oxr_bindings/b_oxr_generated_bindings.h"', - '#include ', - '#include "oxr_objects.h"', - '', - '// clang-format off', - '', - ]) + with open(template_file, 'r') as f: + src = Template(f.read()) - # Add all verify functions + # Generate verify functions + lines = [] for profile in b.profiles: lines.extend(get_verify_functions(profile)) + verify_functions = '\n'.join(lines) - lines.extend([ - '', - '', - f'struct profile_template profile_templates[{len(b.profiles)}] = {{ // array of profile_template', - ]) + # Generate profile templates + profile_templates = '\n'.join(generate_profile_template_entry(profile) for profile in b.profiles) - # Add all profile templates - for profile in b.profiles: - lines.extend(generate_profile_template(profile)) + with open(output, "w", encoding="utf-8") as fp: + fp.write(src.substitute( + template_count=len(b.profiles), + verify_functions=verify_functions, + profile_templates=profile_templates + )) - lines.extend([ - '}; // /array of profile_template', - '', - '// clang-format on', - ]) - # Write all lines to file - with open(file, "w") as f: - f.write('\n'.join(lines) + '\n') - - -H_TEMPLATE = Template("""$header - -#pragma once - -#include -#include "xrt/xrt_defines.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef uint64_t XrPath; // OpenXR typedef' -typedef uint64_t XrVersion; // OpenXR typedef' - -struct oxr_extension_status; - -#define OXR_BINDINGS_PROFILE_TEMPLATE_COUNT $template_count - -// clang-format off - -$verify_protos - -#define PATHS_PER_BINDING_TEMPLATE 16 - -enum oxr_dpad_binding_point -{ -\tOXR_DPAD_BINDING_POINT_NONE, -\tOXR_DPAD_BINDING_POINT_UP, -\tOXR_DPAD_BINDING_POINT_DOWN, -\tOXR_DPAD_BINDING_POINT_LEFT, -\tOXR_DPAD_BINDING_POINT_RIGHT, -}; - -struct dpad_emulation -{ -\tconst char *subaction_path; -\tconst char *paths[PATHS_PER_BINDING_TEMPLATE]; -\tenum xrt_input_name position; -\tenum xrt_input_name activate; // Can be zero -}; - -struct binding_template -{ -\tconst char *subaction_path; -\tconst char *steamvr_path; -\tconst char *localized_name; -\tconst char *paths[PATHS_PER_BINDING_TEMPLATE]; -\tenum xrt_input_name input; -\tenum xrt_input_name dpad_activate; -\tenum xrt_output_name output; -}; - -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, XrVersion openxr_version, bool *out_supported, bool *out_enabled); - -struct profile_template -{ -\tenum xrt_device_name name; -\tconst char *path; -\tconst char *localized_name; -\tconst char *steamvr_input_profile_path; -\tconst char *steamvr_controller_type; -\tstruct binding_template *bindings; -\tsize_t binding_count; -\tstruct dpad_emulation *dpads; -\tsize_t dpad_count; -\tstruct { -\t\tstruct { -\t\t\tuint32_t major; -\t\t\tuint32_t minor; -\t\t} promoted; -\t} openxr_version; -\t//! path_cache is an INVALID value until oxr_instance_create initializes it. -\tXrPath path_cache; - -\tpath_verify_fn_t subpath_fn; -\tpath_verify_fn_t dpad_path_fn; -\tpath_verify_fn_t dpad_emulator_fn; -\text_verify_fn_t ext_verify_fn; -\tconst char *extension_name; -}; - -extern struct profile_template profile_templates[OXR_BINDINGS_PROFILE_TEMPLATE_COUNT]; -// clang-format on") -#ifdef __cplusplus -} -#endif -""") - -def generate_bindings_h(file, b): +def generate_bindings_h(output, b): """Generate header for the verify subpaths functions.""" + script_dir = os.path.dirname(os.path.abspath(__file__)) + template_file = os.path.join(script_dir, 'oxr_generated_bindings.h.template') + + with open(template_file, 'r') as f: + src = Template(f.read()) + + # Generate function prototypes verify_protos = [] fn_prefixes = ["_subpath", "_dpad_path", "_dpad_emulator"] - for profile in b.profiles: for fn_suffix in fn_prefixes: verify_protos.extend([ @@ -433,18 +336,15 @@ def generate_bindings_h(file, b): '', ]) - filled = H_TEMPLATE.substitute( - header=header.format(brief='Generated bindings data', group='oxr_main'), - template_count=len(b.profiles), - verify_protos='\n'.join(verify_protos) - ) - - with open(file, "w") as f: - f.write(filled) + with open(output, "w", encoding="utf-8") as fp: + fp.write(src.substitute( + template_count=len(b.profiles), + verify_protos='\n'.join(verify_protos) + )) def main(): - """Handle command line and generate a file.""" + """Handle command line and generate file(s).""" parser = argparse.ArgumentParser(description='OpenXR Bindings generator.') parser.add_argument( 'bindings', help='Bindings file to use') @@ -458,8 +358,10 @@ def main(): for output in args.output: if output.endswith("oxr_generated_bindings.c"): generate_bindings_c(output, bindings) - if output.endswith("oxr_generated_bindings.h"): + elif output.endswith("oxr_generated_bindings.h"): generate_bindings_h(output, bindings) + else: + raise ValueError(f"Unknown output file: {output}") if __name__ == "__main__": diff --git a/src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.c.template b/src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.c.template new file mode 100644 index 000000000..6e03af590 --- /dev/null +++ b/src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.c.template @@ -0,0 +1,25 @@ +// Copyright 2020-2025, Collabora, Ltd. +// Copyright 2024-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Generated bindings data. + * @author Jakob Bornecrantz + * @ingroup oxr_main + * + * GENERATED CODE - see src/xrt/state_trackers/oxr/oxr_bindings/! + */ + +#include "oxr_bindings/b_oxr_generated_bindings.h" +#include +#include "oxr_objects.h" + +// clang-format off + +$verify_functions + +struct profile_template profile_templates[$template_count] = { // array of profile_template +$profile_templates +}; // /array of profile_template + +// clang-format on diff --git a/src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.h.template b/src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.h.template new file mode 100644 index 000000000..b5e1e621c --- /dev/null +++ b/src/xrt/state_trackers/oxr/oxr_bindings/oxr_generated_bindings.h.template @@ -0,0 +1,97 @@ +// Copyright 2020-2025, Collabora, Ltd. +// Copyright 2024-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Generated bindings data. + * @author Jakob Bornecrantz + * @ingroup oxr_main + * + * GENERATED CODE - see src/xrt/state_trackers/oxr/oxr_bindings/! + */ + +#pragma once + +#include +#include "xrt/xrt_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint64_t XrPath; // OpenXR typedef' +typedef uint64_t XrVersion; // OpenXR typedef' + +struct oxr_extension_status; + +#define OXR_BINDINGS_PROFILE_TEMPLATE_COUNT $template_count + +// clang-format off + +$verify_protos + +#define PATHS_PER_BINDING_TEMPLATE 16 + +enum oxr_dpad_binding_point +{ + OXR_DPAD_BINDING_POINT_NONE, + OXR_DPAD_BINDING_POINT_UP, + OXR_DPAD_BINDING_POINT_DOWN, + OXR_DPAD_BINDING_POINT_LEFT, + OXR_DPAD_BINDING_POINT_RIGHT, +}; + +struct dpad_emulation +{ + const char *subaction_path; + const char *paths[PATHS_PER_BINDING_TEMPLATE]; + enum xrt_input_name position; + enum xrt_input_name activate; // Can be zero +}; + +struct binding_template +{ + const char *subaction_path; + const char *steamvr_path; + const char *localized_name; + const char *paths[PATHS_PER_BINDING_TEMPLATE]; + enum xrt_input_name input; + enum xrt_input_name dpad_activate; + enum xrt_output_name output; +}; + +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, XrVersion openxr_version, bool *out_supported, bool *out_enabled); + +struct profile_template +{ + enum xrt_device_name name; + const char *path; + const char *localized_name; + const char *steamvr_input_profile_path; + const char *steamvr_controller_type; + struct binding_template *bindings; + size_t binding_count; + struct dpad_emulation *dpads; + size_t dpad_count; + struct { + struct { + uint32_t major; + uint32_t minor; + } promoted; + } openxr_version; + //! path_cache is an INVALID value until oxr_instance_create initializes it. + XrPath path_cache; + + path_verify_fn_t subpath_fn; + path_verify_fn_t dpad_path_fn; + path_verify_fn_t dpad_emulator_fn; + ext_verify_fn_t ext_verify_fn; + const char *extension_name; +}; + +extern struct profile_template profile_templates[OXR_BINDINGS_PROFILE_TEMPLATE_COUNT]; +// clang-format on +#ifdef __cplusplus +} +#endif -- 2.54.0