From cec787ba0f70b1f811723a3411903455d1618bed Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 7 Nov 2023 20:05:02 +0000 Subject: [PATCH] ipc: Add variable number of views get function --- src/xrt/ipc/client/ipc_client_hmd.c | 93 ++++++++++++++++++++++++- src/xrt/ipc/server/ipc_server_handler.c | 79 +++++++++++++++++++++ src/xrt/ipc/shared/ipc_protocol.h | 1 + src/xrt/ipc/shared/proto.json | 14 ++++ 4 files changed, 184 insertions(+), 3 deletions(-) diff --git a/src/xrt/ipc/client/ipc_client_hmd.c b/src/xrt/ipc/client/ipc_client_hmd.c index 800cd08c5..dc2ca643a 100644 --- a/src/xrt/ipc/client/ipc_client_hmd.c +++ b/src/xrt/ipc/client/ipc_client_hmd.c @@ -21,6 +21,7 @@ #include "util/u_distortion_mesh.h" #include "client/ipc_client.h" +#include "client/ipc_client_connection.h" #include "ipc_client_generated.h" #include @@ -48,7 +49,7 @@ typedef struct ipc_client_xdev ipc_client_hmd_t; /* * - * Functions + * Helpers. * */ @@ -58,6 +59,78 @@ ipc_client_hmd(struct xrt_device *xdev) return (ipc_client_hmd_t *)xdev; } +static void +call_get_view_poses_raw(ipc_client_hmd_t *ich, + const struct xrt_vec3 *default_eye_relation, + uint64_t at_timestamp_ns, + uint32_t view_count, + struct xrt_space_relation *out_head_relation, + struct xrt_fov *out_fovs, + struct xrt_pose *out_poses) +{ + struct ipc_connection *ipc_c = ich->ipc_c; + xrt_result_t xret = XRT_SUCCESS; + + ipc_client_connection_lock(ipc_c); + + // Using the raw send helper is the only one that is required. + xret = ipc_send_device_get_view_poses_locked( // + ipc_c, // + ich->device_id, // + default_eye_relation, // + at_timestamp_ns, // + view_count); // + if (xret != XRT_SUCCESS) { + goto out; + } + + // This is the data we get back in the provided reply. + uint32_t returned_view_count = 0; + struct xrt_space_relation head_relation = XRT_SPACE_RELATION_ZERO; + + // Get the reply, use the raw function helper. + xret = ipc_receive_device_get_view_poses_locked( // + ipc_c, // + &head_relation, // + &returned_view_count); // + if (xret != XRT_SUCCESS) { + goto out; + } + + if (view_count != returned_view_count) { + IPC_ERROR(ich->ipc_c, "Wrong view counts (sent: %u != got: %u)", view_count, returned_view_count); + assert(false); + } + + // We can read directly to the output variables. + xret = ipc_receive(&ipc_c->imc, out_fovs, sizeof(struct xrt_fov) * view_count); + if (xret != XRT_SUCCESS) { + goto out; + } + + // We can read directly to the output variables. + xret = ipc_receive(&ipc_c->imc, out_poses, sizeof(struct xrt_pose) * view_count); + if (xret != XRT_SUCCESS) { + goto out; + } + + /* + * Finally set the head_relation that we got in the reply, mostly to + * demonstrate that you can use the reply struct in such a way. + */ + *out_head_relation = head_relation; + +out: + ipc_client_connection_unlock(ipc_c); +} + + +/* + * + * Member functions + * + */ + static void ipc_client_hmd_destroy(struct xrt_device *xdev) { @@ -114,6 +187,7 @@ ipc_client_hmd_get_view_poses(struct xrt_device *xdev, struct ipc_info_get_view_poses_2 info = {0}; if (view_count == 2) { + // Fast path. xrt_result_t r = ipc_call_device_get_view_poses_2( // ich->ipc_c, // ich->device_id, // @@ -129,9 +203,22 @@ ipc_client_hmd_get_view_poses(struct xrt_device *xdev, out_fovs[i] = info.fovs[i]; out_poses[i] = info.poses[i]; } + + } else if (view_count <= IPC_MAX_RAW_VIEWS) { + // Artificial limit. + + call_get_view_poses_raw( // + ich, // + default_eye_relation, // + at_timestamp_ns, // + view_count, // + out_head_relation, // + out_fovs, // + out_poses); // } else { - IPC_ERROR(ich->ipc_c, "Cannot handle %u view_count, only 2 supported.", view_count); - assert(false && !"Can only handle view_count of 2."); + IPC_ERROR(ich->ipc_c, "Cannot handle %u view_count, %u or less supported.", view_count, + (uint32_t)IPC_MAX_RAW_VIEWS); + assert(false && !"Too large view_count!"); } } diff --git a/src/xrt/ipc/server/ipc_server_handler.c b/src/xrt/ipc/server/ipc_server_handler.c index c7c316753..e950bdf7c 100644 --- a/src/xrt/ipc/server/ipc_server_handler.c +++ b/src/xrt/ipc/server/ipc_server_handler.c @@ -1419,6 +1419,85 @@ ipc_handle_device_get_hand_tracking(volatile struct ipc_client_state *ics, return XRT_SUCCESS; } +xrt_result_t +ipc_handle_device_get_view_poses(volatile struct ipc_client_state *ics, + uint32_t id, + const struct xrt_vec3 *fallback_eye_relation, + uint64_t at_timestamp_ns, + uint32_t view_count) +{ + struct ipc_message_channel *imc = (struct ipc_message_channel *)&ics->imc; + struct ipc_device_get_view_poses_reply reply = XRT_STRUCT_INIT; + struct ipc_server *s = ics->server; + xrt_result_t xret; + + // To make the code a bit more readable. + uint32_t device_id = id; + struct xrt_device *xdev = get_xdev(ics, device_id); + + + if (view_count == 0 || view_count > IPC_MAX_RAW_VIEWS) { + IPC_ERROR(s, "Client asked for zero or too many views! (%u)", view_count); + + reply.result = XRT_ERROR_IPC_FAILURE; + // Send the full reply, the client expects it. + return ipc_send(imc, &reply, sizeof(reply)); + } + + // Data to get. + struct xrt_fov fovs[IPC_MAX_RAW_VIEWS]; + struct xrt_pose poses[IPC_MAX_RAW_VIEWS]; + + xrt_device_get_view_poses( // + xdev, // + fallback_eye_relation, // + at_timestamp_ns, // + view_count, // + &reply.head_relation, // + fovs, // + poses); // + + /* + * Operation ok, head_relation has already been put in the reply + * struct, so we don't need to send that manually. + */ + reply.result = XRT_SUCCESS; + + /* + * This isn't really needed, but demonstrates the server sending the + * length back in the reply, a common pattern for other functions. + */ + reply.view_count = view_count; + + /* + * Send the reply first isn't required for functions in general, but it + * will need to match what the client expects. This demonstrates the + * server sending the length back in the reply, a common pattern for + * other functions. + */ + xret = ipc_send(imc, &reply, sizeof(reply)); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to send reply!"); + return xret; + } + + // Send the fovs that we got. + xret = ipc_send(imc, fovs, sizeof(struct xrt_fov) * view_count); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to send fovs!"); + return xret; + } + + // And finally the poses. + xret = ipc_send(imc, poses, sizeof(struct xrt_pose) * view_count); + if (xret != XRT_SUCCESS) { + IPC_ERROR(s, "Failed to send poses!"); + return xret; + } + + return XRT_SUCCESS; +} + xrt_result_t ipc_handle_device_get_view_poses_2(volatile struct ipc_client_state *ics, uint32_t id, diff --git a/src/xrt/ipc/shared/ipc_protocol.h b/src/xrt/ipc/shared/ipc_protocol.h index debb6d103..c5a7477f0 100644 --- a/src/xrt/ipc/shared/ipc_protocol.h +++ b/src/xrt/ipc/shared/ipc_protocol.h @@ -33,6 +33,7 @@ #define IPC_MAX_LAYERS 16 #define IPC_MAX_SLOTS 128 #define IPC_MAX_CLIENTS 8 +#define IPC_MAX_RAW_VIEWS 32 // Max views that we can get, artificial limit. #define IPC_EVENT_QUEUE_SIZE 32 #define IPC_SHARED_MAX_INPUTS 1024 diff --git a/src/xrt/ipc/shared/proto.json b/src/xrt/ipc/shared/proto.json index da8179f9e..39e846f61 100644 --- a/src/xrt/ipc/shared/proto.json +++ b/src/xrt/ipc/shared/proto.json @@ -307,6 +307,20 @@ ] }, + "device_get_view_poses": { + "varlen": true, + "in": [ + {"name": "id", "type": "uint32_t"}, + {"name": "fallback_eye_relation", "type": "struct xrt_vec3"}, + {"name": "at_timestamp_ns", "type": "uint64_t"}, + {"name": "view_count", "type": "uint32_t"} + ], + "out": [ + {"name": "head_relation", "type": "struct xrt_space_relation"}, + {"name": "view_count", "type": "uint32_t"} + ] + }, + "device_get_view_poses_2": { "in": [ {"name": "id", "type": "uint32_t"},