Enable eye tracking on demand

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2223>
This commit is contained in:
Jiali Zhang 2024-05-28 20:21:59 +08:00 committed by Marge Bot
parent 357cf0e93b
commit ed1ea5af73
11 changed files with 336 additions and 0 deletions

View file

@ -44,6 +44,16 @@ get_index_for_device(const struct xrt_system_devices *xsysd, const struct xrt_de
return -1;
}
static const char *
type_to_small_string(enum xrt_device_feature_type type)
{
switch (type) {
case XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT: return "hand_tracking_left";
case XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT: return "hand_tracking_right";
case XRT_DEVICE_FEATURE_EYE_TRACKING: return "eye_tracking";
default: return "invalid";
}
}
/*
@ -71,6 +81,72 @@ get_roles(struct xrt_system_devices *xsysd, struct xrt_system_roles *out_roles)
return XRT_SUCCESS;
}
static xrt_result_t
feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type)
{
struct u_system_devices_static *usysds = u_system_devices_static(xsysd);
if (type >= XRT_DEVICE_FEATURE_MAX_ENUM) {
return XRT_ERROR_FEATURE_NOT_SUPPORTED;
}
// If it wasn't zero nothing to do.
if (!xrt_reference_inc_and_was_zero(&usysds->feature_use[type])) {
return XRT_SUCCESS;
}
xrt_result_t xret;
if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT) {
xret = xrt_device_begin_feature(xsysd->static_roles.hand_tracking.left, type);
} else if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT) {
xret = xrt_device_begin_feature(xsysd->static_roles.hand_tracking.right, type);
} else if (type == XRT_DEVICE_FEATURE_EYE_TRACKING) {
xret = xrt_device_begin_feature(xsysd->static_roles.eyes, type);
} else {
xret = XRT_ERROR_FEATURE_NOT_SUPPORTED;
}
if (xret != XRT_SUCCESS) {
return xret;
}
U_LOG_D("Device-feature %s in use", type_to_small_string(type));
return XRT_SUCCESS;
}
static xrt_result_t
feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type)
{
struct u_system_devices_static *usysds = u_system_devices_static(xsysd);
if (type >= XRT_DEVICE_FEATURE_MAX_ENUM) {
return XRT_ERROR_FEATURE_NOT_SUPPORTED;
}
// If it is not zero we are done.
if (!xrt_reference_dec_and_is_zero(&usysds->feature_use[type])) {
return XRT_SUCCESS;
}
xrt_result_t xret;
if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT) {
xret = xrt_device_end_feature(xsysd->static_roles.hand_tracking.left, type);
} else if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT) {
xret = xrt_device_end_feature(xsysd->static_roles.hand_tracking.right, type);
} else if (type == XRT_DEVICE_FEATURE_EYE_TRACKING) {
xret = xrt_device_end_feature(xsysd->static_roles.eyes, type);
} else {
xret = XRT_ERROR_FEATURE_NOT_SUPPORTED;
}
if (xret != XRT_SUCCESS) {
return xret;
}
U_LOG_D("Device-feature %s no longer in use", type_to_small_string(type));
return XRT_SUCCESS;
}
/*
*
@ -107,6 +183,8 @@ u_system_devices_static_allocate(void)
struct u_system_devices_static *usysds = U_TYPED_CALLOC(struct u_system_devices_static);
usysds->base.base.destroy = destroy;
usysds->base.base.get_roles = get_roles;
usysds->base.base.feature_inc = feature_inc;
usysds->base.base.feature_dec = feature_dec;
return usysds;
}

View file

@ -113,6 +113,9 @@ struct u_system_devices_static
//! Is automatically returned.
struct xrt_system_roles cached;
//! Tracks usage of device features.
struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM];
};
/*!

View file

@ -219,6 +219,17 @@ struct xrt_binding_profile
size_t output_count;
};
/*!
* Higher level features for devices.
*/
enum xrt_device_feature_type
{
XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT = 0,
XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT,
XRT_DEVICE_FEATURE_EYE_TRACKING,
XRT_DEVICE_FEATURE_MAX_ENUM,
};
/*!
* @interface xrt_device
*
@ -519,6 +530,22 @@ struct xrt_device
bool *out_charging,
float *out_charge);
/*!
* Enable the feature for this device.
*
* @param[in] xdev The device.
* @param[in] type The type of device feature.
*/
xrt_result_t (*begin_feature)(struct xrt_device *xdev, enum xrt_device_feature_type type);
/*!
* Disable the feature for this device.
*
* @param[in] xdev The device.
* @param[in] type The type of device feature.
*/
xrt_result_t (*end_feature)(struct xrt_device *xdev, enum xrt_device_feature_type type);
/*!
* Destroy device.
*/
@ -736,6 +763,38 @@ xrt_device_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *
return xdev->get_battery_status(xdev, out_present, out_charging, out_charge);
}
/*!
* Helper function for @ref xrt_device::begin_feature.
*
* @copydoc xrt_device::begin_feature
*
* @public @memberof xrt_device
*/
static inline xrt_result_t
xrt_device_begin_feature(struct xrt_device *xdev, enum xrt_device_feature_type type)
{
if (xdev->begin_feature == NULL) {
return XRT_ERROR_NOT_IMPLEMENTED;
}
return xdev->begin_feature(xdev, type);
}
/*!
* Helper function for @ref xrt_device::end_feature.
*
* @copydoc xrt_device::end_feature
*
* @public @memberof xrt_device
*/
static inline xrt_result_t
xrt_device_end_feature(struct xrt_device *xdev, enum xrt_device_feature_type type)
{
if (xdev->end_feature == NULL) {
return XRT_ERROR_NOT_IMPLEMENTED;
}
return xdev->end_feature(xdev, type);
}
/*!
* Helper function for @ref xrt_device::destroy.
*

View file

@ -193,4 +193,9 @@ typedef enum xrt_result
* Some other Android error, typically a logic error that should be impossible to reach.
*/
XRT_ERROR_ANDROID = -31,
/*!
* Returned when a feature is not supported by the device.
*/
XRT_ERROR_FEATURE_NOT_SUPPORTED = -32,
} xrt_result_t;

