From 4a65e88e68a67254dcf3dd5d4e5d14ff4cf402d3 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 11 Nov 2025 14:57:47 +0000 Subject: [PATCH] ipc: Get tracking origins ready to be hot-addable Part-of: --- src/xrt/ipc/CMakeLists.txt | 6 +- src/xrt/ipc/client/ipc_client.h | 9 +- src/xrt/ipc/client/ipc_client_instance.c | 42 +++--- .../ipc/client/ipc_client_system_devices.c | 20 ++- .../ipc/client/ipc_client_tracking_origin.c | 127 ++++++++++++++++++ .../ipc/client/ipc_client_tracking_origin.h | 70 ++++++++++ src/xrt/ipc/server/ipc_server.h | 16 ++- src/xrt/ipc/server/ipc_server_handler.c | 87 +++++++----- src/xrt/ipc/server/ipc_server_objects.c | 67 +++++++++ src/xrt/ipc/server/ipc_server_objects.h | 48 +++++++ .../ipc/server/ipc_server_per_client_thread.c | 11 +- src/xrt/ipc/server/ipc_server_process.c | 62 +++------ src/xrt/ipc/shared/ipc_protocol.h | 43 +++--- src/xrt/ipc/shared/proto/50-tracking.json | 18 +++ .../ipc/shared/proto/50-tracking.json.license | 3 + src/xrt/targets/libmonado/monado.c | 85 ++++++++++-- src/xrt/targets/libmonado/monado.h | 13 +- 17 files changed, 582 insertions(+), 145 deletions(-) create mode 100644 src/xrt/ipc/client/ipc_client_tracking_origin.c create mode 100644 src/xrt/ipc/client/ipc_client_tracking_origin.h create mode 100644 src/xrt/ipc/server/ipc_server_objects.c create mode 100644 src/xrt/ipc/server/ipc_server_objects.h create mode 100644 src/xrt/ipc/shared/proto/50-tracking.json create mode 100644 src/xrt/ipc/shared/proto/50-tracking.json.license diff --git a/src/xrt/ipc/CMakeLists.txt b/src/xrt/ipc/CMakeLists.txt index 21ad6031e..e81a023d6 100644 --- a/src/xrt/ipc/CMakeLists.txt +++ b/src/xrt/ipc/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright 2020-2021, Collabora, Ltd. -# Copyright 2025, NVIDIA CORPORATION. +# Copyright 2025-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: BSL-1.0 ### @@ -100,6 +100,8 @@ add_library( client/ipc_client_space_overseer.c client/ipc_client_system.c client/ipc_client_system_devices.c + client/ipc_client_tracking_origin.c + client/ipc_client_tracking_origin.h client/ipc_client_xdev.c client/ipc_client_xdev.h ) @@ -133,6 +135,8 @@ add_library( server/ipc_server_handler.c server/ipc_server_per_client_thread.c server/ipc_server_process.c + server/ipc_server_objects.c + server/ipc_server_objects.h ) target_include_directories( ipc_server diff --git a/src/xrt/ipc/client/ipc_client.h b/src/xrt/ipc/client/ipc_client.h index 9c64a832c..4aafcf79b 100644 --- a/src/xrt/ipc/client/ipc_client.h +++ b/src/xrt/ipc/client/ipc_client.h @@ -1,5 +1,5 @@ // Copyright 2020-2023, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -23,6 +23,8 @@ #include "shared/ipc_protocol.h" #include "shared/ipc_message_channel.h" +#include "ipc_client_tracking_origin.h" + #include @@ -82,9 +84,8 @@ struct ipc_client_system_devices //! Connection to service. struct ipc_connection *ipc_c; - struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES]; - - size_t xtrack_count; + //! Tracking origin manager for on-demand fetching + struct ipc_client_tracking_origin_manager tracking_origin_manager; struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM]; }; diff --git a/src/xrt/ipc/client/ipc_client_instance.c b/src/xrt/ipc/client/ipc_client_instance.c index 1def21f0a..937800c9d 100644 --- a/src/xrt/ipc/client/ipc_client_instance.c +++ b/src/xrt/ipc/client/ipc_client_instance.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -31,6 +31,7 @@ #include "client/ipc_client.h" #include "client/ipc_client_interface.h" #include "client/ipc_client_connection.h" +#include "client/ipc_client_tracking_origin.h" #include "ipc_client_generated.h" @@ -163,32 +164,27 @@ ipc_client_instance_create_system(struct xrt_instance *xinst, struct xrt_system_devices *xsysd = &icsd->base.base; - uint32_t count = 0; - struct xrt_tracking_origin *xtrack = NULL; struct ipc_shared_memory *ism = ii->ipc_c.ism; - // Query the server for how many tracking origins it has. - count = 0; - for (uint32_t i = 0; i < ism->itrack_count; i++) { - xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin); - - memcpy(xtrack->name, ism->itracks[i].name, sizeof(xtrack->name)); - - xtrack->type = ism->itracks[i].type; - xtrack->initial_offset = ism->itracks[i].offset; - icsd->xtracks[count++] = xtrack; - - u_var_add_root(xtrack, "Tracking origin", true); - u_var_add_ro_text(xtrack, xtrack->name, "name"); - u_var_add_pose(xtrack, &xtrack->initial_offset, "offset"); - } - icsd->xtrack_count = count; - - // Query the server for how many devices it has. - count = 0; + // Query the server for how many devices it has and create them. + uint32_t count = 0; for (uint32_t i = 0; i < ism->isdev_count; i++) { struct ipc_shared_device *isdev = &ism->isdevs[i]; - xtrack = icsd->xtracks[isdev->tracking_origin_index]; + + // Get tracking origin from manager (fetches on-demand) + struct xrt_tracking_origin *xtrack = NULL; + xret = ipc_client_tracking_origin_manager_get(&icsd->tracking_origin_manager, isdev->tracking_origin_id, + &xtrack); + if (xret != XRT_SUCCESS) { + IPC_ERROR(&ii->ipc_c, "Failed to get tracking origin for device %u (id %u)", i, + isdev->tracking_origin_id); + continue; + } + if (xtrack == NULL) { + IPC_ERROR(&ii->ipc_c, "Tracking origin for device %u (id %u) is NULL", i, + isdev->tracking_origin_id); + continue; + } if (isdev->device_type == XRT_DEVICE_TYPE_HMD) { xsysd->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i); diff --git a/src/xrt/ipc/client/ipc_client_system_devices.c b/src/xrt/ipc/client/ipc_client_system_devices.c index 6126e5271..38d3db766 100644 --- a/src/xrt/ipc/client/ipc_client_system_devices.c +++ b/src/xrt/ipc/client/ipc_client_system_devices.c @@ -1,5 +1,5 @@ // Copyright 2023, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -10,6 +10,7 @@ */ #include "ipc_client.h" +#include "ipc_client_tracking_origin.h" #include "ipc_client_generated.h" #include "util/u_system_helpers.h" @@ -83,12 +84,8 @@ ipc_client_system_devices_destroy(struct xrt_system_devices *xsysd) { struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd); - for (size_t i = 0; i < usysd->xtrack_count; i++) { - u_var_remove_root(usysd->xtracks[i]); - free(usysd->xtracks[i]); - usysd->xtracks[i] = NULL; - } - usysd->xtrack_count = 0; + // Finalize the tracking origin manager (which cleans up all cached tracking origins) + ipc_client_tracking_origin_manager_fini(&usysd->tracking_origin_manager); u_system_devices_close(&usysd->base.base); @@ -112,7 +109,16 @@ ipc_client_system_devices_create(struct ipc_connection *ipc_c, struct ipc_client icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec; icsd->ipc_c = ipc_c; + // Initialize tracking origin manager + xrt_result_t xret = ipc_client_tracking_origin_manager_init(&icsd->tracking_origin_manager, ipc_c); + IPC_CHK_WITH_GOTO(ipc_c, xret, "ipc_client_tracking_origin_manager_init", err_free); + *out_icsd = icsd; return XRT_SUCCESS; + +err_free: + free(icsd); + + return xret; } diff --git a/src/xrt/ipc/client/ipc_client_tracking_origin.c b/src/xrt/ipc/client/ipc_client_tracking_origin.c new file mode 100644 index 000000000..0e3f1650b --- /dev/null +++ b/src/xrt/ipc/client/ipc_client_tracking_origin.c @@ -0,0 +1,127 @@ +// Copyright 2025-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief IPC Client tracking origin management. + * @author Jakob Bornecrantz + * @ingroup ipc_client + */ + +#include "xrt/xrt_defines.h" +#include "xrt/xrt_tracking.h" + +#include "util/u_misc.h" +#include "util/u_var.h" +#include "util/u_hashmap.h" + +#include + +#include "shared/ipc_message_channel.h" +#include "shared/ipc_protocol.h" + +#include "client/ipc_client.h" +#include "client/ipc_client_connection.h" +#include "client/ipc_client_tracking_origin.h" + +#include "ipc_client_generated.h" + + +/* + * + * Helper functions + * + */ + +static void +tracking_origin_cleanup_callback(void *item, void *priv) +{ + struct xrt_tracking_origin *xtrack = (struct xrt_tracking_origin *)item; + + // Remove from variable tracking + u_var_remove_root(xtrack); + + // Free the tracking origin + free(xtrack); +} + + +/* + * + * Exported functions + * + */ + +xrt_result_t +ipc_client_tracking_origin_manager_init(struct ipc_client_tracking_origin_manager *manager, + struct ipc_connection *ipc_c) +{ + assert(manager != NULL); + assert(ipc_c != NULL); + + manager->ipc_c = ipc_c; + manager->tracking_origin_map = NULL; + + int ret = u_hashmap_int_create(&manager->tracking_origin_map); + if (ret != 0) { + IPC_ERROR(ipc_c, "Failed to create tracking origin hashmap"); + return XRT_ERROR_ALLOCATION; + } + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_client_tracking_origin_manager_get(struct ipc_client_tracking_origin_manager *manager, + uint32_t tracking_origin_id, + struct xrt_tracking_origin **out_xtrack) +{ + // Check if we already have this tracking origin cached + void *cached_xtrack = NULL; + int ret = u_hashmap_int_find(manager->tracking_origin_map, tracking_origin_id, &cached_xtrack); + if (ret == 0) { + // Found in cache + *out_xtrack = (struct xrt_tracking_origin *)cached_xtrack; + return XRT_SUCCESS; + } + + // Not in cache, fetch from server + struct ipc_tracking_origin_info info; + xrt_result_t xret = ipc_call_tracking_origin_get_info(manager->ipc_c, tracking_origin_id, &info); + IPC_CHK_AND_RET(manager->ipc_c, xret, "ipc_call_tracking_origin_get_info"); + + // Create a new tracking origin + struct xrt_tracking_origin *xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin); + + memcpy(xtrack->name, info.name, sizeof(xtrack->name)); + xtrack->type = info.type; + xtrack->initial_offset = info.offset; + + // Add to variable tracking + u_var_add_root(xtrack, "Tracking origin", true); + u_var_add_ro_text(xtrack, xtrack->name, "name"); + u_var_add_pose(xtrack, &xtrack->initial_offset, "offset"); + + // Store in cache + u_hashmap_int_insert(manager->tracking_origin_map, tracking_origin_id, xtrack); + + *out_xtrack = xtrack; + + return XRT_SUCCESS; +} + +void +ipc_client_tracking_origin_manager_fini(struct ipc_client_tracking_origin_manager *manager) +{ + assert(manager != NULL); + assert(manager->ipc_c != NULL); + + // Clean up all cached tracking origins + if (manager->tracking_origin_map != NULL) { + u_hashmap_int_clear_and_call_for_each(manager->tracking_origin_map, tracking_origin_cleanup_callback, + NULL); + u_hashmap_int_destroy(&manager->tracking_origin_map); + manager->tracking_origin_map = NULL; + } + + manager->ipc_c = NULL; +} diff --git a/src/xrt/ipc/client/ipc_client_tracking_origin.h b/src/xrt/ipc/client/ipc_client_tracking_origin.h new file mode 100644 index 000000000..7cd71bb1e --- /dev/null +++ b/src/xrt/ipc/client/ipc_client_tracking_origin.h @@ -0,0 +1,70 @@ +// Copyright 2025-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief IPC Client tracking origin management. + * @author Jakob Bornecrantz + * @ingroup ipc_client + */ + +#pragma once + +#include "xrt/xrt_tracking.h" +#include "util/u_hashmap.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +struct ipc_connection; + +/*! + * Tracking origin manager for IPC client. + * + * Maintains a hashmap of tracking origin IDs to xrt_tracking_origin objects. + * Fetches tracking origin info from the server on-demand. + * + * @ingroup ipc_client + */ +struct ipc_client_tracking_origin_manager +{ + //! Connection to the IPC server + struct ipc_connection *ipc_c; + + //! Hashmap from tracking_origin_id to xrt_tracking_origin* + struct u_hashmap_int *tracking_origin_map; +}; + +/*! + * Initialize a tracking origin manager. + * + * @ingroup ipc_client + */ +xrt_result_t +ipc_client_tracking_origin_manager_init(struct ipc_client_tracking_origin_manager *manager, + struct ipc_connection *ipc_c); + +/*! + * Get a tracking origin by ID. If not already cached, fetches it from the server. + * + * @ingroup ipc_client + */ +xrt_result_t +ipc_client_tracking_origin_manager_get(struct ipc_client_tracking_origin_manager *manager, + uint32_t tracking_origin_id, + struct xrt_tracking_origin **out_xtrack); + +/*! + * Finalize the tracking origin manager and all cached tracking origins. + * + * @ingroup ipc_client + */ +void +ipc_client_tracking_origin_manager_fini(struct ipc_client_tracking_origin_manager *manager); + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index e68ad9aaf..0ae825048 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -1,5 +1,5 @@ // Copyright 2020-2023, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -20,6 +20,7 @@ #include "os/os_threading.h" #include "util/u_logging.h" +#include "util/u_hashmap.h" #include "shared/ipc_protocol.h" #include "shared/ipc_message_channel.h" @@ -96,6 +97,18 @@ struct ipc_client_state //! Has the system part of the shm initialized. bool has_init_shm_system; + struct + { + /*! + * Array of tracking origins. + * + * We don't control the lifetime of the tracking origins, + * and we only access it from the per client thread, + * so we don't need to lock it. + */ + struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES]; + } objects; + //! Session for this client. struct xrt_session *xs; @@ -370,7 +383,6 @@ struct ipc_server struct xrt_system_compositor *xsysc; struct ipc_device idevs[XRT_SYSTEM_MAX_DEVICES]; - struct xrt_tracking_origin *xtracks[XRT_SYSTEM_MAX_DEVICES]; struct ipc_shared_memory *isms[IPC_MAX_CLIENTS]; diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index 2fe1ba3b4..c6d57c4c9 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -17,6 +17,7 @@ #include "util/u_trace_marker.h" #include "server/ipc_server.h" +#include "server/ipc_server_objects.h" #include "ipc_server_generated.h" #include "xrt/xrt_device.h" #include "xrt/xrt_results.h" @@ -32,6 +33,12 @@ * */ +#define GET_XTRACK_OR_RETURN(ICS, ID, XTRACK) \ + do { \ + xrt_result_t xret = ipc_server_objects_get_xtrack_and_validate((ICS), ID, &(XTRACK)); \ + IPC_CHK_AND_RET((ICS)->server, xret, "ipc_server_objects_get_xtrack_and_validate"); \ + } while (0) + static xrt_result_t validate_device_id(volatile struct ipc_client_state *ics, int64_t device_id, struct xrt_device **out_device) { @@ -59,26 +66,6 @@ validate_device_id(volatile struct ipc_client_state *ics, int64_t device_id, str } \ } while (0) - -static xrt_result_t -validate_origin_id(volatile struct ipc_client_state *ics, int64_t origin_id, struct xrt_tracking_origin **out_xtrack) -{ - if (origin_id >= XRT_SYSTEM_MAX_DEVICES) { - IPC_ERROR(ics->server, "Invalid origin ID (origin_id >= XRT_SYSTEM_MAX_DEVICES)!"); - return XRT_ERROR_IPC_FAILURE; - } - - struct xrt_tracking_origin *xtrack = ics->server->xtracks[origin_id]; - if (xtrack == NULL) { - IPC_ERROR(ics->server, "Invalid origin ID (xtrack is NULL)!"); - return XRT_ERROR_IPC_FAILURE; - } - - *out_xtrack = xtrack; - - return XRT_SUCCESS; -} - static xrt_result_t validate_swapchain_state(volatile struct ipc_client_state *ics, uint32_t *out_index) { @@ -946,11 +933,9 @@ ipc_handle_space_get_tracking_origin_offset(volatile struct ipc_client_state *ic struct xrt_pose *out_offset) { struct xrt_space_overseer *xso = ics->server->xso; - struct xrt_tracking_origin *xto; - xrt_result_t xret = validate_origin_id(ics, origin_id, &xto); - if (xret != XRT_SUCCESS) { - return xret; - } + struct xrt_tracking_origin *xto = NULL; + GET_XTRACK_OR_RETURN(ics, origin_id, xto); + return xrt_space_overseer_get_tracking_origin_offset(xso, xto, out_offset); } @@ -960,11 +945,9 @@ ipc_handle_space_set_tracking_origin_offset(volatile struct ipc_client_state *ic const struct xrt_pose *offset) { struct xrt_space_overseer *xso = ics->server->xso; - struct xrt_tracking_origin *xto; - xrt_result_t xret = validate_origin_id(ics, origin_id, &xto); - if (xret != XRT_SUCCESS) { - return xret; - } + struct xrt_tracking_origin *xto = NULL; + GET_XTRACK_OR_RETURN(ics, origin_id, xto); + return xrt_space_overseer_set_tracking_origin_offset(xso, xto, offset); } @@ -1922,6 +1905,48 @@ ipc_handle_compositor_semaphore_destroy(volatile struct ipc_client_state *ics, u } +/* + * + * Tracking origin functions. + * + */ + +xrt_result_t +ipc_handle_tracking_origin_get_list(volatile struct ipc_client_state *ics, struct ipc_tracking_origin_list *out_list) +{ + // Count and collect origin IDs. + uint32_t count = 0; + for (uint32_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { + struct xrt_tracking_origin *xtrack = ics->objects.xtracks[i]; + if (xtrack != NULL) { + out_list->origins[count].id = i; + count++; + } + } + + out_list->origin_count = count; + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_handle_tracking_origin_get_info(volatile struct ipc_client_state *ics, + uint32_t tracking_origin_id, + struct ipc_tracking_origin_info *out_info) +{ + // Validate the tracking origin ID and get the tracking origin + struct xrt_tracking_origin *xtrack = NULL; + GET_XTRACK_OR_RETURN(ics, tracking_origin_id, xtrack); + + // Copy tracking origin info to output + memcpy(out_info->name, xtrack->name, sizeof(out_info->name)); + out_info->type = xtrack->type; + out_info->offset = xtrack->initial_offset; + + return XRT_SUCCESS; +} + + /* * * Device functions. diff --git a/src/xrt/ipc/server/ipc_server_objects.c b/src/xrt/ipc/server/ipc_server_objects.c new file mode 100644 index 000000000..f5bed1ec6 --- /dev/null +++ b/src/xrt/ipc/server/ipc_server_objects.c @@ -0,0 +1,67 @@ +// Copyright 2025-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Tracking objects to IDs. + * @author Jakob Bornecrantz + * @ingroup ipc_server + */ + +#include "xrt/xrt_tracking.h" + +#include "ipc_server.h" +#include "ipc_server_objects.h" + + +/* + * + * Tracking origin functions. + * + */ + +xrt_result_t +ipc_server_objects_get_xtrack_and_validate(volatile struct ipc_client_state *ics, + uint32_t id, + struct xrt_tracking_origin **out_xtrack) +{ + if (id >= XRT_SYSTEM_MAX_DEVICES) { + IPC_ERROR(ics->server, "Invalid tracking origin ID %u (>= XRT_SYSTEM_MAX_DEVICES)", id); + return XRT_ERROR_IPC_FAILURE; + } + + struct xrt_tracking_origin *xtrack = ics->objects.xtracks[id]; + if (xtrack == NULL) { + IPC_ERROR(ics->server, "Tracking origin ID %u not found (NULL)", id); + return XRT_ERROR_IPC_FAILURE; + } + + *out_xtrack = xtrack; + + return XRT_SUCCESS; +} + +xrt_result_t +ipc_server_objects_get_xtrack_id_or_add(volatile struct ipc_client_state *ics, + struct xrt_tracking_origin *xtrack, + uint32_t *out_id) +{ + assert(out_id != NULL); + + // Find the next available slot in xtracks array and assign an ID, or if we find the xtrack return it. + for (uint32_t index = 0; index < XRT_SYSTEM_MAX_DEVICES; index++) { + if (ics->objects.xtracks[index] == NULL) { + ics->objects.xtracks[index] = xtrack; + *out_id = index; + return XRT_SUCCESS; + } + if (ics->objects.xtracks[index] == xtrack) { + *out_id = index; + return XRT_SUCCESS; + } + } + + // No available slot or xtrack found + IPC_ERROR(ics->server, "Failed to find available slot for tracking origin: '%s'", xtrack->name); + + return XRT_ERROR_IPC_FAILURE; +} diff --git a/src/xrt/ipc/server/ipc_server_objects.h b/src/xrt/ipc/server/ipc_server_objects.h new file mode 100644 index 000000000..4e87e0eee --- /dev/null +++ b/src/xrt/ipc/server/ipc_server_objects.h @@ -0,0 +1,48 @@ +// Copyright 2025-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Tracking objects to IDs. + * @author Jakob Bornecrantz + * @ingroup ipc_server + */ + +#pragma once + +#include "xrt/xrt_results.h" + +struct ipc_client_state; + + +/*! + * Get a tracking origin by ID, must only be called from the per client + * thread as this function accesses the client state's memory. + * + * @param ics The client state instance. + * @param id The tracking origin ID. + * @param out_xtrack Will be filled with the tracking origin object on success. + * @return XRT_SUCCESS on success, some other result on failure. + * + * @ingroup ipc_server + */ +xrt_result_t +ipc_server_objects_get_xtrack_and_validate(volatile struct ipc_client_state *ics, + uint32_t id, + struct xrt_tracking_origin **out_xtrack); + +/*! + * Get a tracking origin ID for a given tracking origin object, must only be + * called from the per client thread as this function accesses the client + * state's memory. + * + * @param ics The client state instance. + * @param xtrack The tracking origin object. + * @param out_id Will be filled with the tracking origin ID on success. + * @return XRT_SUCCESS on success, some other result on failure. + * + * @ingroup ipc_server + */ +xrt_result_t +ipc_server_objects_get_xtrack_id_or_add(volatile struct ipc_client_state *ics, + struct xrt_tracking_origin *xtrack, + uint32_t *out_id); diff --git a/src/xrt/ipc/server/ipc_server_per_client_thread.c b/src/xrt/ipc/server/ipc_server_per_client_thread.c index b2d221a84..e2d3b67d4 100644 --- a/src/xrt/ipc/server/ipc_server_per_client_thread.c +++ b/src/xrt/ipc/server/ipc_server_per_client_thread.c @@ -1,5 +1,5 @@ // Copyright 2020-2023, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -133,6 +133,15 @@ common_shutdown(volatile struct ipc_client_state *ics) ics->device_feature_used[i] = false; } + // Clear the tracking origins array. + for (uint32_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { + /* + * We don't control the lifetime of the tracking origins, + * so we just set the pointer to NULL. + */ + ics->objects.xtracks[i] = NULL; + } + // Make sure undestroyed plane detections are cleaned up for (uint32_t i = 0; i < ics->plane_detection_count; i++) { xrt_device_destroy_plane_detection_ext(ics->plane_detection_xdev[i], ics->plane_detection_ids[i]); diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 0a0f2d657..e0a40f0f6 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -1,5 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. -// Copyright 2024-2025, NVIDIA CORPORATION. +// Copyright 2024-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -33,6 +33,7 @@ #include "shared/ipc_protocol.h" #include "shared/ipc_shmem.h" #include "server/ipc_server.h" +#include "server/ipc_server_objects.h" #include "server/ipc_server_interface.h" #include @@ -218,8 +219,10 @@ teardown_all(struct ipc_server *s) } static void -init_tracking_origins(struct ipc_server *s) +init_tracking_origins(volatile struct ipc_client_state *ics) { + struct ipc_server *s = ics->server; + for (size_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { struct xrt_device *xdev = s->idevs[i].xdev; if (xdev == NULL) { @@ -228,16 +231,13 @@ init_tracking_origins(struct ipc_server *s) struct xrt_tracking_origin *xtrack = xdev->tracking_origin; assert(xtrack != NULL); - size_t index = 0; - for (; index < XRT_SYSTEM_MAX_DEVICES; index++) { - if (s->xtracks[index] == NULL) { - s->xtracks[index] = xtrack; - break; - } - if (s->xtracks[index] == xtrack) { - break; - } + // Get or add tracking origin ID + uint32_t tracking_origin_id = 0; + xrt_result_t xret = ipc_server_objects_get_xtrack_id_or_add(ics, xtrack, &tracking_origin_id); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to get/add tracking origin ID for: '%s'", xtrack->name); + continue; } } } @@ -318,25 +318,8 @@ init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs uint32_t count = 0; struct ipc_shared_memory *ism = s->isms[cs->server_thread_index]; - // Setup the tracking origins. - count = 0; - for (size_t i = 0; i < XRT_SYSTEM_MAX_DEVICES; i++) { - struct xrt_tracking_origin *xtrack = s->xtracks[i]; - if (xtrack == NULL) { - continue; - } - - // The position of the tracking origin matches that in the - // server's memory. - assert(i < XRT_SYSTEM_MAX_DEVICES); - - struct ipc_shared_tracking_origin *itrack = &ism->itracks[count++]; - memcpy(itrack->name, xtrack->name, sizeof(itrack->name)); - itrack->type = xtrack->type; - itrack->offset = xtrack->initial_offset; - } - - ism->itrack_count = count; + // Tracking origins are no longer copied to shared memory. + // They are fetched on-demand via IPC calls. count = 0; uint32_t input_index = 0; @@ -361,18 +344,13 @@ init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs isdev->device_type = xdev->device_type; isdev->supported = xdev->supported; - // Setup the tracking origin. - isdev->tracking_origin_index = (uint32_t)-1; - for (uint32_t k = 0; k < XRT_SYSTEM_MAX_DEVICES; k++) { - if (xdev->tracking_origin != s->xtracks[k]) { - continue; - } - - isdev->tracking_origin_index = k; - break; - } + // Setup the tracking origin ID. + uint32_t tracking_origin_id = UINT32_MAX; + xrt_result_t xret = + ipc_server_objects_get_xtrack_id_or_add(cs, xdev->tracking_origin, &tracking_origin_id); + assert(xret == XRT_SUCCESS); - assert(isdev->tracking_origin_index != (uint32_t)-1); + isdev->tracking_origin_id = tracking_origin_id; // Initial update. xrt_device_update_inputs(xdev); @@ -843,11 +821,11 @@ ipc_server_init_system_if_available_locked(struct ipc_server *s, // Always succeeds. init_idevs(s); - init_tracking_origins(s); } } if (available && ics != NULL && !ics->has_init_shm_system) { + init_tracking_origins(ics); init_system_shm_state(s, ics); ics->has_init_shm_system = true; } diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index 4cdb4accf..2cf5e4d1e 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -1,5 +1,5 @@ // Copyright 2020-2024 Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -59,12 +59,37 @@ typedef int pid_t; * */ +/*! + * Information about a device in the device list. + * + * @ingroup ipc + */ +struct ipc_tracking_origin_list_entry +{ + //! Tracking origin ID + uint32_t id; +}; + +/*! + * A list of the current tracking origins. + * + * @ingroup ipc + */ +struct ipc_tracking_origin_list +{ + //! Number of tracking origins. + uint32_t origin_count; + + //! Compact list of tracking origins. + struct ipc_tracking_origin_list_entry origins[XRT_SYSTEM_MAX_DEVICES]; +}; + /*! * A tracking in the shared memory area. * * @ingroup ipc */ -struct ipc_shared_tracking_origin +struct ipc_tracking_origin_info { //! For debugging. char name[XRT_TRACKING_NAME_LEN]; @@ -108,7 +133,7 @@ struct ipc_shared_device enum xrt_device_type device_type; //! Which tracking system origin is this device attached to. - uint32_t tracking_origin_index; + uint32_t tracking_origin_id; //! A string describing the device. char str[XRT_DEVICE_NAME_LEN]; @@ -195,18 +220,6 @@ struct ipc_shared_memory */ char u_git_tag[IPC_VERSION_NAME_LEN]; - /*! - * Number of elements in @ref itracks that are populated/valid. - */ - uint32_t itrack_count; - - /*! - * @brief Array of shared tracking origin data. - * - * Only @ref itrack_count elements are populated/valid. - */ - struct ipc_shared_tracking_origin itracks[XRT_SYSTEM_MAX_DEVICES]; - /*! * Number of elements in @ref isdevs that are populated/valid. */ diff --git a/src/xrt/ipc/shared/proto/50-tracking.json b/src/xrt/ipc/shared/proto/50-tracking.json new file mode 100644 index 000000000..e46d54757 --- /dev/null +++ b/src/xrt/ipc/shared/proto/50-tracking.json @@ -0,0 +1,18 @@ +{ + "$schema": "../proto.schema.json", + + "tracking_origin_get_list": { + "out": [ + {"name": "list", "type": "struct ipc_tracking_origin_list"} + ] + }, + + "tracking_origin_get_info": { + "in": [ + {"name": "tracking_origin_id", "type": "uint32_t"} + ], + "out": [ + {"name": "info", "type": "struct ipc_tracking_origin_info"} + ] + } +} diff --git a/src/xrt/ipc/shared/proto/50-tracking.json.license b/src/xrt/ipc/shared/proto/50-tracking.json.license new file mode 100644 index 000000000..feed63d38 --- /dev/null +++ b/src/xrt/ipc/shared/proto/50-tracking.json.license @@ -0,0 +1,3 @@ +Copyright 2025-2026, NVIDIA CORPORATION. + +SPDX-License-Identifier: BSL-1.0 diff --git a/src/xrt/targets/libmonado/monado.c b/src/xrt/targets/libmonado/monado.c index 5a9335f32..221a17592 100644 --- a/src/xrt/targets/libmonado/monado.c +++ b/src/xrt/targets/libmonado/monado.c @@ -1,5 +1,5 @@ // Copyright 2019-2024, Collabora, Ltd. -// Copyright 2025, NVIDIA CORPORATION. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -36,6 +36,12 @@ struct mnd_root //! List of clients. struct ipc_client_list clients; + //! The retrieved list of tracking origins. + struct ipc_tracking_origin_list tracking_origin_list; + + //! Cached infos about tracking origins. + struct ipc_tracking_origin_info origin_infos[XRT_SYSTEM_MAX_DEVICES]; + /// State of most recent app asked about struct ipc_app_state app_state; }; @@ -87,6 +93,14 @@ enum role_enum } \ } while (false) +#define CHECK_ORIGIN_INDEX(INDEX) \ + do { \ + if (INDEX >= root->tracking_origin_list.origin_count) { \ + PE("Invalid itrack index (%u)\n", INDEX); \ + return MND_ERROR_INVALID_VALUE; \ + } \ + } while (false) + #define CHECK_DEVICE_INDEX(INDEX) \ do { \ if (INDEX >= root->ipc_c.ism->isdev_count) { \ @@ -95,6 +109,7 @@ enum role_enum } \ } while (false) + static int get_client_info(mnd_root_t *root, uint32_t client_id) { @@ -109,6 +124,28 @@ get_client_info(mnd_root_t *root, uint32_t client_id) return MND_SUCCESS; } +static mnd_result_t +update_tracking_origin_list_and_infos(mnd_root_t *root) +{ + xrt_result_t xret = ipc_call_tracking_origin_get_list(&root->ipc_c, &root->tracking_origin_list); + if (xret != XRT_SUCCESS) { + PE("Failed ipc_call_tracking_origin_get_list '%i'", xret); + return MND_ERROR_OPERATION_FAILED; + } + + for (uint32_t i = 0; i < root->tracking_origin_list.origin_count; i++) { + uint32_t id = root->tracking_origin_list.origins[i].id; + + xret = ipc_call_tracking_origin_get_info(&root->ipc_c, id, &root->origin_infos[i]); + if (xret != XRT_SUCCESS) { + PE("Failed ipc_call_tracking_origin_get_list '%i'", xret); + return MND_ERROR_OPERATION_FAILED; + } + } + + return MND_SUCCESS; +} + /* * @@ -158,6 +195,12 @@ mnd_root_create(mnd_root_t **out_root) PE("System isn't available, devices won't be available!"); } + mnd_result_t mret = update_tracking_origin_list_and_infos(r); + if (mret != MND_SUCCESS) { + mnd_root_destroy(&r); + return mret; + } + *out_root = r; return MND_SUCCESS; @@ -369,7 +412,15 @@ mnd_root_get_device_info_u32(mnd_root_t *root, uint32_t device_index, mnd_proper const struct ipc_shared_device *shared_device = &root->ipc_c.ism->isdevs[device_index]; switch (prop) { - case MND_PROPERTY_TRACKING_ORIGIN_U32: *out_u32 = shared_device->tracking_origin_index; break; + case MND_PROPERTY_TRACKING_ORIGIN_U32: + for (uint32_t i = 0; i < root->tracking_origin_list.origin_count; i++) { + if (shared_device->tracking_origin_id == root->tracking_origin_list.origins[i].id) { + *out_u32 = i; + return MND_SUCCESS; + } + } + PE("Could not find tracking origin id in origins list '%u'!\n", shared_device->tracking_origin_id); + return MND_ERROR_INVALID_VALUE; default: PE("Is not a valid u32 property (%u)", prop); return MND_ERROR_INVALID_PROPERTY; } @@ -538,8 +589,14 @@ mnd_root_set_reference_space_offset(mnd_root_t *root, mnd_reference_space_type_t } mnd_result_t -mnd_root_get_tracking_origin_offset(mnd_root_t *root, uint32_t origin_id, mnd_pose_t *out_offset) +mnd_root_get_tracking_origin_offset(mnd_root_t *root, uint32_t origin_index, mnd_pose_t *out_offset) { + CHECK_NOT_NULL(root); + CHECK_NOT_NULL(out_offset); + CHECK_ORIGIN_INDEX(origin_index); + + uint32_t origin_id = root->tracking_origin_list.origins[origin_index].id; + xrt_result_t xret = ipc_call_space_get_tracking_origin_offset(&root->ipc_c, origin_id, (struct xrt_pose *)out_offset); switch (xret) { @@ -551,8 +608,14 @@ mnd_root_get_tracking_origin_offset(mnd_root_t *root, uint32_t origin_id, mnd_po } mnd_result_t -mnd_root_set_tracking_origin_offset(mnd_root_t *root, uint32_t origin_id, const mnd_pose_t *offset) +mnd_root_set_tracking_origin_offset(mnd_root_t *root, uint32_t origin_index, const mnd_pose_t *offset) { + CHECK_NOT_NULL(root); + CHECK_NOT_NULL(offset); + CHECK_ORIGIN_INDEX(origin_index); + + uint32_t origin_id = root->tracking_origin_list.origins[origin_index].id; + xrt_result_t xret = ipc_call_space_set_tracking_origin_offset(&root->ipc_c, origin_id, (struct xrt_pose *)offset); switch (xret) { @@ -569,25 +632,21 @@ mnd_root_get_tracking_origin_count(mnd_root_t *root, uint32_t *out_track_count) CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_track_count); - *out_track_count = root->ipc_c.ism->itrack_count; + *out_track_count = root->tracking_origin_list.origin_count; return MND_SUCCESS; } mnd_result_t -mnd_root_get_tracking_origin_name(mnd_root_t *root, uint32_t origin_id, const char **out_string) +mnd_root_get_tracking_origin_name(mnd_root_t *root, uint32_t origin_index, const char **out_string) { CHECK_NOT_NULL(root); CHECK_NOT_NULL(out_string); + CHECK_ORIGIN_INDEX(origin_index); - if (origin_id >= root->ipc_c.ism->itrack_count) { - PE("Invalid itrack index (%u)", origin_id); - return MND_ERROR_INVALID_VALUE; - } - - const struct ipc_shared_tracking_origin *ipcsto = &root->ipc_c.ism->itracks[origin_id]; + const struct ipc_tracking_origin_info *itoi = &root->origin_infos[origin_index]; - *out_string = ipcsto->name; + *out_string = itoi->name; return MND_SUCCESS; } diff --git a/src/xrt/targets/libmonado/monado.h b/src/xrt/targets/libmonado/monado.h index 5d0a99b35..1942265fb 100644 --- a/src/xrt/targets/libmonado/monado.h +++ b/src/xrt/targets/libmonado/monado.h @@ -1,4 +1,5 @@ // Copyright 2019-2023, Collabora, Ltd. +// Copyright 2025-2026, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -433,13 +434,13 @@ mnd_root_set_reference_space_offset(mnd_root_t *root, mnd_reference_space_type_t * Supported in version 1.3 and above. * * @param root The libmonado state. - * @param origin_id The ID of the tracking origin. + * @param origin_index The index of the tracking origin into the internal list. * @param[out] out_offset A pointer to where the offset should be written. * * @return MND_SUCCESS on success */ mnd_result_t -mnd_root_get_tracking_origin_offset(mnd_root_t *root, uint32_t origin_id, mnd_pose_t *out_offset); +mnd_root_get_tracking_origin_offset(mnd_root_t *root, uint32_t origin_index, mnd_pose_t *out_offset); /*! * Apply an offset to the specified tracking origin. @@ -447,13 +448,13 @@ mnd_root_get_tracking_origin_offset(mnd_root_t *root, uint32_t origin_id, mnd_po * Supported in version 1.3 and above. * * @param root The libmonado state. - * @param origin_id The ID of the tracking origin. + * @param origin_index The index of the tracking origin into the internal list. * @param offset A pointer to valid xrt_pose. * * @return MND_SUCCESS on success */ mnd_result_t -mnd_root_set_tracking_origin_offset(mnd_root_t *root, uint32_t origin_id, const mnd_pose_t *offset); +mnd_root_set_tracking_origin_offset(mnd_root_t *root, uint32_t origin_index, const mnd_pose_t *offset); /*! * Retrieve the number of tracking origins available. @@ -474,13 +475,13 @@ mnd_root_get_tracking_origin_count(mnd_root_t *root, uint32_t *out_track_count); * Supported in version 1.3 and above. * * @param root The libmonado state. - * @param origin_id The ID of a tracking origin. + * @param origin_index The index of the tracking origin into the internal list. * @param out_string The pointer to write the name's pointer to. * * @return MND_SUCCESS on success */ mnd_result_t -mnd_root_get_tracking_origin_name(mnd_root_t *root, uint32_t origin_id, const char **out_string); +mnd_root_get_tracking_origin_name(mnd_root_t *root, uint32_t origin_index, const char **out_string); /*! * Get battery status of a device. -- 2.51.2