mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-24 07:31:48 +00:00
d6cc662d11
There is another handtracker type in spec. And also we can support other jointCount handtracker. So checking this default value is not necessary.
522 lines
14 KiB
C
522 lines
14 KiB
C
// Copyright 2019-2020, Collabora, Ltd.
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
/*!
|
|
* @file
|
|
* @brief Session entrypoints for the OpenXR state tracker.
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
* @ingroup oxr_api
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#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
|