View file

@ -13,6 +13,7 @@
#include "xrt/xrt_compiler.h"
#include "xrt/xrt_defines.h"
#include "xrt/xrt_device.h"
#ifdef __cplusplus
@ -301,6 +302,24 @@ struct xrt_system_devices
*/
xrt_result_t (*get_roles)(struct xrt_system_devices *xsysd, struct xrt_system_roles *out_roles);
/*!
* Increment the usage count of a feature.
* When the feature is used for the first time, then the feature will be begun.
*
* @param xsysd Pointer to self
* @param feature Which feature is being counted.
*/
xrt_result_t (*feature_inc)(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type);
/*!
* Decrement the usage count of a feature.
* When the feature is not used by the current application any more, then the feature will be ended.
*
* @param xsysd Pointer to self
* @param feature Which feature is being counted.
*/
xrt_result_t (*feature_dec)(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type);
/*!
* Destroy all the devices that are owned by this system devices.
*
@ -324,6 +343,32 @@ xrt_system_devices_get_roles(struct xrt_system_devices *xsysd, struct xrt_system
return xsysd->get_roles(xsysd, out_roles);
}
/*!
* @copydoc xrt_system_devices::feature_inc
*
* Helper for calling through the function pointer.
*
* @public @memberof xrt_system_devices
*/
static inline xrt_result_t
xrt_system_devices_feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type)
{
return xsysd->feature_inc(xsysd, type);
}
/*!
* @copydoc xrt_system_devices::feature_dec
*
* Helper for calling through the function pointer.
*
* @public @memberof xrt_system_devices
*/
static inline xrt_result_t
xrt_system_devices_feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type)
{
return xsysd->feature_dec(xsysd, type);
}
/*!
* Destroy an xrt_system_devices and owned devices - helper function.
*

View file

@ -21,6 +21,8 @@ struct ipc_client_system_devices
//! Connection to service.
struct ipc_connection *ipc_c;
struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM];
};
@ -51,6 +53,41 @@ ipc_client_system_devices_get_roles(struct xrt_system_devices *xsysd, struct xrt
return ipc_call_system_devices_get_roles(usysd->ipc_c, out_roles);
}
static xrt_result_t
ipc_client_system_devices_feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type)
{
struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd);
xrt_result_t xret;
assert(type < XRT_DEVICE_FEATURE_MAX_ENUM);
// If it wasn't zero nothing to do.
if (!xrt_reference_inc_and_was_zero(&usysd->feature_use[type])) {
return XRT_SUCCESS;
}
xret = ipc_call_system_devices_begin_feature(usysd->ipc_c, type);
IPC_CHK_ALWAYS_RET(usysd->ipc_c, xret, "ipc_call_system_devices_begin_feature");
}
static xrt_result_t
ipc_client_system_devices_feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type)
{
struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd);
xrt_result_t xret;
assert(type < XRT_DEVICE_FEATURE_MAX_ENUM);
// If it is not zero we are done.
if (!xrt_reference_dec_and_is_zero(&usysd->feature_use[type])) {
return XRT_SUCCESS;
}
xret = ipc_call_system_devices_end_feature(usysd->ipc_c, type);
IPC_CHK_ALWAYS_RET(usysd->ipc_c, xret, "ipc_call_system_devices_end_feature");
}
static void
ipc_client_system_devices_destroy(struct xrt_system_devices *xsysd)
{
@ -74,6 +111,8 @@ ipc_client_system_devices_create(struct ipc_connection *ipc_c)
struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices);
icsd->base.base.get_roles = ipc_client_system_devices_get_roles;
icsd->base.base.destroy = ipc_client_system_devices_destroy;
icsd->base.base.feature_inc = ipc_client_system_devices_feature_inc;
icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec;
icsd->ipc_c = ipc_c;
return &icsd->base.base;

View file

@ -131,6 +131,9 @@ struct ipc_client_state
//! Which of the references spaces is the client using.
bool ref_space_used[XRT_SPACE_REFERENCE_TYPE_COUNT];
//! Which of the device features is the client using.
bool device_feature_used[XRT_DEVICE_FEATURE_MAX_ENUM];
//! Socket fd used for client comms
struct ipc_message_channel imc;

View file

@ -113,6 +113,18 @@ validate_reference_space_type(volatile struct ipc_client_state *ics, enum xrt_re
return XRT_SUCCESS;
}
static xrt_result_t
validate_device_feature_type(volatile struct ipc_client_state *ics, enum xrt_device_feature_type type)
{
if ((uint32_t)type >= XRT_DEVICE_FEATURE_MAX_ENUM) {
IPC_ERROR(ics->server, "Invalid device feature type %u", type);
return XRT_ERROR_FEATURE_NOT_SUPPORTED;
}
return XRT_SUCCESS;
}
static xrt_result_t
validate_space_id(volatile struct ipc_client_state *ics, int64_t space_id, struct xrt_space **out_xspc)
{
@ -2150,6 +2162,63 @@ ipc_handle_system_devices_get_roles(volatile struct ipc_client_state *ics, struc
return xrt_system_devices_get_roles(ics->server->xsysd, out_roles);
}
xrt_result_t
ipc_handle_system_devices_begin_feature(volatile struct ipc_client_state *ics, enum xrt_device_feature_type type)
{
struct xrt_system_devices *xsysd = ics->server->xsysd;
xrt_result_t xret;
xret = validate_device_feature_type(ics, type);
if (xret != XRT_SUCCESS) {
return XRT_ERROR_IPC_FAILURE;
}
// Is this feature already used?
if (ics->device_feature_used[type]) {
IPC_ERROR(ics->server, "feature '%u' already used!", type);
return XRT_ERROR_IPC_FAILURE;
}
xret = xrt_system_devices_feature_inc(xsysd, type);
if (xret != XRT_SUCCESS) {
IPC_ERROR(ics->server, "xrt_system_devices_feature_inc failed");
return xret;
}
// Can now mark it as used.
ics->device_feature_used[type] = true;
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_system_devices_end_feature(volatile struct ipc_client_state *ics, enum xrt_device_feature_type type)
{
struct xrt_system_devices *xsysd = ics->server->xsysd;
xrt_result_t xret;
xret = validate_device_feature_type(ics, type);
if (xret != XRT_SUCCESS) {
return XRT_ERROR_IPC_FAILURE;
}
if (!ics->device_feature_used[type]) {
IPC_ERROR(ics->server, "feature '%u' not used!", type);
return XRT_ERROR_IPC_FAILURE;
}
xret = xrt_system_devices_feature_dec(xsysd, type);
if (xret != XRT_SUCCESS) {
IPC_ERROR(ics->server, "xrt_system_devices_feature_dec failed");
return xret;
}
// Now we can mark it as not used.
ics->device_feature_used[type] = false;
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_device_get_face_tracking(volatile struct ipc_client_state *ics,
uint32_t id,

View file

@ -90,6 +90,17 @@ common_shutdown(volatile struct ipc_client_state *ics)
ics->ref_space_used[i] = false;
}
// Make a still in use device features as no longer used.
for (uint32_t i = 0; i < ARRAY_SIZE(ics->device_feature_used); i++) {
bool used = ics->device_feature_used[i];
if (!used) {
continue;
}
xrt_system_devices_feature_dec(ics->server->xsysd, (enum xrt_device_feature_type)i);
ics->device_feature_used[i] = false;
}
// Should we stop the server when a client disconnects?
if (ics->server->exit_on_disconnect) {
ics->server->running = false;

View file

@ -62,6 +62,18 @@
]
},
"system_devices_begin_feature": {
"in": [
{"name": "type", "type": "enum xrt_device_feature_type"}
]
},
"system_devices_end_feature": {
"in": [
{"name": "type", "type": "enum xrt_device_feature_type"}
]
},
"system_compositor_get_info": {
"out": [
{"name": "info", "type": "struct xrt_system_compositor_info"}

View file

@ -72,6 +72,12 @@ get_xrt_space_action(struct oxr_logger *log, struct oxr_space *spc, struct xrt_s
if (xret != XRT_SUCCESS) {
oxr_warn(log, "Failed to create pose space");
} else {
struct xrt_system_devices *xsysd = spc->sess->sys->xsysd;
if (xdev == xsysd->static_roles.eyes) {
// eye tracking is being used
xrt_system_devices_feature_inc(xsysd, XRT_DEVICE_FEATURE_EYE_TRACKING);
}
spc->action.xdev = xdev;
spc->action.name = name;
}
@ -128,6 +134,12 @@ oxr_space_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
xrt_space_overseer_ref_space_dec(spc->sess->sys->xso, xtype);
}
struct xrt_system_devices *xsysd = spc->sess->sys->xsysd;
if (spc->action.xdev && spc->action.xdev == xsysd->static_roles.eyes) {
// eye tracking isn't being used anymore
xrt_system_devices_feature_dec(xsysd, XRT_DEVICE_FEATURE_EYE_TRACKING);
}
xrt_space_reference(&spc->xdev_pose.xs, NULL);
xrt_space_reference(&spc->action.xs, NULL);
spc->action.xdev = NULL;