xrt: Add support for assigned device roles

Abandons the assumption that in oxr_system.xdevs[], index 0 is HMD,
1 is left controller, 2 is right controller.

Now to represent the dynamically assigned roles, oxr_system.role contains
the index for a device in oxr_system.xdevs[] for head, left and right.

This role assignment happens on the client side and currently can not be updated
from the server side.

Also adds an enum that device drivers set indicating allowed assignments
(many controllers are physically designed to be held in a specific hand).

This also adds support for configurations with only a HMD and a right controller.
This commit is contained in:
Christoph Haag 2020-07-07 02:14:29 +02:00
parent 5788fb90a2
commit b073e3dfb9
28 changed files with 184 additions and 73 deletions

View file

@ -434,6 +434,7 @@ arduino_device_create(struct os_ble_device *ble,
ad->base.orientation_tracking_supported = true;
ad->base.position_tracking_supported = false;
ad->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
ARDUINO_DEBUG(ad, "Created device!");

View file

@ -390,6 +390,7 @@ daydream_device_create(struct os_ble_device *ble,
dd->base.orientation_tracking_supported = true;
dd->base.position_tracking_supported = false;
dd->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
DAYDREAM_DEBUG(dd, "Created device!");

View file

@ -199,6 +199,7 @@ dummy_hmd_create(void)
// Setup the distortion mesh.
u_distortion_mesh_none(dh->base.hmd);
}
dh->base.device_type = XRT_DEVICE_TYPE_HMD;
return &dh->base;
}

View file

@ -512,6 +512,7 @@ hdk_device_create(struct os_hid_device *dev,
hd->base.orientation_tracking_supported = true;
hd->base.position_tracking_supported = false;
hd->base.device_type = XRT_DEVICE_TYPE_HMD;
return hd;
}

View file

@ -714,7 +714,9 @@ hydra_found(struct xrt_prober *xp,
}
hs->devs[0]->base.orientation_tracking_supported = true;
hs->devs[0]->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
hs->devs[1]->base.position_tracking_supported = true;
hs->devs[1]->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
printf("Opened razer hydra!\n");
return 2;

View file

@ -364,6 +364,7 @@ ns_hmd_create(const char *config_path, bool print_spew, bool print_debug)
ns->base.orientation_tracking_supported = true;
//! @todo: Set to true when T265 is used
ns->base.position_tracking_supported = false;
ns->base.device_type = XRT_DEVICE_TYPE_HMD;
return &ns->base;

View file

@ -134,6 +134,7 @@ oh_prober_autoprobe(struct xrt_auto_prober *xap,
ohd->base.orientation_tracking_supported =
orientation_tracking_supported;
ohd->base.position_tracking_supported = position_tracking_supported;
ohd->base.device_type = XRT_DEVICE_TYPE_HMD;
return &ohd->base;
}

View file

