// 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 "util/u_trace_marker.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) { OXR_TRACE_MARKER(); XrResult ret; struct oxr_instance *inst; struct oxr_session *sess; struct oxr_session **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) { OXR_TRACE_MARKER(); struct oxr_session *sess; struct oxr_session **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) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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); XrResult res = oxr_session_frame_begin(&log, sess); #ifdef XRT_FEATURE_RENDERDOC if (sess->sys->inst->rdoc_api) { sess->sys->inst->rdoc_api->StartFrameCapture(NULL, NULL); } #endif return res; } XrResult oxr_xrEndFrame(XrSession session, const XrFrameEndInfo *frameEndInfo) { OXR_TRACE_MARKER(); 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); #ifdef XRT_FEATURE_RENDERDOC if (sess->sys->inst->rdoc_api) { sess->sys->inst->rdoc_api->EndFrameCapture(NULL, NULL); } #endif XrResult res = oxr_session_frame_end(&log, sess, frameEndInfo); return res; } XrResult oxr_xrRequestExitSession(XrSession session) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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_locate_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) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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"); } #endif /* * * XR_EXT_hand_tracking * */ #ifdef 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; // Find the assigned device. struct xrt_device *xdev = NULL; if (createInfo->hand == XR_HAND_LEFT_EXT) { xdev = sess->sys->xsysd->roles.hand_tracking.left; } else if (createInfo->hand == XR_HAND_RIGHT_EXT) { xdev = sess->sys->xsysd->roles.hand_tracking.right; } // Find the correct input on the device. if (xdev != NULL && xdev->hand_tracking_supported) { for (uint32_t j = 0; j < xdev->input_count; 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; } } } // Consistency checking. if (xdev != NULL && hand_tracker->xdev == NULL) { oxr_warn(log, "We got hand tracking xdev but it didn't have a hand tracking input."); } *out_hand_tracker = hand_tracker; return XR_SUCCESS; } XrResult oxr_xrCreateHandTrackerEXT(XrSession session, const XrHandTrackerCreateInfoEXT *createInfo, XrHandTrackerEXT *handTracker) { OXR_TRACE_MARKER(); 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); } 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) { OXR_TRACE_MARKER(); 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) { OXR_TRACE_MARKER(); 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_ARG_NOT_NULL(&log, locations->jointLocations); 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 /* * * XR_FB_display_refresh_rate * */ #ifdef XR_FB_display_refresh_rate XrResult oxr_xrEnumerateDisplayRefreshRatesFB(XrSession session, uint32_t displayRefreshRateCapacityInput, uint32_t *displayRefreshRateCountOutput, float *displayRefreshRates) { struct oxr_session *sess = NULL; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrEnumerateDisplayRefreshRatesFB"); // headless if (!sess->sys->xsysc) { *displayRefreshRateCountOutput = 0; return XR_SUCCESS; } OXR_TWO_CALL_HELPER(&log, displayRefreshRateCapacityInput, displayRefreshRateCountOutput, displayRefreshRates, sess->sys->xsysc->info.num_refresh_rates, sess->sys->xsysc->info.refresh_rates, XR_SUCCESS); } XrResult oxr_xrGetDisplayRefreshRateFB(XrSession session, float *displayRefreshRate) { struct oxr_session *sess = NULL; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrEnumerateDisplayRefreshRatesFB"); // headless if (!sess->sys->xsysc) { *displayRefreshRate = 0.0f; return XR_SUCCESS; } OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrGetDisplayRefreshRateFB"); if (sess->sys->xsysc->info.num_refresh_rates < 1) { return XR_ERROR_RUNTIME_FAILURE; } *displayRefreshRate = sess->sys->xsysc->info.refresh_rates[0]; return XR_SUCCESS; } XrResult oxr_xrRequestDisplayRefreshRateFB(XrSession session, float displayRefreshRate) { struct oxr_session *sess = NULL; struct oxr_logger log; OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrRequestDisplayRefreshRateFB"); //! @todo support for changing refresh rates return XR_SUCCESS; } #endif