ipc: Make it possible to toggle inputs on and off

This commit is contained in:
Jakob Bornecrantz 2020-08-18 17:05:43 +01:00 committed by Jakob Bornecrantz
parent 557dacbb02
commit 4e6a137c62
10 changed files with 252 additions and 65 deletions

View file

@ -0,0 +1,3 @@
ipc: Add functionality to disable a device input via the `monado-ctl` utility,
this allows us to pass the conformance tests that requires the runtime to turn
off a device.

View file

@ -31,4 +31,9 @@ typedef enum xrt_result
* Could not allocate native image buffer(s).
*/
XRT_ERROR_ALLOCATION = -7,
/*
* The pose is no longer active, this happens when the application
* tries to access a pose that is no longer active.
*/
XRT_ERROR_POSE_NOT_ACTIVE = -8,
} xrt_result_t;

View file

@ -139,7 +139,7 @@ ipc_client_device_create(struct ipc_connection *ipc_c,
{
// Helpers.
struct ipc_shared_memory *ism = ipc_c->ism;
struct ipc_shared_device *idev = &ism->idevs[device_id];
struct ipc_shared_device *isdev = &ism->isdevs[device_id];
// Allocate and setup the basics.
enum u_device_alloc_flags flags =
@ -153,23 +153,23 @@ ipc_client_device_create(struct ipc_connection *ipc_c,
icd->base.set_output = ipc_client_device_set_output;
icd->base.destroy = ipc_client_device_destroy;
// Start copying the information from the idev.
// Start copying the information from the isdev.
icd->base.tracking_origin = xtrack;
icd->base.name = idev->name;
icd->base.name = isdev->name;
icd->device_id = device_id;
// Print name.
snprintf(icd->base.str, XRT_DEVICE_NAME_LEN, "%s", idev->str);
snprintf(icd->base.str, XRT_DEVICE_NAME_LEN, "%s", isdev->str);
// Setup inputs, by pointing directly to the shared memory.
assert(idev->num_inputs > 0);
icd->base.inputs = &ism->inputs[idev->first_input_index];
icd->base.num_inputs = idev->num_inputs;
assert(isdev->num_inputs > 0);
icd->base.inputs = &ism->inputs[isdev->first_input_index];
icd->base.num_inputs = isdev->num_inputs;
// Setup outputs, if any point directly into the shared memory.
icd->base.num_outputs = idev->num_outputs;
if (idev->num_outputs > 0) {
icd->base.outputs = &ism->outputs[idev->first_output_index];
icd->base.num_outputs = isdev->num_outputs;
if (isdev->num_outputs > 0) {
icd->base.outputs = &ism->outputs[isdev->first_output_index];
} else {
icd->base.outputs = NULL;
}
@ -178,6 +178,6 @@ ipc_client_device_create(struct ipc_connection *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;
icd->base.device_type = isdev->device_type;
return &icd->base;
}

View file

@ -130,7 +130,7 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c,
uint32_t device_id)
{
struct ipc_shared_memory *ism = ipc_c->ism;
struct ipc_shared_device *idev = &ism->idevs[device_id];
struct ipc_shared_device *isdev = &ism->isdevs[device_id];
@ -145,18 +145,18 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c,
ich->base.get_view_pose = ipc_client_hmd_get_view_pose;
ich->base.destroy = ipc_client_hmd_destroy;
// Start copying the information from the idev.
// Start copying the information from the isdev.
ich->base.tracking_origin = xtrack;
ich->base.name = idev->name;
ich->base.name = isdev->name;
ich->device_id = device_id;
// Print name.
snprintf(ich->base.str, XRT_DEVICE_NAME_LEN, "%s", idev->str);
snprintf(ich->base.str, XRT_DEVICE_NAME_LEN, "%s", isdev->str);
// Setup inputs, by pointing directly to the shared memory.
assert(idev->num_inputs > 0);
ich->base.inputs = &ism->inputs[idev->first_input_index];
ich->base.num_inputs = idev->num_inputs;
assert(isdev->num_inputs > 0);
ich->base.inputs = &ism->inputs[isdev->first_input_index];
ich->base.num_inputs = isdev->num_inputs;
#if 0
// Setup info.
@ -198,10 +198,10 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c,
u_var_add_ro_u32(ich, &ich->device_id, "device_id");
ich->base.orientation_tracking_supported =
idev->orientation_tracking_supported;
isdev->orientation_tracking_supported;
ich->base.position_tracking_supported =
idev->position_tracking_supported;
ich->base.device_type = idev->device_type;
isdev->position_tracking_supported;
ich->base.device_type = isdev->device_type;
return &ich->base;
}

View file

@ -283,11 +283,11 @@ ipc_instance_create(struct xrt_instance_info *i_info,
// Query the server for how many devices it has.
count = 0;
for (uint32_t i = 0; i < ism->num_idevs; i++) {
struct ipc_shared_device *idev = &ism->idevs[i];
xtrack = ii->xtracks[idev->tracking_origin_index];
for (uint32_t i = 0; i < ism->num_isdevs; i++) {
struct ipc_shared_device *isdev = &ism->isdevs[i];
xtrack = ii->xtracks[isdev->tracking_origin_index];
if (idev->name == XRT_DEVICE_GENERIC_HMD) {
if (isdev->name == XRT_DEVICE_GENERIC_HMD) {
ii->xdevs[count++] =
ipc_client_hmd_create(&ii->ipc_c, xtrack, i);
} else {

View file

@ -127,7 +127,7 @@ struct ipc_layer_slot
* struct xrt_input *
* helper(struct ipc_shared_memory *ism, uin32_t device_id, size_t input)
* {
* size_t index = ism->idevs[device_id]->first_input_index + input;
* size_t index = ism->isdevs[device_id]->first_input_index + input;
* return &ism->inputs[index];
* }
* ```
@ -149,16 +149,16 @@ struct ipc_shared_memory
struct ipc_shared_tracking_origin itracks[IPC_SHARED_MAX_DEVICES];
/*!
* Number of elements in @ref idevs that are populated/valid.
* Number of elements in @ref isdevs that are populated/valid.
*/
size_t num_idevs;
size_t num_isdevs;
/*!
* @brief Array of shared data per device.
*
* Only @ref num_idevs elements are populated/valid.
* Only @ref num_isdevs elements are populated/valid.
*/
struct ipc_shared_device idevs[IPC_SHARED_MAX_DEVICES];
struct ipc_shared_device isdevs[IPC_SHARED_MAX_DEVICES];
struct
{
@ -213,6 +213,7 @@ struct ipc_app_state
bool session_visible;
bool session_focused;
bool session_overlay;
bool io_active;
uint32_t z_order;
pid_t pid;
struct xrt_instance_info info;

View file

@ -108,6 +108,9 @@ struct ipc_client_state
//! Compositor for this client.
struct xrt_compositor *xc;
//! Is the inputs and outputs active.
bool io_active;
//! Number of swapchains in use by client
uint32_t num_swapchains;
@ -150,6 +153,19 @@ struct ipc_thread
volatile struct ipc_client_state ics;
};
/*!
*
*/
struct ipc_device
{
//! The actual device.
struct xrt_device *xdev;
//! Is the IO suppressed for this device.
bool io_active;
};
/*!
* Main IPC object for the server.
*
@ -162,7 +178,7 @@ struct ipc_server
struct xrt_compositor *xc;
struct xrt_compositor_native *xcn;
struct xrt_device *xdevs[IPC_SERVER_NUM_XDEVS];
struct ipc_device idevs[IPC_SERVER_NUM_XDEVS];
struct xrt_tracking_origin *xtracks[IPC_SERVER_NUM_XDEVS];
struct ipc_shared_memory *ism;
@ -223,6 +239,31 @@ void *
ipc_server_client_thread(void *_cs);
/*
*
* Helpers
*
*/
/*!
* Get a xdev with the given device_id.
*/
static inline struct xrt_device *
get_xdev(volatile struct ipc_client_state *ics, uint32_t device_id)
{
return ics->server->idevs[device_id].xdev;
}
/*!
* Get a idev with the given device_id.
*/
static inline struct ipc_device *
get_idev(volatile struct ipc_client_state *ics, uint32_t device_id)
{
return &ics->server->idevs[device_id];
}
#ifdef __cplusplus
}
#endif

View file

@ -260,6 +260,7 @@ ipc_handle_system_get_client_info(volatile struct ipc_client_state *_ics,
}
*out_client_desc = ics->client_state;
out_client_desc->io_active = ics->io_active;
//@todo: track this data in the ipc_client_state struct
out_client_desc->primary_application = false;
@ -310,6 +311,42 @@ ipc_handle_system_set_focused_client(volatile struct ipc_client_state *ics,
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_system_toggle_io_client(volatile struct ipc_client_state *_ics,
uint32_t client_id)
{
volatile struct ipc_client_state *ics = NULL;
if (client_id >= IPC_MAX_CLIENTS) {
return XRT_ERROR_IPC_FAILURE;
}
ics = &_ics->server->threads[client_id].ics;
if (ics->imc.socket_fd <= 0) {
return XRT_ERROR_IPC_FAILURE;
}
ics->io_active = !ics->io_active;
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_system_toggle_io_device(volatile struct ipc_client_state *ics,
uint32_t device_id)
{
if (device_id >= IPC_MAX_DEVICES) {
return XRT_ERROR_IPC_FAILURE;
}
struct ipc_device *idev = &ics->server->idevs[device_id];
idev->io_active = !idev->io_active;
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_swapchain_create(volatile struct ipc_client_state *ics,
const struct xrt_swapchain_create_info *info,
@ -466,21 +503,56 @@ ipc_handle_device_update_input(volatile struct ipc_client_state *ics,
// To make the code a bit more readable.
uint32_t device_id = id;
struct ipc_shared_memory *ism = ics->server->ism;
struct xrt_device *xdev = ics->server->xdevs[device_id];
struct ipc_shared_device *idev = &ism->idevs[device_id];
struct ipc_device *idev = get_idev(ics, device_id);
struct xrt_device *xdev = idev->xdev;
struct ipc_shared_device *isdev = &ism->isdevs[device_id];
// Update inputs.
xrt_device_update_inputs(xdev);
// Copy data into the shared memory.
struct xrt_input *src = xdev->inputs;
struct xrt_input *dst = &ism->inputs[idev->first_input_index];
memcpy(dst, src, sizeof(struct xrt_input) * idev->num_inputs);
struct xrt_input *dst = &ism->inputs[isdev->first_input_index];
size_t size = sizeof(struct xrt_input) * isdev->num_inputs;
bool io_active = ics->io_active && idev->io_active;
if (io_active) {
memcpy(dst, src, size);
} else {
memset(dst, 0, size);
for (uint32_t i = 0; i < isdev->num_inputs; i++) {
dst[i].name = src[i].name;
// Special case the rotation of the head.
if (dst[i].name == XRT_INPUT_GENERIC_HEAD_POSE) {
dst[i].active = src[i].active;
}
}
}
// Reply.
return XRT_SUCCESS;
}
static struct xrt_input *
find_input(volatile struct ipc_client_state *ics,
uint32_t device_id,
enum xrt_input_name name)
{
struct ipc_shared_memory *ism = ics->server->ism;
struct ipc_shared_device *isdev = &ism->isdevs[device_id];
struct xrt_input *io = &ism->inputs[isdev->first_input_index];
for (uint32_t i = 0; i < isdev->num_inputs; i++) {
if (io[i].name == name) {
return &io[i];
}
}
return NULL;
}
xrt_result_t
ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *ics,
uint32_t id,
@ -492,7 +564,30 @@ ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *ics,
// To make the code a bit more readable.
uint32_t device_id = id;
struct xrt_device *xdev = ics->server->xdevs[device_id];
struct ipc_device *isdev = &ics->server->idevs[device_id];
struct xrt_device *xdev = isdev->xdev;
// Find the input
struct xrt_input *input = find_input(ics, device_id, name);
if (input == NULL) {
return XRT_ERROR_IPC_FAILURE;
}
// Special case the headpose.
bool disabled = (!isdev->io_active || !ics->io_active) &&
name != XRT_INPUT_GENERIC_HEAD_POSE;
bool active_on_client = input->active;
// We have been disabled but the client hasn't called update.
if (disabled && active_on_client) {
U_ZERO(out_relation);
*out_timestamp = at_timestamp;
return XRT_SUCCESS;
}
if (disabled || !active_on_client) {
return XRT_ERROR_POSE_NOT_ACTIVE;
}
// Get the pose.
xrt_device_get_tracked_pose(xdev, name, at_timestamp, out_timestamp,
@ -508,10 +603,9 @@ ipc_handle_device_get_view_pose(volatile struct ipc_client_state *ics,
uint32_t view_index,
struct xrt_pose *out_pose)
{
// To make the code a bit more readable.
uint32_t device_id = id;
struct xrt_device *xdev = ics->server->xdevs[device_id];
struct xrt_device *xdev = get_xdev(ics, device_id);
// Get the pose.
xrt_device_get_view_pose(xdev, eye_relation, view_index, out_pose);
@ -527,7 +621,7 @@ ipc_handle_device_set_output(volatile struct ipc_client_state *ics,
{
// To make the code a bit more readable.
uint32_t device_id = id;
struct xrt_device *xdev = ics->server->xdevs[device_id];
struct xrt_device *xdev = get_xdev(ics, device_id);
// Set the output.
xrt_device_set_output(xdev, name, value);

View file

@ -56,6 +56,24 @@ struct _z_sort_data
int32_t z_order;
};
static void
init_idev(struct ipc_device *idev, struct xrt_device *xdev)
{
if (xdev != NULL) {
idev->io_active = true;
idev->xdev = xdev;
} else {
idev->io_active = false;
}
}
static void
teardown_idev(struct ipc_device *idev)
{
xrt_device_destroy(&idev->xdev);
idev->io_active = false;
}
/*
*
@ -71,7 +89,7 @@ teardown_all(struct ipc_server *s)
xrt_comp_destroy(&s->xc);
for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) {
xrt_device_destroy(&s->xdevs[i]);
teardown_idev(&s->idevs[i]);
}
xrt_instance_destroy(&s->xinst);
@ -95,11 +113,11 @@ static int
init_tracking_origins(struct ipc_server *s)
{
for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) {
if (s->xdevs[i] == NULL) {
struct xrt_device *xdev = s->idevs[i].xdev;
if (xdev == NULL) {
continue;
}
struct xrt_device *xdev = s->xdevs[i];
struct xrt_tracking_origin *xtrack = xdev->tracking_origin;
assert(xtrack != NULL);
size_t index = 0;
@ -166,21 +184,21 @@ init_shm(struct ipc_server *s)
uint32_t input_index = 0;
uint32_t output_index = 0;
for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) {
struct xrt_device *xdev = s->xdevs[i];
struct xrt_device *xdev = s->idevs[i].xdev;
if (xdev == NULL) {
continue;
}
struct ipc_shared_device *idev = &ism->idevs[count++];
struct ipc_shared_device *isdev = &ism->isdevs[count++];
idev->name = xdev->name;
memcpy(idev->str, xdev->str, sizeof(idev->str));
isdev->name = xdev->name;
memcpy(isdev->str, xdev->str, sizeof(isdev->str));
idev->orientation_tracking_supported =
isdev->orientation_tracking_supported =
xdev->orientation_tracking_supported;
idev->position_tracking_supported =
isdev->position_tracking_supported =
xdev->position_tracking_supported;
idev->device_type = xdev->device_type;
isdev->device_type = xdev->device_type;
// Is this a HMD?
if (xdev->hmd != NULL) {
@ -197,17 +215,17 @@ init_shm(struct ipc_server *s)
}
// Setup the tracking origin.
idev->tracking_origin_index = (uint32_t)-1;
isdev->tracking_origin_index = (uint32_t)-1;
for (size_t k = 0; k < IPC_SERVER_NUM_XDEVS; k++) {
if (xdev->tracking_origin != s->xtracks[k]) {
continue;
}
idev->tracking_origin_index = k;
isdev->tracking_origin_index = k;
break;
}
assert(idev->tracking_origin_index != (uint32_t)-1);
assert(isdev->tracking_origin_index != (uint32_t)-1);
// Initial update.
xrt_device_update_inputs(xdev);
@ -220,8 +238,8 @@ init_shm(struct ipc_server *s)
// Setup the 'offsets' and number of inputs.
if (input_start != input_index) {
idev->num_inputs = input_index - input_start;
idev->first_input_index = input_start;
isdev->num_inputs = input_index - input_start;
isdev->first_input_index = input_start;
}
// Copy the initial state and also count the number in outputs.
@ -232,13 +250,13 @@ init_shm(struct ipc_server *s)
// Setup the 'offsets' and number of outputs.
if (output_start != output_index) {
idev->num_outputs = output_index - output_start;
idev->first_output_index = output_start;
isdev->num_outputs = output_index - output_start;
isdev->first_output_index = output_start;
}
}
// Finally tell the client how many devices we have.
s->ism->num_idevs = count;
s->ism->num_isdevs = count;
return 0;
}
@ -382,13 +400,25 @@ init_all(struct ipc_server *s)
return ret;
}
ret = xrt_instance_select(s->xinst, s->xdevs, IPC_SERVER_NUM_XDEVS);
struct xrt_device *xdevs[IPC_SERVER_NUM_XDEVS] = {0};
ret = xrt_instance_select(s->xinst, xdevs, IPC_SERVER_NUM_XDEVS);
if (ret < 0) {
teardown_all(s);
return ret;
}
if (s->xdevs[0] == NULL) {
// Copy the devices over into the idevs array.
for (size_t i = 0; i < IPC_SERVER_NUM_XDEVS; i++) {
if (xdevs[i] == NULL) {
continue;
}
init_idev(&s->idevs[i], xdevs[i]);
xdevs[i] = NULL;
}
// If we don't have a HMD shutdown.
if (s->idevs[0].xdev == NULL) {
teardown_all(s);
return -1;
}
@ -399,7 +429,7 @@ init_all(struct ipc_server *s)
return -1;
}
ret = xrt_instance_create_native_compositor(s->xinst, s->xdevs[0],
ret = xrt_instance_create_native_compositor(s->xinst, s->idevs[0].xdev,
&s->xcn);
if (ret < 0) {
teardown_all(s);
@ -506,6 +536,7 @@ handle_listen(struct ipc_server *vs)
ics->imc.socket_fd = fd;
ics->server = vs;
ics->server_thread_index = cs_index;
ics->io_active = true;
os_thread_start(&it->thread, ipc_server_client_thread, (void *)ics);
// Unlock when we are done.
@ -599,13 +630,13 @@ _update_projection_layer(struct xrt_compositor *xc,
uint32_t i)
{
// xdev
uint32_t xdevi = layer->xdev_id;
uint32_t device_id = layer->xdev_id;
// left
uint32_t lxsci = layer->swapchain_ids[0];
// right
uint32_t rxsci = layer->swapchain_ids[1];
struct xrt_device *xdev = ics->server->xdevs[xdevi];
struct xrt_device *xdev = get_xdev(ics, device_id);
struct xrt_swapchain *lxcs = ics->xscs[lxsci];
struct xrt_swapchain *rxcs = ics->xscs[rxsci];
@ -645,7 +676,7 @@ _update_projection_layer_depth(struct xrt_compositor *xc,
// right
uint32_t r_d_xsci = layer->swapchain_ids[3];
struct xrt_device *xdev = ics->server->xdevs[xdevi];
struct xrt_device *xdev = get_xdev(ics, xdevi);
struct xrt_swapchain *l_xcs = ics->xscs[l_xsci];
struct xrt_swapchain *r_xcs = ics->xscs[r_xsci];
struct xrt_swapchain *l_d_xcs = ics->xscs[l_d_xsci];
@ -682,10 +713,10 @@ do_single(struct xrt_compositor *xc,
struct xrt_swapchain **out_xcs,
struct xrt_layer_data **out_data)
{
uint32_t xdevi = layer->xdev_id;
uint32_t device_id = layer->xdev_id;
uint32_t sci = layer->swapchain_ids[0];
struct xrt_device *xdev = ics->server->xdevs[xdevi];
struct xrt_device *xdev = get_xdev(ics, device_id);
struct xrt_swapchain *xcs = ics->xscs[sci];
if (xcs == NULL) {

View file

@ -38,6 +38,18 @@
]
},
"system_toggle_io_client": {
"in": [
{"name": "id", "type": "uint32_t"}
]
},
"system_toggle_io_device": {
"in": [
{"name": "id", "type": "uint32_t"}
]
},
"session_create": {
"in": [
{"name": "overlay_info", "type": "const struct xrt_session_prepare_info"}