From 803e8168e4dbf5bc3ffa15261af2eccb422ee9d5 Mon Sep 17 00:00:00 2001 From: Andrei Aristarkhov Date: Wed, 05 Feb 2025 18:10:43 +0000 Subject: [PATCH] xrt: server can use xrt_instance::is_system_available to delay system creation Part-of: --- src/xrt/include/xrt/xrt_instance.h | 20 ++++++++++++++++++++ src/xrt/ipc/client/ipc_client_instance.c | 9 +++++++++ src/xrt/ipc/server/ipc_server.h | 13 +++++++++++++ src/xrt/ipc/server/ipc_server_handler.c | 19 +++++++++++++++++++ src/xrt/ipc/server/ipc_server_process.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ src/xrt/ipc/shared/proto.json | 6 ++++++ src/xrt/state_trackers/oxr/oxr_instance.c | 15 +++++++++++++++ src/xrt/targets/common/target_instance.c | 14 ++++++++++++++ 8 file(s) changed, 164 insertion(s)(+), 18 deletion(s)(-) diff --git a/src/xrt/include/xrt/xrt_instance.h b/src/xrt/include/xrt/xrt_instance.h --- a/src/xrt/include/xrt/xrt_instance.h +++ b/src/xrt/include/xrt/xrt_instance.h @@ -1,4 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -126,6 +127,11 @@ */ /*! + * Checks if the system can be created with create_system(). + */ + xrt_result_t (*is_system_available)(struct xrt_instance *xinst, bool *out_available); + + /*! * Creates all of the system resources like the devices and system * compositor. The system compositor is optional. * @@ -198,6 +204,20 @@ */ struct xrt_instance_android *android_instance; }; + + +/*! + * @copydoc xrt_instance::create_system + * + * Helper for calling through the function pointer. + * + * @public @memberof xrt_instance + */ +static inline xrt_result_t +xrt_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) +{ + return xinst->is_system_available(xinst, out_available); +} /*! * @copydoc xrt_instance::create_system diff --git a/src/xrt/ipc/client/ipc_client_instance.c b/src/xrt/ipc/client/ipc_client_instance.c --- a/src/xrt/ipc/client/ipc_client_instance.c +++ b/src/xrt/ipc/client/ipc_client_instance.c @@ -131,6 +131,14 @@ */ static xrt_result_t +ipc_client_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) +{ + struct ipc_client_instance *ii = ipc_client_instance(xinst); + xrt_result_t xret = ipc_call_instance_is_system_available(&ii->ipc_c, out_available); + IPC_CHK_ALWAYS_RET(&ii->ipc_c, xret, "ipc_call_instance_is_system_available"); +} + +static xrt_result_t ipc_client_instance_create_system(struct xrt_instance *xinst, struct xrt_system **out_xsys, struct xrt_system_devices **out_xsysd, @@ -284,6 +292,7 @@ ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst) { struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance); + ii->base.is_system_available = ipc_client_instance_is_system_available; ii->base.create_system = ipc_client_instance_create_system; ii->base.get_prober = ipc_client_instance_get_prober; ii->base.destroy = ipc_client_instance_destroy; diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -1,4 +1,5 @@ // Copyright 2020-2023, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -89,6 +90,9 @@ { //! Link back to the main server. struct ipc_server *server; + + //! Has the system part of the shm initialized. + bool has_init_shm_system; //! Session for this client. struct xrt_session *xs; @@ -409,6 +413,15 @@ } global_state; }; +/*! + * Finish setting up the server by creating the system, compositor and devices. + * + * @ingroup ipc_server + */ +xrt_result_t +ipc_server_init_system_if_available_locked(struct ipc_server *s, + volatile struct ipc_client_state *ics, + bool *out_available); /*! * Get the current state of a client. diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -400,6 +400,25 @@ } xrt_result_t +ipc_handle_instance_is_system_available(volatile struct ipc_client_state *ics, bool *out_available) +{ + IPC_TRACE_MARKER(); + + xrt_result_t xret = XRT_SUCCESS; + + struct ipc_server *s = ics->server; + + os_mutex_lock(&s->global_state.lock); + + xret = ipc_server_init_system_if_available_locked(s, ics, out_available); + IPC_CHK_WITH_GOTO(s, xret, "ipc_server_init_system_if_available_locked", cleanup); + +cleanup: + os_mutex_unlock(&s->global_state.lock); + return xret; +} + +xrt_result_t ipc_handle_system_compositor_get_info(volatile struct ipc_client_state *ics, struct xrt_system_compositor_info *out_info) { diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -279,18 +279,32 @@ } XRT_CHECK_RESULT static xrt_result_t -init_shm(struct ipc_server *s, volatile struct ipc_client_state *cs) +init_shm_and_instance_state(struct ipc_server *s, volatile struct ipc_client_state *ics) { const size_t size = sizeof(struct ipc_shared_memory); xrt_shmem_handle_t handle; - xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[cs->server_thread_index]); + xrt_result_t xret = ipc_shmem_create(size, &handle, (void **)&s->isms[ics->server_thread_index]); IPC_CHK_AND_RET(s, xret, "ipc_shmem_create"); // we have a filehandle, we will pass this to our client - cs->ism_handle = handle; + ics->ism_handle = handle; + // Convenience + struct ipc_shared_memory *ism = s->isms[ics->server_thread_index]; + // Clients expect git version info and timestamp available upon connect. + snprintf(ism->u_git_tag, IPC_VERSION_NAME_LEN, "%s", u_git_tag); + + // Used to synchronize all client's xrt_instance::startup_timestamp. + ism->startup_timestamp = os_monotonic_get_ns(); + + return XRT_SUCCESS; +} + +static void +init_system_shm_state(struct ipc_server *s, volatile struct ipc_client_state *cs) +{ /* * * Setup the shared memory state. @@ -299,8 +313,6 @@ uint32_t count = 0; struct ipc_shared_memory *ism = s->isms[cs->server_thread_index]; - - ism->startup_timestamp = os_monotonic_get_ns(); // Setup the tracking origins. count = 0; @@ -423,17 +435,13 @@ ism->roles.eyes = find_xdev_index(s, s->xsysd->static_roles.eyes); ism->roles.face = find_xdev_index(s, s->xsysd->static_roles.face); ism->roles.body = find_xdev_index(s, s->xsysd->static_roles.body); + #define SET_HT_ROLE(SRC) \ ism->roles.hand_tracking.SRC.left = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.left); \ ism->roles.hand_tracking.SRC.right = find_xdev_index(s, s->xsysd->static_roles.hand_tracking.SRC.right); SET_HT_ROLE(unobstructed) SET_HT_ROLE(conforming) #undef SET_HT_ROLE - - // Fill out git version info. - snprintf(ism->u_git_tag, IPC_VERSION_NAME_LEN, "%s", u_git_tag); - - return XRT_SUCCESS; } static void @@ -487,13 +495,6 @@ xret = xrt_instance_create(NULL, &s->xinst); IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create", error); - - xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc); - IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error); - - // Always succeeds. - init_idevs(s); - init_tracking_origins(s); ret = ipc_server_mainloop_init(&s->ml); if (ret < 0) { @@ -806,6 +807,46 @@ */ xrt_result_t +ipc_server_init_system_if_available_locked(struct ipc_server *s, + volatile struct ipc_client_state *ics, + bool *out_available) +{ + xrt_result_t xret = XRT_SUCCESS; + + bool available = false; + + if (s->xsys) { + available = true; + } else { + xret = xrt_instance_is_system_available(s->xinst, &available); + IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_is_system_available", error); + + if (available) { + xret = xrt_instance_create_system(s->xinst, &s->xsys, &s->xsysd, &s->xso, &s->xsysc); + IPC_CHK_WITH_GOTO(s, xret, "xrt_instance_create_system", error); + + // Always succeeds. + init_idevs(s); + init_tracking_origins(s); + } + } + + if (available && ics != NULL && !ics->has_init_shm_system) { + init_system_shm_state(s, ics); + ics->has_init_shm_system = true; + } + + if (out_available) { + *out_available = available; + } + + return XRT_SUCCESS; + +error: + return xret; +} + +xrt_result_t ipc_server_get_client_app_state(struct ipc_server *s, uint32_t client_id, struct ipc_app_state *out_ias) { os_mutex_lock(&s->global_state.lock); @@ -982,7 +1023,7 @@ ics->plane_detection_ids = NULL; ics->plane_detection_xdev = NULL; - xrt_result_t xret = init_shm(vs, ics); + xrt_result_t xret = init_shm_and_instance_state(vs, ics); if (xret != XRT_SUCCESS) { // Unlock when we are done. @@ -1048,6 +1089,15 @@ // Tell the callbacks we are entering the main-loop. callbacks->mainloop_entering(s, s->xinst, data); + + // Early init the system. If not available now, will try again per client request. + xret = ipc_server_init_system_if_available_locked( // + s, // + NULL, // optional - ics + NULL); // optional - out_available + if (xret != XRT_SUCCESS) { + U_LOG_CHK_ONLY_PRINT(log_level, xret, "ipc_server_init_system_if_available_locked"); + } // Main loop. ret = main_loop(s); diff --git a/src/xrt/ipc/shared/proto.json b/src/xrt/ipc/shared/proto.json --- a/src/xrt/ipc/shared/proto.json +++ b/src/xrt/ipc/shared/proto.json @@ -11,6 +11,12 @@ ] }, + "instance_is_system_available": { + "out": [ + {"name": "available", "type": "bool"} + ] + }, + "system_get_properties": { "out": [ {"name": "properties", "type": "struct xrt_system_properties"} diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c --- a/src/xrt/state_trackers/oxr/oxr_instance.c +++ b/src/xrt/state_trackers/oxr/oxr_instance.c @@ -479,6 +479,21 @@ xrt_result_t xret; XrResult ret; + bool available = false; + xret = xrt_instance_is_system_available(inst->xinst, &available); + if (xret != XRT_SUCCESS) { + struct u_pp_sink_stack_only sink; + u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); + u_pp(dg, "Call to xrt_instance_is_system_available failed: "); + u_pp_xrt_result(dg, xret); + ret = oxr_error(log, xret == XRT_ERROR_IPC_FAILURE ? XR_ERROR_INSTANCE_LOST : XR_ERROR_RUNTIME_FAILURE, + "%s", sink.buffer); + return ret; + } + if (!available) { + return XR_ERROR_FORM_FACTOR_UNAVAILABLE; + } + // Create the compositor if we are not headless, currently always create it. bool should_create_compositor = true /* !inst->extensions.MND_headless */; diff --git a/src/xrt/targets/common/target_instance.c b/src/xrt/targets/common/target_instance.c --- a/src/xrt/targets/common/target_instance.c +++ b/src/xrt/targets/common/target_instance.c @@ -1,4 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -50,6 +51,18 @@ * Internal functions. * */ + +static xrt_result_t +t_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) +{ + XRT_TRACE_MARKER(); + + assert(out_available != NULL); + + *out_available = true; + + return XRT_SUCCESS; +} static xrt_result_t t_instance_create_system(struct xrt_instance *xinst, @@ -168,6 +181,7 @@ } struct t_instance *tinst = U_TYPED_CALLOC(struct t_instance); + tinst->base.is_system_available = t_instance_is_system_available; tinst->base.create_system = t_instance_create_system; tinst->base.get_prober = t_instance_get_prober; tinst->base.destroy = t_instance_destroy; -- tangled.sh