// Copyright 2019-2020, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Session entrypoints for the OpenXR state tracker. * @author Jakob Bornecrantz * @ingroup oxr_api */ #include #include #include #include #include "xrt/xrt_compiler.h" #include "util/u_debug.h" #include "oxr_objects.h" #include "oxr_logger.h" #include "oxr_two_call.h" #include "oxr_api_funcs.h" #include "oxr_api_verify.h" #include "oxr_handle.h" #include "oxr_chain.h" XrResult oxr_xrCreateSession(XrInstance instance, const XrSessionCreateInfo *createInfo, XrSession *out_session) { XrResult ret; struct oxr_instance *inst; struct oxr_session *sess, **link; struct oxr_logger log; OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrCreateSession"); ret = oxr_verify_XrSessionCreateInfo(&log, inst, createInfo); if (ret != XR_SUCCESS) { return ret; } ret = oxr_session_create(&log, &inst->system, createInfo, &sess); if (ret != XR_SUCCESS) { return ret; } *out_session = oxr_session_to_openxr(sess); /* Add to session list */ link = &inst->sessions; while (*link) { link = &(*link)->next; } *link = sess; return XR_SUCCESS; } XrResult oxr_xrDestroySession(XrSession session) { struct oxr_session *sess, **link; struct oxr_instance *inst; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrDestroySession"); /* Remove from session list */ inst = sess->sys->inst; link = &inst->sessions; while (*link != sess) { link = &(*link)->next; } *link = sess->next; return oxr_handle_destroy(&log, &sess->handle); } XrResult oxr_xrBeginSession(XrSession session, const XrSessionBeginInfo *beginInfo) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrBeginSession"); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, beginInfo, XR_TYPE_SESSION_BEGIN_INFO); OXR_VERIFY_VIEW_CONFIG_TYPE(&log, sess->sys->inst, beginInfo->primaryViewConfigurationType); return oxr_session_begin(&log, sess, beginInfo); } XrResult oxr_xrEndSession(XrSession session) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrEndSession"); return oxr_session_end(&log, sess); } XrResult oxr_xrWaitFrame(XrSession session, const XrFrameWaitInfo *frameWaitInfo, XrFrameState *frameState) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrWaitFrame"); OXR_VERIFY_ARG_TYPE_CAN_BE_NULL(&log, frameWaitInfo, XR_TYPE_FRAME_WAIT_INFO); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, frameState, XR_TYPE_FRAME_STATE); OXR_VERIFY_ARG_NOT_NULL(&log, frameState); return oxr_session_frame_wait(&log, sess, frameState); } XrResult oxr_xrBeginFrame(XrSession session, const XrFrameBeginInfo *frameBeginInfo) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrBeginFrame"); // NULL explicitly allowed here because it's a basically empty struct. OXR_VERIFY_ARG_TYPE_CAN_BE_NULL(&log, frameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO); return oxr_session_frame_begin(&log, sess); } XrResult oxr_xrEndFrame(XrSession session, const XrFrameEndInfo *frameEndInfo) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrEndFrame"); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, frameEndInfo, XR_TYPE_FRAME_END_INFO); return oxr_session_frame_end(&log, sess, frameEndInfo); } XrResult oxr_xrRequestExitSession(XrSession session) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrRequestExitSession"); return oxr_session_request_exit(&log, sess); } XrResult oxr_xrLocateViews(XrSession session, const XrViewLocateInfo *viewLocateInfo, XrViewState *viewState, uint32_t viewCapacityInput, uint32_t *viewCountOutput, XrView *views) { struct oxr_session *sess; struct oxr_space *spc; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrLocateViews"); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO); OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, viewState, XR_TYPE_VIEW_STATE); if (viewCapacityInput == 0) { OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput); } else { OXR_VERIFY_ARG_NOT_NULL(&log, views); } return oxr_session_views(&log, sess, viewLocateInfo, viewState, viewCapacityInput, viewCountOutput, views); } /* * * XR_KHR_visibility_mask * */ #ifdef XR_KHR_visibility_mask XrResult oxr_xrGetVisibilityMaskKHR(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR *visibilityMask) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrGetVisibilityMaskKHR"); return oxr_error(&log, XR_ERROR_HANDLE_INVALID, "Not implemented"); } #endif /* * * XR_EXT_performance_settings * */ #ifdef XR_EXT_performance_settings XrResult oxr_xrPerfSettingsSetPerformanceLevelEXT(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrPerfSettingsSetPerformanceLevelEXT"); return oxr_error(&log, XR_ERROR_HANDLE_INVALID, "Not implemented"); } #endif /* * * XR_EXT_thermal_query * */ #ifdef XR_EXT_thermal_query XrResult oxr_xrThermalGetTemperatureTrendEXT(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT *notificationLevel, float *tempHeadroom, float *tempSlope) { struct oxr_session *sess; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrThermalGetTemperatureTrendEXT"); return oxr_error(&log, XR_ERROR_HANDLE_INVALID, "Not implemented"); } /* * * XR_EXT_hand_tracking * */ static XrResult oxr_hand_tracker_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb) { struct oxr_hand_tracker *hand_tracker = (struct oxr_hand_tracker *)hb; free(hand_tracker); return XR_SUCCESS; } XrResult oxr_hand_tracker_create(struct oxr_logger *log, struct oxr_session *sess, const XrHandTrackerCreateInfoEXT *createInfo, struct oxr_hand_tracker **out_hand_tracker) { if (!oxr_system_get_hand_tracking_support(log, sess->sys->inst)) { return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED, "System does not support hand tracking"); } struct oxr_hand_tracker *hand_tracker = NULL; OXR_ALLOCATE_HANDLE_OR_RETURN(log, hand_tracker, OXR_XR_DEBUG_HTRACKER, oxr_hand_tracker_destroy_cb, &sess->handle); hand_tracker->sess = sess; hand_tracker->hand = createInfo->hand; hand_tracker->hand_joint_set = createInfo->handJointSet; //! @todo: Implement choice when more than one device has hand tracking for (uint32_t i = 0; i < sess->sys->num_xdevs; i++) { struct xrt_device *xdev = sess->sys->xdevs[i]; if (!xdev->hand_tracking_supported) { continue; } for (uint32_t j = 0; j < xdev->num_inputs; j++) { struct xrt_input *input = &xdev->inputs[j]; if ((input->name == XRT_INPUT_GENERIC_HAND_TRACKING_LEFT && createInfo->hand == XR_HAND_LEFT_EXT) || (input->name == XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT && createInfo->hand == XR_HAND_RIGHT_EXT)) { hand_tracker->xdev = xdev; hand_tracker->input_name = input->name; break; } } if (hand_tracker->xdev != NULL) { break; } } *out_hand_tracker = hand_tracker; return XR_SUCCESS; } XrResult oxr_xrCreateHandTrackerEXT(XrSession session, const XrHandTrackerCreateInfoEXT *createInfo, XrHandTrackerEXT *handTracker) { struct oxr_hand_tracker *hand_tracker = NULL; struct oxr_session *sess = NULL; struct oxr_logger log; XrResult ret; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrCreateHandTrackerEXT"); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT); OXR_VERIFY_ARG_NOT_NULL(&log, handTracker); OXR_VERIFY_EXTENSION(&log, sess->sys->inst, EXT_hand_tracking); if (createInfo->hand != XR_HAND_LEFT_EXT && createInfo->hand != XR_HAND_RIGHT_EXT) { return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "Invalid hand value %d\n", createInfo->hand); } if (createInfo->handJointSet != XR_HAND_JOINT_SET_DEFAULT_EXT) { return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "Invalid handJointSet value %d\n", createInfo->handJointSet); } ret = oxr_hand_tracker_create(&log, sess, createInfo, &hand_tracker); if (ret != XR_SUCCESS) { return ret; } *handTracker = oxr_hand_tracker_to_openxr(hand_tracker); return XR_SUCCESS; } XrResult oxr_xrDestroyHandTrackerEXT(XrHandTrackerEXT handTracker) { struct oxr_hand_tracker *hand_tracker; struct oxr_logger log; OXR_VERIFY_HAND_TRACKER_AND_INIT_LOG(&log, handTracker, hand_tracker, "xrDestroyHandTrackerEXT"); return oxr_handle_destroy(&log, &hand_tracker->handle); } XrResult oxr_xrLocateHandJointsEXT(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT *locateInfo, XrHandJointLocationsEXT *locations) { struct oxr_hand_tracker *hand_tracker; struct oxr_space *spc; struct oxr_logger log; OXR_VERIFY_HAND_TRACKER_AND_INIT_LOG(&log, handTracker, hand_tracker, "xrLocateHandJointsEXT"); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, locateInfo, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT); OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, locations, XR_TYPE_HAND_JOINT_LOCATIONS_EXT); OXR_VERIFY_SPACE_NOT_NULL(&log, locateInfo->baseSpace, spc); if (locateInfo->time <= (XrTime)0) { return oxr_error(&log, XR_ERROR_TIME_INVALID, "(time == %" PRIi64 ") is not a valid time.", locateInfo->time); } if (hand_tracker->hand_joint_set == XR_HAND_JOINT_SET_DEFAULT_EXT) { if (locations->jointCount != XR_HAND_JOINT_COUNT_EXT) { return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "joint count must be %d, not %d\n", XR_HAND_JOINT_COUNT_EXT, locations->jointCount); } }; XrHandJointVelocitiesEXT *vel = OXR_GET_OUTPUT_FROM_CHAIN(locations, XR_TYPE_HAND_JOINT_VELOCITIES_EXT, XrHandJointVelocitiesEXT); if (vel) { if (vel->jointCount <= 0) { return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "XrHandJointVelocitiesEXT joint count " "must be >0, is %d\n", vel->jointCount); } if (hand_tracker->hand_joint_set == XR_HAND_JOINT_SET_DEFAULT_EXT) { if (vel->jointCount != XR_HAND_JOINT_COUNT_EXT) { return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE, "XrHandJointVelocitiesEXT joint count must " "be %d, not %d\n", XR_HAND_JOINT_COUNT_EXT, locations->jointCount); } } } return oxr_session_hand_joints(&log, hand_tracker, locateInfo, locations); } #endif