@ -1153,6 +1153,7 @@ psmv_found(struct xrt_prober *xp,
psmv->base.orientation_tracking_supported = true;
psmv->base.position_tracking_supported = psmv->ball != NULL;
psmv->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
// And finally done
*out_xdevs = &psmv->base;

View file

@ -1145,6 +1145,7 @@ psvr_device_create(struct hid_device_info *hmd_handle_info,
psvr->base.orientation_tracking_supported = true;
psvr->base.position_tracking_supported = false;
psvr->base.device_type = XRT_DEVICE_TYPE_HMD;
PSVR_DEBUG(psvr, "YES!");

View file

@ -285,6 +285,7 @@ rs_6dof_create(void)
rs->base.orientation_tracking_supported = true;
rs->base.position_tracking_supported = true;
rs->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER;
return &rs->base;
}

View file

@ -976,6 +976,7 @@ _create_hmd_device(struct survive_system *sys)
survive->base.orientation_tracking_supported = true;
survive->base.position_tracking_supported = true;
survive->base.device_type = XRT_DEVICE_TYPE_HMD;
return true;
}
@ -1054,6 +1055,11 @@ _create_controller_device(struct survive_system *sys, int controller_num)
controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH]
.value.boolean = false;
//! @todo: find out left/right hand from survive
controller->base.device_type =
XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
} else {
controller->base.name = XRT_DEVICE_VIVE_WAND;
snprintf(controller->base.str, XRT_DEVICE_NAME_LEN,

View file

@ -1106,6 +1106,8 @@ vive_controller_create(struct os_hid_device *controller_hid,
d->base.update_inputs =
vive_controller_device_update_wand_inputs;
d->base.device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
} else if (d->variant == CONTROLLER_INDEX_LEFT ||
d->variant == CONTROLLER_INDEX_RIGHT) {
d->base.name = XRT_DEVICE_INDEX_CONTROLLER;
@ -1136,14 +1138,24 @@ vive_controller_create(struct os_hid_device *controller_hid,
d->base.update_inputs =
vive_controller_device_update_index_inputs;
if (d->variant == CONTROLLER_INDEX_LEFT) {
d->base.device_type =
XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER;
} else if (d->variant == CONTROLLER_INDEX_RIGHT) {
d->base.device_type =
XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER;
}
} else if (d->variant == CONTROLLER_TRACKER_GEN1) {
d->base.name = XRT_DEVICE_VIVE_TRACKER_GEN1;
d->base.update_inputs = _update_tracker_inputs;
d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER;
} else if (d->variant == CONTROLLER_TRACKER_GEN2) {
d->base.name = XRT_DEVICE_VIVE_TRACKER_GEN2;
d->base.update_inputs = _update_tracker_inputs;
d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER;
} else {
d->base.name = XRT_DEVICE_GENERIC_HMD;
d->base.device_type = XRT_DEVICE_TYPE_GENERIC_TRACKER;
VIVE_ERROR(d, "Failed to assign update input function");
}

View file

@ -711,6 +711,7 @@ vive_device_create(struct os_hid_device *mainboard_dev,
d->base.orientation_tracking_supported = true;
d->base.position_tracking_supported = false;
d->base.device_type = XRT_DEVICE_TYPE_HMD;
ret = os_thread_helper_start(&d->sensors_thread,
vive_sensors_run_thread, d);

View file

@ -390,6 +390,21 @@ enum xrt_device_name
XRT_DEVICE_VIVE_TRACKER_GEN2 = 8,
};
/*!
* How an xrt_device can be used.
*
* @ingroup xrt_iface
*/
enum xrt_device_type
{
XRT_DEVICE_TYPE_UNKNOWN = 0,
XRT_DEVICE_TYPE_HMD,
XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER,
XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER,
XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER,
XRT_DEVICE_TYPE_GENERIC_TRACKER
};
/*!
* Base type of this inputs.
*

View file

@ -205,6 +205,7 @@ struct xrt_device
{
//! Enum identifier of the device.
enum xrt_device_name name;
enum xrt_device_type device_type;
//! A string describing the device.
char str[XRT_DEVICE_NAME_LEN];

View file

@ -178,5 +178,6 @@ ipc_client_device_create(ipc_connection_t *ipc_c,
u_var_add_root(icd, icd->base.str, true);
u_var_add_ro_u32(icd, &icd->device_id, "device_id");
icd->base.device_type = idev->device_type;
return &icd->base;
}

View file

@ -201,6 +201,7 @@ ipc_client_hmd_create(ipc_connection_t *ipc_c,
idev->orientation_tracking_supported;
ich->base.position_tracking_supported =
idev->position_tracking_supported;
ich->base.device_type = idev->device_type;
return &ich->base;
}

View file

@ -58,6 +58,7 @@ struct ipc_shared_device
{
//! Enum identifier of the device.
enum xrt_device_name name;
enum xrt_device_type device_type;
//! Which tracking system origin is this device attached to.
uint32_t tracking_origin_index;

View file

@ -194,6 +194,7 @@ init_shm(struct ipc_server *s)
xdev->orientation_tracking_supported;
idev->position_tracking_supported =
xdev->position_tracking_supported;
idev->device_type = xdev->device_type;
// Is this a HMD?
if (xdev->hmd != NULL) {

View file

@ -595,15 +595,15 @@ get_binding(struct oxr_logger *log,
break;
case OXR_SUB_ACTION_PATH_HEAD:
user_path_str = "/user/head";
xdev = sess->sys->head;
xdev = GET_XDEV_BY_ROLE(sess->sys, head);
break;
case OXR_SUB_ACTION_PATH_LEFT:
user_path_str = "/user/hand/left";
xdev = sess->sys->left;
xdev = GET_XDEV_BY_ROLE(sess->sys, left);
break;
case OXR_SUB_ACTION_PATH_RIGHT:
user_path_str = "/user/hand/right";
xdev = sess->sys->right;
xdev = GET_XDEV_BY_ROLE(sess->sys, right);
break;
case OXR_SUB_ACTION_PATH_GAMEPAD:
user_path_str = "/user/hand/gamepad";
@ -1170,13 +1170,18 @@ oxr_session_attach_action_sets(struct oxr_logger *log,
const XrSessionActionSetsAttachInfo *bindInfo)
{
struct oxr_instance *inst = sess->sys->inst;
struct oxr_interaction_profile *head = NULL;
struct oxr_interaction_profile *left = NULL;
struct oxr_interaction_profile *right = 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);
oxr_find_profile_for_device(log, inst,
GET_XDEV_BY_ROLE(sess->sys, head), &head);
oxr_find_profile_for_device(log, inst,
GET_XDEV_BY_ROLE(sess->sys, left), &left);
oxr_find_profile_for_device(log, inst,
GET_XDEV_BY_ROLE(sess->sys, right), &right);
//! @todo add other subaction paths here
// Allocate room for list. No need to check if anything has been

View file

@ -100,6 +100,47 @@ cache_path(struct oxr_logger *log,
#define NUM_XDEVS 16
static void
assign_xdev_roles(struct oxr_instance *inst)
{
struct oxr_system *sys = &inst->system;
for (size_t i = 0; i < NUM_XDEVS; i++) {
if (sys->xdevs[i] == NULL) {
continue;
}
if (sys->xdevs[i]->device_type == XRT_DEVICE_TYPE_HMD) {
sys->role.head = i;
} else if (sys->xdevs[i]->device_type ==
XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) {
if (sys->role.left == XRT_DEVICE_ROLE_UNASSIGNED) {
sys->role.left = i;
}
} else if (sys->xdevs[i]->device_type ==
XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER) {
if (sys->role.right == XRT_DEVICE_ROLE_UNASSIGNED) {
sys->role.right = i;
}
} else if (sys->xdevs[i]->device_type ==
XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER) {
if (sys->role.left == XRT_DEVICE_ROLE_UNASSIGNED) {
sys->role.left = i;
} else if (sys->role.left ==
XRT_DEVICE_ROLE_UNASSIGNED) {
sys->role.right = i;
} else {
//! @todo: do something with unassigend devices?
}
}
}
}
static inline size_t
min_size_t(size_t a, size_t b)
{
return a < b ? a : b;
}
XrResult
oxr_instance_create(struct oxr_logger *log,
const XrInstanceCreateInfo *createInfo,
@ -194,17 +235,33 @@ oxr_instance_create(struct oxr_logger *log,
return ret;
}
struct oxr_system *sys = &inst->system;
sys->role.head = XRT_DEVICE_ROLE_UNASSIGNED;
sys->role.left = XRT_DEVICE_ROLE_UNASSIGNED;
sys->role.right = XRT_DEVICE_ROLE_UNASSIGNED;
sys->num_xdevs = min_size_t(ARRAY_SIZE(sys->xdevs), NUM_XDEVS);
for (uint32_t i = 0; i < sys->num_xdevs; i++) {
sys->xdevs[i] = xdevs[i];
}
for (size_t i = sys->num_xdevs; i < NUM_XDEVS; i++) {
oxr_xdev_destroy(&xdevs[i]);
}
assign_xdev_roles(inst);
// Did we find any HMD
// @todo Headless with only controllers?
if (xdevs[0] == NULL) {
struct xrt_device *dev = GET_XDEV_BY_ROLE(sys, head);
if (dev == NULL) {
ret = oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
"Failed to find any HMD device");
oxr_instance_destroy(log, &inst->handle);
return ret;
}
struct xrt_device *dev = xdevs[0];
const float left_override = debug_get_float_option_lfov_left();
if (left_override != 0.0f) {
printf(

View file

@ -1026,6 +1026,8 @@ struct oxr_handle_base
oxr_handle_destroyer destroy;
};
#define XRT_DEVICE_ROLE_UNASSIGNED (-1)
/*!
* Single or multiple devices grouped together to form a system that sessions
* can be created from. Might need to open devices in order to get all
@ -1040,17 +1042,15 @@ struct oxr_handle_base
struct oxr_system
{
struct oxr_instance *inst;
union {
struct
{
struct xrt_device *head;
struct xrt_device *left;
struct xrt_device *right;
};
struct xrt_device *xdevs[16];
};
struct xrt_device *xdevs[16];
size_t num_xdevs;
/* index for xdevs array */
struct
{
int head;
int left;
int right;
} role;
XrSystemId systemId;
@ -1064,6 +1064,11 @@ struct oxr_system
XrEnvironmentBlendMode blend_modes[3];
};
#define GET_XDEV_BY_ROLE(SYS, ROLE) \
SYS->role.ROLE == XRT_DEVICE_ROLE_UNASSIGNED \
? NULL \
: SYS->xdevs[SYS->role.ROLE]
#define MAKE_EXT_STATUS(mixed_case, all_caps) bool mixed_case;
/*!
* Structure tracking which extensions are enabled for a given instance.

View file

@ -278,7 +278,7 @@ oxr_session_get_view_pose_at(struct oxr_logger *log,
// @todo If using orientation tracking only implement a neck model to
// get at least a slightly better position.
struct xrt_device *xdev = sess->sys->head;
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
struct xrt_space_relation relation;
uint64_t timestamp;
@ -368,7 +368,7 @@ oxr_session_views(struct oxr_logger *log,
uint32_t *viewCountOutput,
XrView *views)
{
struct xrt_device *xdev = sess->sys->head;
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
struct oxr_space *baseSpc = XRT_CAST_OXR_HANDLE_TO_PTR(
struct oxr_space *, viewLocateInfo->space);
uint32_t num_views = 2;
@ -1015,7 +1015,8 @@ oxr_session_frame_end(struct oxr_logger *log,
frameEndInfo->environmentBlendMode);
}
if ((blend_mode & sess->sys->head->hmd->blend_mode) == 0) {
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
if ((blend_mode & xdev->hmd->blend_mode) == 0) {
//! @todo Make integer print to string.
return oxr_error(log,
XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED,
@ -1060,12 +1061,12 @@ oxr_session_frame_end(struct oxr_logger *log,
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
res = verify_projection_layer(
xc, log, i, (XrCompositionLayerProjection *)layer,
sess->sys->head, frameEndInfo->displayTime);
xdev, frameEndInfo->displayTime);
break;
case XR_TYPE_COMPOSITION_LAYER_QUAD:
res = verify_quad_layer(
xc, log, i, (XrCompositionLayerQuad *)layer,
sess->sys->head, frameEndInfo->displayTime);
xc, log, i, (XrCompositionLayerQuad *)layer, xdev,
frameEndInfo->displayTime);
break;
default:
return oxr_error(log, XR_ERROR_LAYER_INVALID,
@ -1085,8 +1086,7 @@ oxr_session_frame_end(struct oxr_logger *log,
*/
struct xrt_pose inv_offset = {0};
math_pose_invert(&sess->sys->head->tracking_origin->offset,
&inv_offset);
math_pose_invert(&xdev->tracking_origin->offset, &inv_offset);
CALL_CHK(xrt_comp_layer_begin(xc, sess->frame_id.begun, blend_mode));
@ -1099,14 +1099,12 @@ oxr_session_frame_end(struct oxr_logger *log,
case XR_TYPE_COMPOSITION_LAYER_PROJECTION:
submit_projection_layer(
xc, log, (XrCompositionLayerProjection *)layer,
sess->sys->head, &inv_offset,
frameEndInfo->displayTime);
xdev, &inv_offset, frameEndInfo->displayTime);
break;
case XR_TYPE_COMPOSITION_LAYER_QUAD:
submit_quad_layer(xc, log,
(XrCompositionLayerQuad *)layer,
sess->sys->head, &inv_offset,
frameEndInfo->displayTime);
submit_quad_layer(
xc, log, (XrCompositionLayerQuad *)layer, xdev,
&inv_offset, frameEndInfo->displayTime);
break;
default: assert(false && "invalid layer type");
}

View file

@ -66,7 +66,9 @@ oxr_session_populate_egl(struct oxr_logger *log,
}
struct xrt_compositor_fd *xcfd = NULL;
int ret = xrt_instance_create_fd_compositor(sys->inst->xinst, sys->head,
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
int ret = xrt_instance_create_fd_compositor(sys->inst->xinst, xdev,
true, &xcfd);
if (ret < 0 || xcfd == NULL) {
return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,

View file

@ -34,7 +34,9 @@ oxr_session_populate_gl_xlib(struct oxr_logger *log,
struct oxr_session *sess)
{
struct xrt_compositor_fd *xcfd = NULL;
int ret = xrt_instance_create_fd_compositor(sys->inst->xinst, sys->head,
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
int ret = xrt_instance_create_fd_compositor(sys->inst->xinst, xdev,
true, &xcfd);
if (ret < 0 || xcfd == NULL) {
return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,

View file

@ -28,7 +28,9 @@ oxr_session_populate_vk(struct oxr_logger *log,
struct oxr_session *sess)
{
struct xrt_compositor_fd *xcfd = NULL;
int ret = xrt_instance_create_fd_compositor(sys->inst->xinst, sys->head,
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head);
int ret = xrt_instance_create_fd_compositor(sys->inst->xinst, xdev,
false, &xcfd);
if (ret < 0 || xcfd == NULL) {
return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,

View file

@ -24,12 +24,6 @@
DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 140)
// clang-format on
static inline size_t
min_size_t(size_t a, size_t b)
{
return a < b ? a : b;
}
static bool
oxr_system_matches(struct oxr_logger *log,
struct oxr_system *sys,
@ -109,18 +103,9 @@ oxr_system_fill_in(struct oxr_logger *log,
struct xrt_device **xdevs,
size_t num_xdevs)
{
sys->num_xdevs = min_size_t(ARRAY_SIZE(sys->xdevs), num_xdevs);
for (uint32_t i = 0; i < sys->num_xdevs; i++) {
sys->xdevs[i] = xdevs[i];
}
for (size_t i = sys->num_xdevs; i < num_xdevs; i++) {
oxr_xdev_destroy(&xdevs[i]);
}
struct xrt_device *head = sys->head;
struct xrt_device *left = sys->left;
struct xrt_device *right = sys->right;
struct xrt_device *head = GET_XDEV_BY_ROLE(sys, head);
struct xrt_device *left = GET_XDEV_BY_ROLE(sys, left);
struct xrt_device *right = GET_XDEV_BY_ROLE(sys, right);
if (head == NULL) {
return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,
@ -212,9 +197,11 @@ oxr_system_get_properties(struct oxr_logger *log,
properties->vendorId = 42;
properties->systemId = sys->systemId;
struct xrt_device *xdev = GET_XDEV_BY_ROLE(sys, head);
// The magical 247 number, is to silence warnings.
snprintf(properties->systemName, XR_MAX_SYSTEM_NAME_SIZE,
"Monado: %.*s", 247, sys->head->str);
"Monado: %.*s", 247, xdev->str);
//! Get from compositor.
uint32_t max = XR_MIN_COMPOSITION_LAYERS_SUPPORTED;
@ -223,9 +210,9 @@ oxr_system_get_properties(struct oxr_logger *log,
properties->graphicsProperties.maxSwapchainImageWidth = 1024 * 16;
properties->graphicsProperties.maxSwapchainImageHeight = 1024 * 16;
properties->trackingProperties.orientationTracking =
sys->head->orientation_tracking_supported;
xdev->orientation_tracking_supported;
properties->trackingProperties.positionTracking =
sys->head->position_tracking_supported;
xdev->position_tracking_supported;
return XR_SUCCESS;
}

View file

@ -530,29 +530,32 @@ handle_found_device(struct prober *p,
{
P_DEBUG(p, "Found '%s' %p", xdev->str, (void *)xdev);
// For controllers we put them after the first found HMD.
if (xdev->hmd == NULL) {
for (size_t i = 1; i < num_xdevs; i++) {
if (xdevs[i] == NULL) {
xdevs[i] = xdev;
return;
}
bool have_hmd = false;
size_t i = 0;
for (; i < num_xdevs; i++) {
if (xdevs[i] == NULL) {
break;
}
if (xdevs[i]->device_type == XRT_DEVICE_TYPE_HMD) {
have_hmd = true;
}
}
P_ERROR(p, "Too many controller devices closing '%s'",
xdev->str);
if (i + 1 > num_xdevs) {
P_ERROR(p, "Too many devices, closing '%s'", xdev->str);
xdev->destroy(xdev);
return;
}
// Not found a HMD before, add it first in the list.
if (xdevs[0] == NULL) {
xdevs[0] = xdev;
return;
// we can have only one HMD
if (xdev->device_type == XRT_DEVICE_TYPE_HMD) {
if (have_hmd) {
P_ERROR(p, "Too many HMDs, closing '%s'", xdev->str);
xdev->destroy(xdev);
return;
}
}
P_ERROR(p, "Found more than one, HMD closing '%s'", xdev->str);
xdev->destroy(xdev);
xdevs[i] = xdev;
}
static int