From 4e6a137c624b8cfc0719f1ea07307be0b921b4a6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 18 Aug 2020 17:05:43 +0100 Subject: [PATCH] ipc: Make it possible to toggle inputs on and off --- doc/changes/ipc/mr.511.md | 3 + src/xrt/include/xrt/xrt_results.h | 5 ++ src/xrt/ipc/ipc_client_device.c | 22 +++--- src/xrt/ipc/ipc_client_hmd.c | 20 +++--- src/xrt/ipc/ipc_client_instance.c | 8 +-- src/xrt/ipc/ipc_protocol.h | 11 +-- src/xrt/ipc/ipc_server.h | 43 +++++++++++- src/xrt/ipc/ipc_server_client.c | 110 +++++++++++++++++++++++++++--- src/xrt/ipc/ipc_server_process.c | 83 +++++++++++++++------- src/xrt/ipc/proto.json | 12 ++++ 10 files changed, 252 insertions(+), 65 deletions(-) create mode 100644 doc/changes/ipc/mr.511.md diff --git a/doc/changes/ipc/mr.511.md b/doc/changes/ipc/mr.511.md new file mode 100644 index 000000000..84da6763d --- /dev/null +++ b/doc/changes/ipc/mr.511.md @@ -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. diff --git a/src/xrt/include/xrt/xrt_results.h b/src/xrt/include/xrt/xrt_results.h index 6fc3830f5..0b5dd1051 100644 --- a/src/xrt/include/xrt/xrt_results.h +++ b/src/xrt/include/xrt/xrt_results.h @@ -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; diff --git a/src/xrt/ipc/ipc_client_device.c b/src/xrt/ipc/ipc_client_device.c index b2ba6c6d3..ffbf43084 100644 --- a/src/xrt/ipc/ipc_client_device.c +++ b/src/xrt/ipc/ipc_client_device.c @@ -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; } diff --git a/src/xrt/ipc/ipc_client_hmd.c b/src/xrt/ipc/ipc_client_hmd.c index 1084a4f53..d118d39e3 100644 --- a/src/xrt/ipc/ipc_client_hmd.c +++ b/src/xrt/ipc/ipc_client_hmd.c @@ -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; } diff --git a/src/xrt/ipc/ipc_client_instance.c b/src/xrt/ipc/ipc_client_instance.c index a70f94238..2648983be 100644 --- a/src/xrt/ipc/ipc_client_instance.c +++ b/src/xrt/ipc/ipc_client_instance.c @@ -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 { diff --git a/src/xrt/ipc/ipc_protocol.h b/src/xrt/ipc/ipc_protocol.h index 034387506..528c0d349 100644 --- a/src/xrt/ipc/ipc_protocol.h +++ b/src/xrt/ipc/ipc_protocol.h @@ -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; diff --git a/src/xrt/ipc/ipc_server.h b/src/xrt/ipc/ipc_server.h index 18e4afc17..312cf3cdd 100644 --- a/src/xrt/ipc/ipc_server.h +++ b/src/xrt/ipc/ipc_server.h @@ -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 diff --git a/src/xrt/ipc/ipc_server_client.c b/src/xrt/ipc/ipc_server_client.c index 3301f2b3f..291a8725a 100644 --- a/src/xrt/ipc/ipc_server_client.c +++ b/src/xrt/ipc/ipc_server_client.c @@ -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); diff --git a/src/xrt/ipc/ipc_server_process.c b/src/xrt/ipc/ipc_server_process.c index 3f2b55e4a..9c6d798cb 100644 --- a/src/xrt/ipc/ipc_server_process.c +++ b/src/xrt/ipc/ipc_server_process.c @@ -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) { diff --git a/src/xrt/ipc/proto.json b/src/xrt/ipc/proto.json index 5ae878eaa..e32c96eab 100644 --- a/src/xrt/ipc/proto.json +++ b/src/xrt/ipc/proto.json @@ -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"}