diff --git a/src/xrt/state_trackers/oxr/oxr_input.c b/src/xrt/state_trackers/oxr/oxr_input.c index 4592d4884..182cd8dff 100644 --- a/src/xrt/state_trackers/oxr/oxr_input.c +++ b/src/xrt/state_trackers/oxr/oxr_input.c @@ -69,24 +69,111 @@ oxr_source_bind_inputs(struct oxr_logger *log, struct oxr_interaction_profile *profile, enum oxr_sub_action_path sub_path); -static XrResult -oxr_action_attachment_destroy_cb(struct oxr_logger *log, - struct oxr_handle_base *hb); +/* + * + * Action attachment functions + * + */ /*! - * Create an action attachment in the given action set attachment, for the - * specified action. + * De-initialize/de-allocate all dynamic members of @ref oxr_source_cache + * @private @memberof oxr_source_cache + */ +static void +oxr_source_cache_teardown(struct oxr_source_cache *cache) +{ + free(cache->inputs); + cache->inputs = NULL; + free(cache->outputs); + cache->outputs = NULL; +} + +/*! + * Tear down an action attachment struct. * - * @private @memberof oxr_action_set_attachment + * Does not deallocate the struct itself. + * + * @public @memberof oxr_action_attachment + */ +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->key); + oxr_source_cache_teardown(&(act_attached->user)); + oxr_source_cache_teardown(&(act_attached->head)); + oxr_source_cache_teardown(&(act_attached->left)); + oxr_source_cache_teardown(&(act_attached->right)); + oxr_source_cache_teardown(&(act_attached->gamepad)); +} + +/*! + * Set up an action attachment struct. + * + * @public @memberof oxr_action_attachment */ static XrResult -oxr_action_attachment_create(struct oxr_logger *log, - struct oxr_action_set_attachment *act_set_attached, - struct oxr_action *act, - struct oxr_interaction_profile *head, - struct oxr_interaction_profile *left, - struct oxr_interaction_profile *right, - struct oxr_interaction_profile *gamepad); +oxr_action_attachment_init(struct oxr_logger *log, + struct oxr_action_set_attachment *act_set_attached, + struct oxr_action_attachment *act_attached, + struct oxr_action *act) +{ + 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->key, + act_attached); + + // Need to copy these, since we may outlive the action handle. + act_attached->action_type = act->action_type; + act_attached->key = act->key; + return XR_SUCCESS; +} + + +/* + * + * Action set attachment functions + * + */ + +/*! + * @public @memberof oxr_action_set_attachment + */ +static XrResult +oxr_action_set_attachment_init( + struct oxr_logger *log, + struct oxr_session *sess, + struct oxr_action_set *act_set, + struct oxr_action_set_attachment *act_set_attached) +{ + act_set_attached->sess = sess; + + u_hashmap_int_insert(sess->act_sets_attachments_by_key, act_set->key, + act_set_attached); + + // Need to copy these, since we may outlive the action handle. + act_set_attached->key = act_set->key; + + return XR_SUCCESS; +} + +void +oxr_action_set_attachment_teardown( + struct oxr_action_set_attachment *act_set_attached) +{ + for (size_t i = 0; i < act_set_attached->num_action_attachments; ++i) { + oxr_action_attachment_teardown( + &(act_set_attached->act_attachments[i])); + } + free(act_set_attached->act_attachments); + act_set_attached->act_attachments = NULL; + act_set_attached->num_action_attachments = 0; + + struct oxr_session *sess = act_set_attached->sess; + u_hashmap_int_erase(sess->act_sets_attachments_by_key, + act_set_attached->key); +} /* @@ -574,104 +661,22 @@ get_binding(struct oxr_logger *log, } -/* - * - * Source set functions - * - */ - -static XrResult -oxr_action_set_attachment_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb) -{ - //! @todo Move to oxr_objects.h - struct oxr_action_set_attachment *act_set_attached = - (struct oxr_action_set_attachment *)hb; - - free(act_set_attached); - - return XR_SUCCESS; -} - -static XrResult -oxr_action_set_attachment_create(struct oxr_logger *log, - struct oxr_session *sess, - struct oxr_action_set *act_set, - struct oxr_action_set_attachment **out_src_set) -{ - struct oxr_action_set_attachment *act_set_attached = NULL; - OXR_ALLOCATE_HANDLE_OR_RETURN(log, act_set_attached, - OXR_XR_DEBUG_SOURCESET, - oxr_action_set_attachment_destroy_cb, &sess->handle); - - act_set_attached->sess = sess; - u_hashmap_int_insert(sess->act_sets, act_set->key, act_set_attached); - - act_set_attached->next = sess->src_set_list; - sess->src_set_list = act_set_attached; - - *out_src_set = act_set_attached; - - return XR_SUCCESS; -} - - -/* - * - * Source functions - * - */ /*! - * De-initialize/de-allocate all dynamic members of @ref oxr_source_cache - * @private @memberof oxr_source_cache + * @public @memberof oxr_action_attachment */ -static void -oxr_source_cache_teardown(struct oxr_source_cache *cache) -{ - free(cache->inputs); - cache->inputs = NULL; - free(cache->outputs); - cache->outputs = NULL; -} - static XrResult -oxr_action_attachment_destroy_cb(struct oxr_logger *log, - struct oxr_handle_base *hb) +oxr_action_attachment_bind(struct oxr_logger *log, + struct oxr_action_attachment *act_attached, + struct oxr_action *act, + struct oxr_interaction_profile *head, + struct oxr_interaction_profile *left, + struct oxr_interaction_profile *right, + struct oxr_interaction_profile *gamepad) { - //! @todo Move to oxr_objects.h - struct oxr_action_attachment *act_attached = - (struct oxr_action_attachment *)hb; - oxr_source_cache_teardown(&(act_attached->user)); - oxr_source_cache_teardown(&(act_attached->head)); - oxr_source_cache_teardown(&(act_attached->left)); - oxr_source_cache_teardown(&(act_attached->right)); - oxr_source_cache_teardown(&(act_attached->gamepad)); - free(act_attached); - - return XR_SUCCESS; -} - -static XrResult -oxr_action_attachment_create(struct oxr_logger *log, - struct oxr_action_set_attachment *act_set_attached, - struct oxr_action *act, - struct oxr_interaction_profile *head, - struct oxr_interaction_profile *left, - struct oxr_interaction_profile *right, - struct oxr_interaction_profile *gamepad) -{ - struct oxr_session *sess = act_set_attached->sess; - struct oxr_action_attachment *act_attached = NULL; struct oxr_sink_logger slog = {0}; - OXR_ALLOCATE_HANDLE_OR_RETURN(log, act_attached, OXR_XR_DEBUG_SOURCE, - oxr_action_attachment_destroy_cb, - &act_set_attached->handle); - u_hashmap_int_insert(act_set_attached->sess->sources, act->key, - act_attached); - - // Need to copy this. - act_attached->action_type = act->action_type; + struct oxr_session *sess = act_attached->sess; // Start logging into a single buffer. oxr_slog(&slog, ": Binding %s/%s\n", act->act_set->name, act->name); @@ -1034,7 +1039,8 @@ oxr_session_get_action_set_attachment( *act_set = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_action_set *, actionSet); - int ret = u_hashmap_int_find(sess->act_sets, (*act_set)->key, &ptr); + int ret = u_hashmap_int_find(sess->act_sets_attachments_by_key, + (*act_set)->key, &ptr); if (ret == 0) { *act_set_attached = (struct oxr_action_set_attachment *)ptr; } @@ -1054,12 +1060,25 @@ oxr_session_get_action_attachment( { void *ptr = NULL; - int ret = u_hashmap_int_find(sess->sources, act_key, &ptr); + int ret = + u_hashmap_int_find(sess->act_attachments_by_key, act_key, &ptr); if (ret == 0) { *out_act_attached = (struct oxr_action_attachment *)ptr; } } +static inline size_t +oxr_handle_base_get_num_children(struct oxr_handle_base *hb) +{ + size_t ret = 0; + for (uint32_t i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) { + if (hb->children[i] != NULL) { + ++ret; + } + } + return ret; +} + XrResult oxr_session_attach_action_sets(struct oxr_logger *log, struct oxr_session *sess, @@ -1069,30 +1088,60 @@ oxr_session_attach_action_sets(struct oxr_logger *log, struct oxr_interaction_profile *head = NULL; struct oxr_interaction_profile *left = NULL; struct oxr_interaction_profile *right = NULL; - struct oxr_action_set *act_set = NULL; - struct oxr_action_set_attachment *act_set_attached = NULL; - struct oxr_action *act = NULL; oxr_find_profile_for_device(log, inst, sess->sys->head, &head); oxr_find_profile_for_device(log, inst, sess->sys->left, &left); oxr_find_profile_for_device(log, inst, sess->sys->right, &right); + //! @todo add other subaction paths here + + // Before allocating, make sure nothing has been attached yet. - // Has any of the bound action sets been updated. for (uint32_t i = 0; i < bindInfo->countActionSets; i++) { - act_set = XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_action_set *, - bindInfo->actionSets[i]); + struct oxr_action_set *act_set = XRT_CAST_OXR_HANDLE_TO_PTR( + struct oxr_action_set *, bindInfo->actionSets[i]); + if (act_set->attached) { + return XR_ERROR_ACTIONSETS_ALREADY_ATTACHED; + } + } + + // Allocate room for list. + sess->num_action_set_attachments = bindInfo->countActionSets; + sess->act_set_attachments = U_TYPED_ARRAY_CALLOC( + struct oxr_action_set_attachment, sess->num_action_set_attachments); + + // Set up the per-session data for these action sets. + for (uint32_t i = 0; i < sess->num_action_set_attachments; i++) { + struct oxr_action_set *act_set = XRT_CAST_OXR_HANDLE_TO_PTR( + struct oxr_action_set *, bindInfo->actionSets[i]); act_set->attached = true; + struct oxr_action_set_attachment *act_set_attached = + &sess->act_set_attachments[i]; + oxr_action_set_attachment_init(log, sess, act_set, + act_set_attached); - oxr_action_set_attachment_create(log, sess, act_set, &act_set_attached); + // Allocate the action attachments for this set. + act_set_attached->num_action_attachments = + oxr_handle_base_get_num_children(&act_set->handle); + act_set_attached->act_attachments = U_TYPED_ARRAY_CALLOC( + struct oxr_action_attachment, + act_set_attached->num_action_attachments); + // Set up the per-session data for the actions. + uint32_t child_index = 0; for (uint32_t k = 0; k < XRT_MAX_HANDLE_CHILDREN; k++) { - act = (struct oxr_action *)act_set->handle.children[k]; + struct oxr_action *act = + (struct oxr_action *)act_set->handle.children[k]; if (act == NULL) { continue; } - oxr_action_attachment_create(log, act_set_attached, act, - head, left, right, NULL); + struct oxr_action_attachment *act_attached = + &act_set_attached->act_attachments[child_index]; + oxr_action_attachment_init(log, act_set_attached, + act_attached, act); + oxr_action_attachment_bind(log, act_attached, act, head, + left, right, NULL); + ++child_index; } } @@ -1141,16 +1190,14 @@ oxr_action_sync_data(struct oxr_logger *log, oxr_xdev_update(sess->sys->xdevs[i]); } - // Reset all requested source sets. - act_set_attached = sess->src_set_list; - while (act_set_attached != NULL) { + // Reset all action set attachments. + for (size_t i = 0; i < sess->num_action_set_attachments; ++i) { + act_set_attached = &sess->act_set_attachments[i]; U_ZERO(&act_set_attached->requested_sub_paths); - - // Grab the next one. - act_set_attached = act_set_attached->next; } - // Go over all action sets and update them. + // Go over all requested action sets and update their attachment. + //! @todo can be listed more than once with different paths! for (uint32_t i = 0; i < countActionSets; i++) { struct oxr_sub_paths sub_paths; oxr_session_get_action_set_attachment( @@ -1172,19 +1219,17 @@ oxr_action_sync_data(struct oxr_logger *log, sub_paths.gamepad; } - // Reset all source sets. - act_set_attached = sess->src_set_list; - while (act_set_attached != NULL) { + // Now, update all action attachments + for (size_t i = 0; i < sess->num_action_set_attachments; ++i) { + act_set_attached = &sess->act_set_attachments[i]; struct oxr_sub_paths sub_paths = act_set_attached->requested_sub_paths; - for (uint32_t k = 0; k < XRT_MAX_HANDLE_CHILDREN; k++) { - // This assumes that all children of a - // source set are actions. + for (uint32_t k = 0; + k < act_set_attached->num_action_attachments; k++) { struct oxr_action_attachment *act_attached = - (struct oxr_action_attachment *) - act_set_attached->handle.children[k]; + &act_set_attached->act_attachments[k]; if (act_attached == NULL) { continue; @@ -1193,9 +1238,6 @@ oxr_action_sync_data(struct oxr_logger *log, oxr_action_attachment_update(log, sess, act_attached, now, sub_paths); } - - // Grab the next one. - act_set_attached = act_set_attached->next; } diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h index f26a2381a..5247431c0 100644 --- a/src/xrt/state_trackers/oxr/oxr_objects.h +++ b/src/xrt/state_trackers/oxr/oxr_objects.h @@ -1181,11 +1181,27 @@ struct oxr_session bool frame_started; bool exiting; - struct u_hashmap_int *act_sets; - struct u_hashmap_int *sources; + /*! + * An array of action set attachments that this session owns. + */ + struct oxr_action_set_attachment *act_set_attachments; + /*! + * Length of @ref oxr_session::act_set_attachments. + */ + size_t num_action_set_attachments; - //! List of created source sets. - struct oxr_action_set_attachment *src_set_list; + /*! + * A map of action set key to action 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. + */ + struct u_hashmap_int *act_attachments_by_key; //! Has xrAttachSessionActionSets been called? bool actionsAttached; @@ -1301,25 +1317,46 @@ struct oxr_sub_paths * The data associated with the attachment of an Action Set (@ref * oxr_action_set) to as Session (@ref oxr_session). * + * Action sets are created as children of the Instance, but are primarily used + * with one or more Sessions. They may be used with multiple sessions at a time, + * so we can't just put the per-session information directly in the action set + * or action. Instead, we have the _attachment structures, which mirror the + * action sets and actions but are rooted under the Session: + * + * - For every action set attached to a session, that session owns a @ref + * oxr_action_set_attachment. + * - For each action in those attached action sets, the action set attachment + * owns an @ref oxr_action_attachment. + * + * We go from the public handle to the _attachment structure by using a `key` + * value and a hash map: specifically, we look up the oxr_action_set::key and + * oxr_action::key in the session. + * + * This structure has no pointer to the @ref oxr_action_set that created it + * because the application is allowed to destroy an action before the session, + * which should change nothing except not allow the application to access the + * corresponding data anymore. + * * @see oxr_action_set - * @extends oxr_handle_base */ struct oxr_action_set_attachment { - /*! - * While this isn't an OpenXR handle type, we're using the handle base - * here to easily handle ownership and destruction. - */ - struct oxr_handle_base handle; - //! Owning session. struct oxr_session *sess; + //! Unique key for the session hashmap. + uint32_t key; + //! Which sub-action paths are requested on the latest sync. struct oxr_sub_paths requested_sub_paths; - //! Next source set on this session. - struct oxr_action_set_attachment *next; + //! An array of action attachments we own. + struct oxr_action_attachment *act_attachments; + + /*! + * Length of @ref oxr_action_set_attachment::act_attachments. + */ + size_t num_action_attachments; }; /*! @@ -1411,11 +1448,19 @@ struct oxr_source_cache */ struct oxr_action_attachment { + //! The owning action set attachment + struct oxr_action_set_attachment *act_set_attached; + /*! - * While this isn't an OpenXR handle type, we're using the handle base - * here to easily handle ownership and destruction. + * The corresponding session. + * + * This will always be valid: the session outlives this object because + * it owns act_set_attached. */ - struct oxr_handle_base handle; + struct oxr_session *sess; + + //! Unique key for the session hashmap. + uint32_t key; //! Type the action this source was created from is. XrActionType action_type; @@ -1546,8 +1591,9 @@ struct oxr_swapchain * * Parent type/handle is @ref oxr_instance * - * Note, however, that an action set must be "attached" to a session (@ref - * oxr_session) to be used and not just configured. + * Note, however, that an action set must be "attached" to a session + * ( @ref oxr_session ) to be used and not just configured. + * The corresponding data is in @ref oxr_action_set_attachment. * * @obj{XrActionSet} * @extends oxr_handle_base @@ -1587,6 +1633,9 @@ struct oxr_action_set * * Parent type/handle is @ref oxr_action_set * + * For actual usage, an action is attached to a session: the corresponding data + * is in @ref oxr_action_attachment + * * @obj{XrAction} * @extends oxr_handle_base */ diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c index a05701689..1641689a8 100644 --- a/src/xrt/state_trackers/oxr/oxr_session.c +++ b/src/xrt/state_trackers/oxr/oxr_session.c @@ -1027,9 +1027,20 @@ oxr_session_destroy(struct oxr_logger *log, struct oxr_handle_base *hb) // Does a null-ptr check. xrt_comp_destroy(&sess->compositor); + for (size_t i = 0; i < sess->num_action_set_attachments; ++i) { + oxr_action_set_attachment_teardown( + &sess->act_set_attachments[i]); + } + free(sess->act_set_attachments); + sess->act_set_attachments = NULL; + sess->num_action_set_attachments = 0; - u_hashmap_int_destroy(&sess->act_sets); - u_hashmap_int_destroy(&sess->sources); + // If we tore everything down correctly, these are empty now. + assert(u_hashmap_int_empty(sess->act_sets_attachments_by_key)); + assert(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); free(sess); @@ -1151,8 +1162,8 @@ oxr_session_create(struct oxr_logger *log, oxr_session_change_state(log, sess, XR_SESSION_STATE_IDLE); oxr_session_change_state(log, sess, XR_SESSION_STATE_READY); - u_hashmap_int_create(&sess->act_sets); - u_hashmap_int_create(&sess->sources); + u_hashmap_int_create(&sess->act_sets_attachments_by_key); + u_hashmap_int_create(&sess->act_attachments_by_key); *out_session = sess;