diff --git a/src/xrt/state_trackers/oxr/CMakeLists.txt b/src/xrt/state_trackers/oxr/CMakeLists.txt index 0788efe69..bcc69cb88 100644 --- a/src/xrt/state_trackers/oxr/CMakeLists.txt +++ b/src/xrt/state_trackers/oxr/CMakeLists.txt @@ -33,6 +33,8 @@ add_library( actions/oxr_instance_path_cache.h actions/oxr_interaction_profile_array.c actions/oxr_interaction_profile_array.h + actions/oxr_session_action_context.c + actions/oxr_session_action_context.h actions/oxr_set_haptic.c actions/oxr_set_haptic.h common/oxr_defines.h diff --git a/src/xrt/state_trackers/oxr/actions/oxr_api_action.c b/src/xrt/state_trackers/oxr/actions/oxr_api_action.c index 1a11b9ad2..1816a442d 100644 --- a/src/xrt/state_trackers/oxr/actions/oxr_api_action.c +++ b/src/xrt/state_trackers/oxr/actions/oxr_api_action.c @@ -21,6 +21,7 @@ #include "oxr_input.h" #include "oxr_binding.h" #include "oxr_haptic.h" +#include "oxr_session_action_context.h" #include "../oxr_api_verify.h" #include "../oxr_objects.h" @@ -178,7 +179,7 @@ oxr_xrAttachSessionActionSets(XrSession session, const XrSessionActionSetsAttach OXR_VERIFY_SESSION_NOT_LOST(&log, sess); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, bindInfo, XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO); - if (sess->act_set_attachments != NULL) { + if (oxr_session_action_context_has_attached_act_sets(&sess->action_context)) { return oxr_error(&log, XR_ERROR_ACTIONSETS_ALREADY_ATTACHED, "(session) has already had action sets " "attached, can only attach action sets once."); @@ -423,10 +424,12 @@ oxr_xrGetCurrentInteractionProfile(XrSession session, str); } + OXR_SESSION_CHECK_ATTACHED_AND_RET(sess, &log); + XrResult ret = oxr_action_get_current_interaction_profile( // &log, // &inst->path_cache, // - sess, // + &sess->action_context, // topLevelUserPath, // interactionProfile); // if (ret == XR_SUCCESS) { @@ -454,10 +457,7 @@ oxr_xrGetInputSourceLocalizedName(XrSession session, // Short hand. inst = sess->sys->inst; - if (sess->act_set_attachments == NULL) { - return oxr_error(&log, XR_ERROR_ACTIONSET_NOT_ATTACHED, - "ActionSet(s) have not been attached to this session"); - } + OXR_SESSION_CHECK_ATTACHED_AND_RET(sess, &log); if (getInfo->sourcePath == XR_NULL_PATH) { return oxr_error(&log, XR_ERROR_PATH_INVALID, @@ -487,7 +487,7 @@ oxr_xrGetInputSourceLocalizedName(XrSession session, XrResult ret = oxr_action_get_input_source_localized_name( // &log, // &inst->path_store, // - sess, // + &sess->action_context, // getInfo, // bufferCapacityInput, // bufferCountOutput, // @@ -805,11 +805,7 @@ oxr_xrEnumerateBoundSourcesForAction(XrSession session, OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, enumerateInfo, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO); OXR_VERIFY_ACTION_NOT_NULL(&log, enumerateInfo->action, act); - if (sess->act_set_attachments == NULL) { - return oxr_error(&log, XR_ERROR_ACTIONSET_NOT_ATTACHED, - "(session) xrAttachSessionActionSets has not " - "been called on this session."); - } + OXR_SESSION_CHECK_ATTACHED_AND_RET(sess, &log); return oxr_action_enumerate_bound_sources(&log, sess, act->act_key, sourceCapacityInput, sourceCountOutput, sources); diff --git a/src/xrt/state_trackers/oxr/actions/oxr_binding.c b/src/xrt/state_trackers/oxr/actions/oxr_binding.c index 3e4347abf..0e1b27360 100644 --- a/src/xrt/state_trackers/oxr/actions/oxr_binding.c +++ b/src/xrt/state_trackers/oxr/actions/oxr_binding.c @@ -15,13 +15,13 @@ #include "oxr_subaction.h" #include "oxr_generated_bindings.h" #include "oxr_dpad_state.h" +#include "oxr_session_action_context.h" #include "oxr_interaction_profile_array.h" #include "../oxr_objects.h" #include "../oxr_logger.h" #include "../oxr_two_call.h" - #include @@ -354,11 +354,12 @@ get_subaction_path_str(enum oxr_subaction_path subaction_path) } static XrPath -get_interaction_bound_to_sub_path(struct oxr_session *sess, enum oxr_subaction_path subaction_path) +get_interaction_bound_to_sub_path(const struct oxr_session_action_context *action_context, + enum oxr_subaction_path subaction_path) { switch (subaction_path) { #define OXR_PATH_MEMBER(lower, CAP, _) \ - case OXR_SUB_ACTION_PATH_##CAP: return sess->lower; + case OXR_SUB_ACTION_PATH_##CAP: return action_context->lower; OXR_FOR_EACH_VALID_SUBACTION_PATH_DETAILED(OXR_PATH_MEMBER) #undef OXR_PATH_MEMBER @@ -610,18 +611,15 @@ out: XrResult oxr_action_get_current_interaction_profile(struct oxr_logger *log, const struct oxr_instance_path_cache *cache, - struct oxr_session *sess, + const struct oxr_session_action_context *action_context, XrPath topLevelUserPath, XrInteractionProfileState *interactionProfile) { - if (sess->act_set_attachments == NULL) { - return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED, - "xrAttachSessionActionSets has not been " - "called on this session."); - } + // Action sets attachment is checked in the API function. + #define IDENTIFY_TOP_LEVEL_PATH(X) \ if (topLevelUserPath == cache->X) { \ - interactionProfile->interactionProfile = sess->X; \ + interactionProfile->interactionProfile = action_context->X; \ } else OXR_FOR_EACH_VALID_SUBACTION_PATH(IDENTIFY_TOP_LEVEL_PATH) @@ -636,7 +634,7 @@ oxr_action_get_current_interaction_profile(struct oxr_logger *log, XrResult oxr_action_get_input_source_localized_name(struct oxr_logger *log, const struct oxr_path_store *store, - struct oxr_session *sess, + const struct oxr_session_action_context *action_context, const XrInputSourceLocalizedNameGetInfo *getInfo, uint32_t bufferCapacityInput, uint32_t *bufferCountOutput, @@ -653,7 +651,7 @@ oxr_action_get_input_source_localized_name(struct oxr_logger *log, } // Get the interaction profile bound to this subaction_path. - XrPath path = get_interaction_bound_to_sub_path(sess, subaction_path); + XrPath path = get_interaction_bound_to_sub_path(action_context, subaction_path); if (path == XR_NULL_PATH) { return oxr_error(log, XR_ERROR_VALIDATION_FAILURE, "(getInfo->sourcePath) no interaction profile " @@ -663,7 +661,7 @@ oxr_action_get_input_source_localized_name(struct oxr_logger *log, // Find the interaction profile. struct oxr_interaction_profile *oip = NULL; //! @todo: If we ever rebind a profile that has not been suggested by the client, it will not be found. - oxr_interaction_profile_array_find_by_path(&sess->profiles_on_attachment, path, &oip); + oxr_interaction_profile_array_find_by_path(&action_context->profiles_on_attachment, path, &oip); if (oip == NULL) { return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "no interaction profile found"); } diff --git a/src/xrt/state_trackers/oxr/actions/oxr_binding.h b/src/xrt/state_trackers/oxr/actions/oxr_binding.h index 3804c32aa..ddfd5a982 100644 --- a/src/xrt/state_trackers/oxr/actions/oxr_binding.h +++ b/src/xrt/state_trackers/oxr/actions/oxr_binding.h @@ -90,11 +90,12 @@ oxr_action_suggest_interaction_profile_bindings(struct oxr_logger *log, /*! * Get the currently active interaction profile for a top-level user path - * on the session (e.g. /user/hand/left). Requires action sets to be attached. + * on the session action context (e.g. /user/hand/left). Requires action sets to + * be attached. * * @param log Logger * @param cache Instance path cache - * @param sess Session + * @param action_context Action context * @param topLevelUserPath Top-level user path (e.g. left hand) * @param interactionProfile Output interaction profile state * @return XR_SUCCESS on success @@ -103,7 +104,7 @@ oxr_action_suggest_interaction_profile_bindings(struct oxr_logger *log, XrResult oxr_action_get_current_interaction_profile(struct oxr_logger *log, const struct oxr_instance_path_cache *cache, - struct oxr_session *sess, + const struct oxr_session_action_context *action_context, XrPath topLevelUserPath, XrInteractionProfileState *interactionProfile); @@ -112,7 +113,7 @@ oxr_action_get_current_interaction_profile(struct oxr_logger *log, * * @param log Logger * @param path_store Needed to look up path strings. - * @param sess Session. + * @param action_context Action context * @param getInfo Input source localized name get info * @param bufferCapacityInput Buffer capacity * @param bufferCountOutput Buffer count output @@ -123,7 +124,7 @@ oxr_action_get_current_interaction_profile(struct oxr_logger *log, XrResult oxr_action_get_input_source_localized_name(struct oxr_logger *log, const struct oxr_path_store *store, - struct oxr_session *sess, + const struct oxr_session_action_context *action_context, const XrInputSourceLocalizedNameGetInfo *getInfo, uint32_t bufferCapacityInput, uint32_t *bufferCountOutput, diff --git a/src/xrt/state_trackers/oxr/actions/oxr_input.c b/src/xrt/state_trackers/oxr/actions/oxr_input.c index 7992ea348..269c6ec62 100644 --- a/src/xrt/state_trackers/oxr/actions/oxr_input.c +++ b/src/xrt/state_trackers/oxr/actions/oxr_input.c @@ -93,6 +93,26 @@ print_profiles(struct oxr_logger *log, oxr_log_slog(log, &slog); } +/*! + * Given an Action Set handle, return the @ref oxr_action_set and the + * associated @ref oxr_action_set_attachment in the given Session. + */ +static void +get_action_set_attachment(struct oxr_session_action_context *sess_context, + XrActionSet actionSet, + struct oxr_action_set_attachment **out_act_set_attached, + struct oxr_action_set **out_act_set) +{ + struct oxr_action_set *act_set = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_action_set *, actionSet); + + // Make sure all are set. + *out_act_set = act_set; + *out_act_set_attached = NULL; + + // Safe to call even if nothing has been attached. + oxr_session_action_context_find_set(sess_context, act_set->act_set_key, out_act_set_attached); +} + /* * @@ -100,12 +120,6 @@ print_profiles(struct oxr_logger *log, * */ -static void -oxr_session_get_action_set_attachment(struct oxr_session *sess, - XrActionSet actionSet, - struct oxr_action_set_attachment **act_set_attached, - struct oxr_action_set **act_set); - static void oxr_action_cache_update(struct oxr_logger *log, struct oxr_session *sess, @@ -218,7 +232,7 @@ static void oxr_action_attachment_teardown(struct oxr_action_attachment *act_attached) { struct oxr_session *sess = act_attached->sess; - u_hashmap_int_erase(sess->act_attachments_by_key, act_attached->act_key); + u_hashmap_int_erase(sess->action_context.act_attachments_by_key, act_attached->act_key); #define CACHE_TEARDOWN(X) oxr_action_cache_teardown(&(act_attached->X)); OXR_FOR_EACH_SUBACTION_PATH(CACHE_TEARDOWN) @@ -242,7 +256,7 @@ oxr_action_attachment_init(struct oxr_logger *log, struct oxr_session *sess = act_set_attached->sess; act_attached->sess = sess; act_attached->act_set_attached = act_set_attached; - u_hashmap_int_insert(sess->act_attachments_by_key, act->act_key, act_attached); + u_hashmap_int_insert(sess->action_context.act_attachments_by_key, act->act_key, act_attached); // Reference this action's refcounted data act_attached->act_ref = act->data; @@ -275,7 +289,7 @@ oxr_action_set_attachment_init(struct oxr_logger *log, act_set_attached->act_set_ref = act_set->data; oxr_refcounted_ref(&act_set_attached->act_set_ref->base); - u_hashmap_int_insert(sess->act_sets_attachments_by_key, act_set->act_set_key, act_set_attached); + u_hashmap_int_insert(sess->action_context.act_sets_attachments_by_key, act_set->act_set_key, act_set_attached); // Copy this for efficiency. act_set_attached->act_set_key = act_set->act_set_key; @@ -294,7 +308,7 @@ oxr_action_set_attachment_teardown(struct oxr_action_set_attachment *act_set_att act_set_attached->action_attachment_count = 0; struct oxr_session *sess = act_set_attached->sess; - u_hashmap_int_erase(sess->act_sets_attachments_by_key, act_set_attached->act_set_key); + u_hashmap_int_erase(sess->action_context.act_sets_attachments_by_key, act_set_attached->act_set_key); // Unref this action set's refcounted data oxr_refcounted_unref(&act_set_attached->act_set_ref->base); @@ -1088,7 +1102,7 @@ oxr_input_supressed(struct oxr_session *sess, struct oxr_action_set *other_act_set = NULL; struct oxr_action_set_attachment *other_act_set_attached = NULL; - oxr_session_get_action_set_attachment(sess, set, &other_act_set_attached, &other_act_set); + get_action_set_attachment(&sess->action_context, set, &other_act_set_attached, &other_act_set); if (other_act_set_attached == NULL) { continue; @@ -1814,34 +1828,6 @@ oxr_action_bind_io(struct oxr_logger *log, * */ -/*! - * Given an Action Set handle, return the @ref oxr_action_set and the - * associated - * @ref oxr_action_set_attachment in the given Session. - * - * @private @memberof oxr_session - */ -static void -oxr_session_get_action_set_attachment(struct oxr_session *sess, - XrActionSet actionSet, - struct oxr_action_set_attachment **act_set_attached, - struct oxr_action_set **act_set) -{ - void *ptr = NULL; - *act_set = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_action_set *, actionSet); - *act_set_attached = NULL; - - // In case no action_sets have been attached. - if (sess->act_sets_attachments_by_key == NULL) { - return; - } - - int ret = u_hashmap_int_find(sess->act_sets_attachments_by_key, (*act_set)->act_set_key, &ptr); - if (ret == 0) { - *act_set_attached = (struct oxr_action_set_attachment *)ptr; - } -} - void oxr_session_get_action_attachment(struct oxr_session *sess, uint32_t act_key, @@ -1849,7 +1835,7 @@ oxr_session_get_action_attachment(struct oxr_session *sess, { void *ptr = NULL; - int ret = u_hashmap_int_find(sess->act_attachments_by_key, act_key, &ptr); + int ret = u_hashmap_int_find(sess->action_context.act_attachments_by_key, act_key, &ptr); if (ret == 0) { *out_act_attached = (struct oxr_action_attachment *)ptr; } @@ -1875,22 +1861,23 @@ oxr_session_attach_action_sets(struct oxr_logger *log, struct oxr_instance *inst = sess->sys->inst; const struct oxr_instance_action_context *inst_context = inst->action_context; + struct oxr_session_action_context *sess_context = &sess->action_context; - oxr_interaction_profile_array_clone(&inst_context->suggested_profiles, &sess->profiles_on_attachment); + oxr_interaction_profile_array_clone(&inst_context->suggested_profiles, &sess_context->profiles_on_attachment); // Allocate room for list. No need to check if anything has been // attached the API function does that. - sess->action_set_attachment_count = bindInfo->countActionSets; - sess->act_set_attachments = - U_TYPED_ARRAY_CALLOC(struct oxr_action_set_attachment, sess->action_set_attachment_count); + sess->action_context.action_set_attachment_count = bindInfo->countActionSets; + sess->action_context.act_set_attachments = + U_TYPED_ARRAY_CALLOC(struct oxr_action_set_attachment, sess->action_context.action_set_attachment_count); // Set up the per-session data for these action sets. - for (uint32_t i = 0; i < sess->action_set_attachment_count; i++) { + for (uint32_t i = 0; i < sess->action_context.action_set_attachment_count; i++) { struct oxr_action_set *act_set = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_action_set *, bindInfo->actionSets[i]); struct oxr_action_set_ref *act_set_ref = act_set->data; act_set_ref->ever_attached = true; - struct oxr_action_set_attachment *act_set_attached = &sess->act_set_attachments[i]; + struct oxr_action_set_attachment *act_set_attached = &sess->action_context.act_set_attachments[i]; oxr_action_set_attachment_init(log, sess, act_set, act_set_attached); // Allocate the action attachments for this set. @@ -1924,13 +1911,14 @@ oxr_session_attach_action_sets(struct oxr_logger *log, static XrResult session_update_action_bindings(struct oxr_logger *log, struct oxr_instance *inst, - struct oxr_session *sess, - const struct oxr_roles *roles) + struct oxr_session_action_context *action_context, + const struct oxr_roles *roles, + bool *out_interaction_profile_changed) { // Convenience. const struct oxr_path_store *store = &inst->path_store; const struct oxr_instance_path_cache *cache = &inst->path_cache; - const struct oxr_interaction_profile_array *array = &sess->profiles_on_attachment; + const struct oxr_interaction_profile_array *array = &action_context->profiles_on_attachment; struct oxr_profiles_per_subaction profiles = {0}; find_profiles_from_roles(cache, array, roles, &profiles); @@ -1940,14 +1928,16 @@ session_update_action_bindings(struct oxr_logger *log, print_profiles(log, store, &profiles); } - for (size_t i = 0; i < sess->action_set_attachment_count; i++) { - struct oxr_action_set_attachment *act_set_attached = &sess->act_set_attachments[i]; + for (size_t i = 0; i < action_context->action_set_attachment_count; i++) { + struct oxr_action_set_attachment *act_set_attached = &action_context->act_set_attachments[i]; for (size_t k = 0; k < act_set_attached->action_attachment_count; k++) { struct oxr_action_attachment *act_attached = &act_set_attached->act_attachments[k]; oxr_action_attachment_bind(log, inst, act_attached, roles, &profiles); } } + bool interaction_profile_changed = false; + /* * This code will only send events (and update the bindings) if there * is a profile mapped to the subaction path. Meaning it won't update @@ -1960,15 +1950,17 @@ session_update_action_bindings(struct oxr_logger *log, if (path == XR_NULL_PATH) { \ break; /* Only update on "active" interaction profiles per sub-action path. */ \ } \ - if (sess->X != path) { \ - sess->X = path; \ - oxr_event_push_XrEventDataInteractionProfileChanged(log, sess); \ + if (action_context->X != path) { \ + action_context->X = path; \ + interaction_profile_changed = true; \ } \ } while (false); OXR_FOR_EACH_VALID_SUBACTION_PATH(POPULATE_PROFILE) #undef POPULATE_PROFILE - return oxr_session_success_result(sess); + *out_interaction_profile_changed = interaction_profile_changed; + + return XR_SUCCESS; } XrResult @@ -1978,6 +1970,9 @@ oxr_action_sync_data(struct oxr_logger *log, const XrActiveActionSet *actionSets, const XrActiveActionSetPrioritiesEXT *activePriorities) { + struct oxr_session_action_context *sess_context = &sess->action_context; + struct oxr_instance *inst = sess->sys->inst; + struct oxr_action_set *act_set = NULL; struct oxr_action_set_attachment *act_set_attached = NULL; @@ -1988,7 +1983,7 @@ oxr_action_sync_data(struct oxr_logger *log, // Check that all action sets has been attached. for (uint32_t i = 0; i < countActionSets; i++) { - oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set); + get_action_set_attachment(sess_context, actionSets[i].actionSet, &act_set_attached, &act_set); if (act_set_attached == NULL) { return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED, "(actionSets[%i].actionSet) action set '%s' has " @@ -2019,12 +2014,23 @@ oxr_action_sync_data(struct oxr_logger *log, // Should we redo the bindings? { - os_mutex_lock(&sess->sync_actions_mutex); - if (sess->dynamic_roles_generation_id < roles.roles.generation_id) { - sess->dynamic_roles_generation_id = roles.roles.generation_id; - session_update_action_bindings(log, sess->sys->inst, sess, &roles); + bool interaction_profile_changed = false; + + os_mutex_lock(&sess_context->sync_actions_mutex); + if (sess_context->dynamic_roles_generation_id < roles.roles.generation_id) { + sess_context->dynamic_roles_generation_id = roles.roles.generation_id; + session_update_action_bindings( // + log, // + inst, // + sess_context, // + &roles, // + &interaction_profile_changed); // + } + os_mutex_unlock(&sess_context->sync_actions_mutex); + + if (interaction_profile_changed) { + oxr_event_push_XrEventDataInteractionProfileChanged(log, sess); } - os_mutex_unlock(&sess->sync_actions_mutex); } if (countActionSets == 0) { @@ -2044,8 +2050,8 @@ oxr_action_sync_data(struct oxr_logger *log, } // Reset all action set attachments. - for (size_t i = 0; i < sess->action_set_attachment_count; ++i) { - act_set_attached = &sess->act_set_attachments[i]; + for (size_t i = 0; i < sess_context->action_set_attachment_count; ++i) { + act_set_attached = &sess_context->act_set_attachments[i]; U_ZERO(&act_set_attached->requested_subaction_paths); } @@ -2054,7 +2060,7 @@ oxr_action_sync_data(struct oxr_logger *log, //! @todo can be listed more than once with different paths! for (uint32_t i = 0; i < countActionSets; i++) { struct oxr_subaction_paths subaction_paths; - oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set); + get_action_set_attachment(sess_context, actionSets[i].actionSet, &act_set_attached, &act_set); assert(act_set_attached != NULL); if (!oxr_classify_subaction_paths(log, sess->sys->inst, 1, &actionSets[i].subactionPath, @@ -2090,11 +2096,10 @@ oxr_action_sync_data(struct oxr_logger *log, } // Now, update all action attachments - for (size_t i = 0; i < sess->action_set_attachment_count; ++i) { - act_set_attached = &sess->act_set_attachments[i]; + for (size_t i = 0; i < sess_context->action_set_attachment_count; ++i) { + act_set_attached = &sess_context->act_set_attachments[i]; struct oxr_subaction_paths subaction_paths = act_set_attached->requested_subaction_paths; - for (uint32_t k = 0; k < act_set_attached->action_attachment_count; k++) { struct oxr_action_attachment *act_attached = &act_set_attached->act_attachments[k]; diff --git a/src/xrt/state_trackers/oxr/actions/oxr_session_action_context.c b/src/xrt/state_trackers/oxr/actions/oxr_session_action_context.c new file mode 100644 index 000000000..17c7b3a3b --- /dev/null +++ b/src/xrt/state_trackers/oxr/actions/oxr_session_action_context.c @@ -0,0 +1,99 @@ +// Copyright 2018-2024, Collabora, Ltd. +// Copyright 2023-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Holds per session action context. + * @author Rylie Pavlik + * @ingroup oxr_main + */ + +#include "util/u_debug.h" +#include "util/u_hashmap.h" + +#include "oxr_session_action_context.h" +#include "../oxr_logger.h" +#include "../oxr_objects.h" +#include "oxr_input.h" + + +XrResult +oxr_session_action_context_init(struct oxr_session_action_context *action_context) +{ + // Initialize dynamic roles generation_id and mutex + action_context->dynamic_roles_generation_id = 0; + os_mutex_init(&action_context->sync_actions_mutex); + + // Action system hashmaps. + int h_ret = u_hashmap_int_create(&action_context->act_sets_attachments_by_key); + if (h_ret != 0) { + return XR_ERROR_RUNTIME_FAILURE; + } + + // @todo Remove or check results. + u_hashmap_int_create(&action_context->act_attachments_by_key); + + // Initialize action set attachments + action_context->act_set_attachments = NULL; + action_context->action_set_attachment_count = 0; + + // Initialize subaction paths +#define INIT_PATH(X) action_context->X = XR_NULL_PATH; + OXR_FOR_EACH_VALID_SUBACTION_PATH(INIT_PATH) +#undef INIT_PATH + + return XR_SUCCESS; +} + +void +oxr_session_action_context_fini(struct oxr_session_action_context *action_context) +{ + oxr_interaction_profile_array_clear(&action_context->profiles_on_attachment); + + // Teardown action set attachments + for (size_t i = 0; i < action_context->action_set_attachment_count; ++i) { + oxr_action_set_attachment_teardown(&action_context->act_set_attachments[i]); + } + free(action_context->act_set_attachments); + action_context->act_set_attachments = NULL; + action_context->action_set_attachment_count = 0; + + // If we tore everything down correctly, these are empty now. + assert(action_context->act_sets_attachments_by_key == NULL || + u_hashmap_int_empty(action_context->act_sets_attachments_by_key)); + assert(action_context->act_attachments_by_key == NULL || + u_hashmap_int_empty(action_context->act_attachments_by_key)); + + u_hashmap_int_destroy(&action_context->act_sets_attachments_by_key); + u_hashmap_int_destroy(&action_context->act_attachments_by_key); + + // Destroy mutex + os_mutex_destroy(&action_context->sync_actions_mutex); +} + +bool +oxr_session_action_context_has_attached_act_sets(const struct oxr_session_action_context *action_context) +{ + return action_context->act_set_attachments != NULL; +} + +XRT_NONNULL_ALL bool +oxr_session_action_context_find_set(struct oxr_session_action_context *action_context, + uint32_t act_set_key, + struct oxr_action_set_attachment **out_act_set_attached) +{ + void *ptr = NULL; + + // In case no action_sets have been attached. + if (!oxr_session_action_context_has_attached_act_sets(action_context)) { + return false; + } + + int ret = u_hashmap_int_find(action_context->act_sets_attachments_by_key, act_set_key, &ptr); + if (ret == 0) { + *out_act_set_attached = (struct oxr_action_set_attachment *)ptr; + return true; + } + + return false; +} diff --git a/src/xrt/state_trackers/oxr/actions/oxr_session_action_context.h b/src/xrt/state_trackers/oxr/actions/oxr_session_action_context.h new file mode 100644 index 000000000..7c914a15b --- /dev/null +++ b/src/xrt/state_trackers/oxr/actions/oxr_session_action_context.h @@ -0,0 +1,184 @@ +// Copyright 2018-2024, Collabora, Ltd. +// Copyright 2023-2026, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Holds per session action context. + * @author Rylie Pavlik + * @ingroup oxr_main + */ + +#pragma once + +#include "os/os_threading.h" + +#include "oxr_forward_declarations.h" +#include "oxr_extension_support.h" +#include "oxr_subaction.h" +#include "oxr_interaction_profile_array.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * + * Helper macros + * + */ + +/*! + * Helper macro to check if action sets are attached to a session. + * + * Returns XR_ERROR_ACTIONSET_NOT_ATTACHED if action sets have not been attached. + * + * @param SESS Session pointer + * @param LOG Logger pointer + * @ingroup oxr_main + */ +#define OXR_SESSION_CHECK_ATTACHED_AND_RET(SESS, LOG) \ + do { \ + if (!oxr_session_action_context_has_attached_act_sets(&(SESS)->action_context)) { \ + return oxr_error(LOG, XR_ERROR_ACTIONSET_NOT_ATTACHED, \ + "ActionSet(s) have not been attached to this session"); \ + } \ + } while (false) + + +/* + * + * Structs + * + */ + +/*! + * This holds all of the action state that belongs on the session level. + * + * Future extensions might enable multiple action contexts per session. + */ +struct oxr_session_action_context +{ + /* + * Action Set fields + */ + + /*! + * A map of action set key to action set attachments. + * + * If non-null, this means action sets have been attached to this + * session, since this map points to elements of + * oxr_session_action_context::act_set_attachments + */ + struct u_hashmap_int *act_sets_attachments_by_key; + + /*! + * An array of action set attachments that this session owns. + * + * If non-null, this means action sets have been attached to this + * session. + */ + struct oxr_action_set_attachment *act_set_attachments; + + /*! + * Length of @ref oxr_session_action_context::act_set_attachments. + */ + size_t action_set_attachment_count; + + + /* + * Action fields + */ + + /*! + * A map of action key to action attachment. + * + * The action attachments are actually owned by the action set + * attachments, but we own the action set attachments, so this is OK. + * + * If non-null, this means an action context (default or otherwise) + * action sets have been attached to the owning session, since this map + * points to @p oxr_action_attachment members of + * @ref oxr_session_action_context::act_set_attachments elements. + */ + struct u_hashmap_int *act_attachments_by_key; + + + /* + * Interaction Profiles fields + */ + + /*! + * Clone of all suggested binding profiles at the point of action set/session attachment. + * @ref oxr_session_attach_action_sets + */ + struct oxr_interaction_profile_array profiles_on_attachment; + + //! Cache of the last known system roles generation_id + uint64_t dynamic_roles_generation_id; + + //! Protects access to dynamic_roles_generation_id during sync actions + struct os_mutex sync_actions_mutex; + + /*! + * Currently bound interaction profile. + * @{ + */ + +#define OXR_PATH_MEMBER(X) XrPath X; + + OXR_FOR_EACH_VALID_SUBACTION_PATH(OXR_PATH_MEMBER) +#undef OXR_PATH_MEMBER + /*! + * @} + */ +}; + + +/* + * + * Functions + * + */ + +/*! + * Initialize the action context for a session. + * + * @public @memberof oxr_session_action_context + */ +XRT_NONNULL_ALL XRT_CHECK_RESULT XrResult +oxr_session_action_context_init(struct oxr_session_action_context *action_context); + +/*! + * Finalize and cleanup the action context for a session. + * + * @public @memberof oxr_session_action_context + */ +XRT_NONNULL_ALL void +oxr_session_action_context_fini(struct oxr_session_action_context *action_context); + +/*! + * Check if action sets have been attached to the action context. + * + * @return true if action sets are attached, false otherwise + * @public @memberof oxr_session_action_context + */ +XRT_NONNULL_ALL bool +oxr_session_action_context_has_attached_act_sets(const struct oxr_session_action_context *action_context); + +/*! + * Helper to find action set attachment. + * + * @return true if the action set was found, false otherwise + * @public @memberof oxr_session_action_context + */ +XRT_NONNULL_ALL bool +oxr_session_action_context_find_set(struct oxr_session_action_context *action_context, + uint32_t act_set_key, + struct oxr_action_set_attachment **out_act_set_attached); + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/state_trackers/oxr/common/oxr_forward_declarations.h b/src/xrt/state_trackers/oxr/common/oxr_forward_declarations.h index 252de72d6..a672686d3 100644 --- a/src/xrt/state_trackers/oxr/common/oxr_forward_declarations.h +++ b/src/xrt/state_trackers/oxr/common/oxr_forward_declarations.h @@ -55,6 +55,7 @@ struct oxr_action_attachment; struct oxr_action_set_attachment; struct oxr_action_input; struct oxr_action_output; +struct oxr_session_action_context; struct oxr_dpad_state; struct oxr_binding; struct oxr_interaction_profile; diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index 65837b7b2..242b10f17 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -40,6 +40,7 @@ #include "actions/oxr_subaction.h" #include "actions/oxr_dpad_state.h" +#include "actions/oxr_session_action_context.h" #include "actions/oxr_interaction_profile_array.h" #include "actions/oxr_instance_path_cache.h" #include "actions/oxr_instance_action_context.h" @@ -1410,63 +1411,9 @@ struct oxr_session struct os_precise_sleeper sleeper; /*! - * An array of action set attachments that this session owns. - * - * If non-null, this means action sets have been attached to this - * session. - */ - struct oxr_action_set_attachment *act_set_attachments; - - /*! - * Length of @ref oxr_session::act_set_attachments. - */ - size_t action_set_attachment_count; - - /*! - * A map of action set key to action set attachments. - * - * If non-null, this means action sets have been attached to this - * session, since this map points to elements of - * oxr_session::act_set_attachments - */ - struct u_hashmap_int *act_sets_attachments_by_key; - - /*! - * A map of action key to action attachment. - * - * The action attachments are actually owned by the action set - * attachments, but we own the action set attachments, so this is OK. - * - * If non-null, this means action sets have been attached to this - * session, since this map points to @p oxr_action_attachment members of - * @ref oxr_session::act_set_attachments elements. - */ - struct u_hashmap_int *act_attachments_by_key; - - /*! - * Clone of all suggested binding profiles at the point of action set/session attachment. - * @ref oxr_session_attach_action_sets - */ - struct oxr_interaction_profile_array profiles_on_attachment; - - //! Cache of the last known system roles generation_id - uint64_t dynamic_roles_generation_id; - - //! Protects access to dynamic_roles_generation_id during sync actions - struct os_mutex sync_actions_mutex; - - /*! - * Currently bound interaction profile. - * @{ - */ - -#define OXR_PATH_MEMBER(X) XrPath X; - - OXR_FOR_EACH_VALID_SUBACTION_PATH(OXR_PATH_MEMBER) -#undef OXR_PATH_MEMBER - /*! - * @} + * Holds all the action state that belongs on the session level. */ + struct oxr_session_action_context action_context; /*! * IPD, to be expanded to a proper 3D relation. diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index 3391b78a2..44a058dcd 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -49,6 +49,7 @@ #include "oxr_xret.h" #include "oxr_roles.h" #include "actions/oxr_input.h" +#include "actions/oxr_session_action_context.h" #include "actions/oxr_binding.h" #include @@ -1062,21 +1063,7 @@ oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb) XrResult ret = oxr_event_remove_session_events(log, sess); - oxr_interaction_profile_array_clear(&sess->profiles_on_attachment); - - for (size_t i = 0; i < sess->action_set_attachment_count; ++i) { - oxr_action_set_attachment_teardown(&sess->act_set_attachments[i]); - } - free(sess->act_set_attachments); - sess->act_set_attachments = NULL; - sess->action_set_attachment_count = 0; - - // If we tore everything down correctly, these are empty now. - assert(sess->act_sets_attachments_by_key == NULL || u_hashmap_int_empty(sess->act_sets_attachments_by_key)); - assert(sess->act_attachments_by_key == NULL || u_hashmap_int_empty(sess->act_attachments_by_key)); - - u_hashmap_int_destroy(&sess->act_sets_attachments_by_key); - u_hashmap_int_destroy(&sess->act_attachments_by_key); + oxr_session_action_context_fini(&sess->action_context); xrt_comp_destroy(&sess->compositor); xrt_comp_native_destroy(&sess->xcn); @@ -1085,7 +1072,6 @@ oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb) os_precise_sleeper_deinit(&sess->sleeper); oxr_frame_sync_fini(&sess->frame_sync); os_mutex_destroy(&sess->active_wait_frames_lock); - os_mutex_destroy(&sess->sync_actions_mutex); free(sess); @@ -1099,8 +1085,15 @@ oxr_session_allocate_and_init(struct oxr_logger *log, struct oxr_session **out_session) { struct oxr_session *sess = NULL; + XrResult ret; OXR_ALLOCATE_HANDLE_OR_RETURN(log, sess, OXR_XR_DEBUG_SESSION, oxr_session_destroy, &sys->inst->handle); + // Needs to happen early due to mutex. + ret = oxr_session_action_context_init(&sess->action_context); + if (ret != XR_SUCCESS) { + return oxr_error(log, ret, "Failed to initialize action context"); + } + // What graphics API type was this created with. sess->gfx_ext = gfx_ext; @@ -1116,19 +1109,11 @@ oxr_session_allocate_and_init(struct oxr_logger *log, sess->active_wait_frames = 0; os_mutex_init(&sess->active_wait_frames_lock); - // Initialize dynamic roles generation_id and mutex - sess->dynamic_roles_generation_id = 0; - os_mutex_init(&sess->sync_actions_mutex); - // Debug and user options. sess->ipd_meters = debug_get_num_option_ipd() / 1000.0f; sess->frame_timing_spew = debug_get_bool_option_frame_timing_spew(); sess->frame_timing_wait_sleep_ms = debug_get_num_option_wait_frame_sleep(); - // Action system hashmaps. - u_hashmap_int_create(&sess->act_sets_attachments_by_key); - u_hashmap_int_create(&sess->act_attachments_by_key); - // This is set to something valid in begin session, used in xrEndFrame. sess->current_view_config_type = XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM;