diff --git a/src/xrt/auxiliary/util/u_space_overseer.c b/src/xrt/auxiliary/util/u_space_overseer.c index a0efb8926..c55dda8a2 100644 --- a/src/xrt/auxiliary/util/u_space_overseer.c +++ b/src/xrt/auxiliary/util/u_space_overseer.c @@ -1,4 +1,5 @@ // Copyright 2023, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -472,6 +473,57 @@ create_and_set_root_space(struct u_space_overseer *uso) } +/* + * + * Device helpers. + * + */ + +/*! + * Helper function to add a device to the space overseer. This function + * handles creating or finding a space for the device's tracking origin + * and linking the device to that space. + */ +static xrt_result_t +add_device_helper(struct u_space_overseer *uso, struct xrt_device *xdev) +{ + struct xrt_tracking_origin *torig = xdev->tracking_origin; + assert(torig != NULL); + + struct xrt_space *root = uso->base.semantic.root; + uint64_t key = (uint64_t)(intptr_t)torig; + struct xrt_space *xs = NULL; + + // Need to take the write lock. + pthread_rwlock_wrlock(&uso->lock); + + // Does this tracking origin already have space. + void *ptr = NULL; + u_hashmap_int_find(uso->xto_map, key, &ptr); + + if (ptr != NULL) { + xs = (struct xrt_space *)ptr; + } else { + /* + * If we ever make u_space_overseer sub-classable maek sure + * this calls the right function, can't call interface function + * as the lock is held here. + */ + xs = (struct xrt_space *)create_space(U_SPACE_TYPE_OFFSET, u_space(root)); + + update_offset_write_locked(u_space(xs), &torig->initial_offset); + + u_hashmap_int_insert(uso->xto_map, key, xs); + } + + pthread_rwlock_unlock(&uso->lock); + + u_space_overseer_link_space_to_device(uso, xs, xdev); + + return XRT_SUCCESS; +} + + /* * * Member functions. @@ -1033,6 +1085,14 @@ unlock: return xret; } +static xrt_result_t +add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev) +{ + struct u_space_overseer *uso = u_space_overseer(xso); + + return add_device_helper(uso, xdev); +} + static void destroy(struct xrt_space_overseer *xso) { @@ -1089,6 +1149,7 @@ u_space_overseer_create(struct xrt_session_event_sink *broadcast) uso->base.set_tracking_origin_offset = set_tracking_origin_offset; uso->base.get_reference_space_offset = get_reference_space_offset; uso->base.set_reference_space_offset = set_reference_space_offset; + uso->base.add_device = add_device; uso->base.destroy = destroy; uso->broadcast = broadcast; @@ -1117,26 +1178,14 @@ u_space_overseer_legacy_setup(struct u_space_overseer *uso, bool root_is_unbounded, bool per_app_local_spaces) { - struct xrt_space *root = uso->base.semantic.root; // Convenience uso->per_app_local_spaces = per_app_local_spaces; + // Add all devices to the space overseer. for (uint32_t i = 0; i < xdev_count; i++) { - struct xrt_device *xdev = xdevs[i]; - struct xrt_tracking_origin *torig = xdev->tracking_origin; - uint64_t key = (uint64_t)(intptr_t)torig; - struct xrt_space *xs = NULL; - - void *ptr = NULL; - u_hashmap_int_find(uso->xto_map, key, &ptr); - - if (ptr != NULL) { - xs = (struct xrt_space *)ptr; - } else { - u_space_overseer_create_offset_space(uso, root, &torig->initial_offset, &xs); - u_hashmap_int_insert(uso->xto_map, key, xs); + xrt_result_t xret = add_device_helper(uso, xdevs[i]); + if (xret != XRT_SUCCESS) { + U_LOG_E("Failed to add device '%s' to space overseer!", xdevs[i]->str); } - - u_space_overseer_link_space_to_device(uso, xs, xdev); } // If these are set something is probably wrong, but just in case unset them. diff --git a/src/xrt/include/xrt/xrt_space.h b/src/xrt/include/xrt/xrt_space.h index 81593e9de..45cc85cff 100644 --- a/src/xrt/include/xrt/xrt_space.h +++ b/src/xrt/include/xrt/xrt_space.h @@ -1,4 +1,5 @@ // Copyright 2019-2023, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -303,6 +304,39 @@ struct xrt_space_overseer struct xrt_space **out_local_space, struct xrt_space **out_local_floor_space); + /* + * + * Special inter-monado component functions. + * + */ + + /*! + * Add a new device to be tracked by the space overseer. The exact + * semantic of the space is determined by the implementation of the + * space overseer. And may be outright rejected by the implementation. + * + * After this call completes successfully, the device can be passed + * into the @ref xrt_space_overseer::locate_device function, but may + * not be locatable immediately. + * + * This function is not intended to be called by the OpenXR state + * tracker, but by other monado components that need to add devices + * but does not own the space overseer. Components like the fixer + * uppers or for push devices. + * + * @param[in] xso The space overseer. + * @param[in] xdev The device to be tracked. + * @return XRT_SUCCESS if added, otherwise an error code. + */ + xrt_result_t (*add_device)(struct xrt_space_overseer *xso, struct xrt_device *xdev); + + + /* + * + * Destroy function always comes last. + * + */ + /*! * Destroy function. * @@ -515,6 +549,19 @@ xrt_space_overseer_create_local_space(struct xrt_space_overseer *xso, return xso->create_local_space(xso, out_local_space, out_local_floor_space); } +/*! + * @copydoc xrt_space_overseer::add_device + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_space_overseer + */ +static inline xrt_result_t +xrt_space_overseer_add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev) +{ + return xso->add_device(xso, xdev); +} + /*! * Helper for calling through the function pointer: does a null check and sets * xc_ptr to null if freed. diff --git a/src/xrt/ipc/client/ipc_client_space_overseer.c b/src/xrt/ipc/client/ipc_client_space_overseer.c index e7edeb16b..665687430 100644 --- a/src/xrt/ipc/client/ipc_client_space_overseer.c +++ b/src/xrt/ipc/client/ipc_client_space_overseer.c @@ -318,6 +318,12 @@ set_reference_space_offset(struct xrt_space_overseer *xso, return ipc_call_space_set_reference_space_offset(icspo->ipc_c, type, offset); } +static xrt_result_t +add_device(struct xrt_space_overseer *xso, struct xrt_device *xdev) +{ + return XRT_ERROR_NOT_IMPLEMENTED; +} + static void destroy(struct xrt_space_overseer *xso) { @@ -374,6 +380,7 @@ ipc_client_space_overseer_create(struct ipc_connection *ipc_c) icspo->base.set_tracking_origin_offset = set_tracking_origin_offset; icspo->base.get_reference_space_offset = get_reference_space_offset; icspo->base.set_reference_space_offset = set_reference_space_offset; + icspo->base.add_device = add_device; icspo->base.destroy = destroy; icspo->ipc_c = ipc_c;