diff --git a/src/xrt/ipc/CMakeLists.txt b/src/xrt/ipc/CMakeLists.txt index a2d50fbd2..dc1f90be8 100644 --- a/src/xrt/ipc/CMakeLists.txt +++ b/src/xrt/ipc/CMakeLists.txt @@ -70,6 +70,8 @@ add_library( client/ipc_client_space_overseer.c client/ipc_client_system.c client/ipc_client_system_devices.c + client/ipc_client_xdev.c + client/ipc_client_xdev.h ) target_include_directories( ipc_client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/xrt/ipc/client/ipc_client.h b/src/xrt/ipc/client/ipc_client.h index 0ba9ea70d..7758fac94 100644 --- a/src/xrt/ipc/client/ipc_client.h +++ b/src/xrt/ipc/client/ipc_client.h @@ -166,21 +166,6 @@ struct ipc_connection #endif // XRT_OS_ANDROID }; -/*! - * An IPC client proxy for an @ref xrt_device. - * - * @implements xrt_device - * @ingroup ipc_client - */ -struct ipc_client_xdev -{ - struct xrt_device base; - - struct ipc_connection *ipc_c; - - uint32_t device_id; -}; - /* * @@ -188,17 +173,6 @@ struct ipc_client_xdev * */ -/*! - * Convenience helper to go from a xdev to @ref ipc_client_xdev. - * - * @ingroup ipc_client - */ -static inline struct ipc_client_xdev * -ipc_client_xdev(struct xrt_device *xdev) -{ - return (struct ipc_client_xdev *)xdev; -} - /*! * Create an IPC client system compositor. * diff --git a/src/xrt/ipc/client/ipc_client_device.c b/src/xrt/ipc/client/ipc_client_device.c index e4b2c142c..2cfb7e76d 100644 --- a/src/xrt/ipc/client/ipc_client_device.c +++ b/src/xrt/ipc/client/ipc_client_device.c @@ -1,4 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -21,6 +22,7 @@ #include "client/ipc_client.h" #include "client/ipc_client_connection.h" +#include "client/ipc_client_xdev.h" #include "ipc_client_generated.h" #include @@ -66,265 +68,32 @@ ipc_client_device_destroy(struct xrt_device *xdev) // Remove the variable tracking. u_var_remove_root(icd); - // We do not own these, so don't free them. - icd->base.inputs = NULL; - icd->base.outputs = NULL; + // Free and de-init the shared things. + ipc_client_xdev_fini(icd); // Free this device with the helper. u_device_free(&icd->base); } -static xrt_result_t -ipc_client_device_update_inputs(struct xrt_device *xdev) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_update_input(icd->ipc_c, icd->device_id); - IPC_CHK_ALWAYS_RET(icd->ipc_c, xret, "ipc_call_device_update_input"); -} - -static xrt_result_t -ipc_client_device_get_tracked_pose(struct xrt_device *xdev, - enum xrt_input_name name, - int64_t at_timestamp_ns, - struct xrt_space_relation *out_relation) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_get_tracked_pose( // - icd->ipc_c, // - icd->device_id, // - name, // - at_timestamp_ns, // - out_relation); // - IPC_CHK_ALWAYS_RET(icd->ipc_c, xret, "ipc_call_device_get_tracked_pose"); -} - -static void -ipc_client_device_get_hand_tracking(struct xrt_device *xdev, - enum xrt_input_name name, - int64_t at_timestamp_ns, - struct xrt_hand_joint_set *out_value, - int64_t *out_timestamp_ns) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_get_hand_tracking( // - icd->ipc_c, // - icd->device_id, // - name, // - at_timestamp_ns, // - out_value, // - out_timestamp_ns); // - IPC_CHK_ONLY_PRINT(icd->ipc_c, xret, "ipc_call_device_get_hand_tracking"); -} - -static xrt_result_t -ipc_client_device_get_face_tracking(struct xrt_device *xdev, - enum xrt_input_name facial_expression_type, - int64_t at_timestamp_ns, - struct xrt_facial_expression_set *out_value) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_get_face_tracking( // - icd->ipc_c, // - icd->device_id, // - facial_expression_type, // - at_timestamp_ns, // - out_value); // - IPC_CHK_ALWAYS_RET(icd->ipc_c, xret, "ipc_call_device_get_face_tracking"); -} - -static xrt_result_t -ipc_client_device_get_body_skeleton(struct xrt_device *xdev, - enum xrt_input_name body_tracking_type, - struct xrt_body_skeleton *out_value) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_get_body_skeleton( // - icd->ipc_c, // - icd->device_id, // - body_tracking_type, // - out_value); // - IPC_CHK_ALWAYS_RET(icd->ipc_c, xret, "ipc_call_device_get_body_skeleton"); -} - -static xrt_result_t -ipc_client_device_get_body_joints(struct xrt_device *xdev, - enum xrt_input_name body_tracking_type, - int64_t desired_timestamp_ns, - struct xrt_body_joint_set *out_value) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_get_body_joints( // - icd->ipc_c, // - icd->device_id, // - body_tracking_type, // - desired_timestamp_ns, // - out_value); // - IPC_CHK_ALWAYS_RET(icd->ipc_c, xret, "ipc_call_device_get_body_joints"); -} - -static void -ipc_client_device_get_view_poses(struct xrt_device *xdev, - const struct xrt_vec3 *default_eye_relation, - int64_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) -{ - // Empty - assert(false); -} - -static void -ipc_client_device_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - struct ipc_connection *ipc_c = icd->ipc_c; - - xrt_result_t xret; - if (value->type == XRT_OUTPUT_VALUE_TYPE_PCM_VIBRATION) { - uint32_t samples_sent = MIN(value->pcm_vibration.sample_rate, 4000); - - struct ipc_pcm_haptic_buffer samples = { - .append = value->pcm_vibration.append, - .num_samples = samples_sent, - .sample_rate = value->pcm_vibration.sample_rate, - }; - - ipc_client_connection_lock(ipc_c); - - xret = ipc_send_device_set_haptic_output_locked(ipc_c, icd->device_id, name, &samples); - IPC_CHK_WITH_RET(ipc_c, xret, "ipc_send_device_set_haptic_output_locked", ); - - xrt_result_t alloc_xret; - xret = ipc_receive(&ipc_c->imc, &alloc_xret, sizeof alloc_xret); - if (xret != XRT_SUCCESS || alloc_xret != XRT_SUCCESS) { - goto send_haptic_output_end; - } - - xret = ipc_send(&ipc_c->imc, value->pcm_vibration.buffer, sizeof(float) * samples_sent); - if (xret != XRT_SUCCESS) { - goto send_haptic_output_end; - } - - xret = ipc_receive(&ipc_c->imc, value->pcm_vibration.samples_consumed, - sizeof(*value->pcm_vibration.samples_consumed)); - if (xret != XRT_SUCCESS) { - goto send_haptic_output_end; - } - - send_haptic_output_end: - ipc_client_connection_unlock(ipc_c); - } else { - xret = ipc_call_device_set_output(ipc_c, icd->device_id, name, value); - IPC_CHK_ONLY_PRINT(ipc_c, xret, "ipc_call_device_set_output"); - } -} - -xrt_result_t -ipc_client_device_get_output_limits(struct xrt_device *xdev, struct xrt_output_limits *limits) -{ - ipc_client_device_t *icd = ipc_client_device(xdev); - - xrt_result_t xret = ipc_call_device_get_output_limits(icd->ipc_c, icd->device_id, limits); - IPC_CHK_ONLY_PRINT(icd->ipc_c, xret, "ipc_call_device_get_output_limits"); - - return xret; -} - -static xrt_result_t -ipc_client_device_get_visibility_mask(struct xrt_device *xdev, - enum xrt_visibility_mask_type type, - uint32_t view_index, - struct xrt_visibility_mask **out_mask) -{ - assert(false); - return XRT_ERROR_IPC_FAILURE; -} - /*! * @public @memberof ipc_client_device */ struct xrt_device * ipc_client_device_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin *xtrack, uint32_t device_id) { - // Helpers. - struct ipc_shared_memory *ism = ipc_c->ism; - struct ipc_shared_device *isdev = &ism->isdevs[device_id]; - // Allocate and setup the basics. enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD); ipc_client_device_t *icd = U_DEVICE_ALLOCATE(ipc_client_device_t, flags, 0, 0); - icd->ipc_c = ipc_c; - icd->base.update_inputs = ipc_client_device_update_inputs; - icd->base.get_tracked_pose = ipc_client_device_get_tracked_pose; - icd->base.get_hand_tracking = ipc_client_device_get_hand_tracking; - icd->base.get_face_tracking = ipc_client_device_get_face_tracking; - icd->base.get_body_skeleton = ipc_client_device_get_body_skeleton; - icd->base.get_body_joints = ipc_client_device_get_body_joints; - icd->base.get_view_poses = ipc_client_device_get_view_poses; - icd->base.set_output = ipc_client_device_set_output; - icd->base.get_output_limits = ipc_client_device_get_output_limits; - icd->base.get_visibility_mask = ipc_client_device_get_visibility_mask; - icd->base.destroy = ipc_client_device_destroy; - - // Start copying the information from the isdev. - icd->base.tracking_origin = xtrack; - icd->base.name = isdev->name; - icd->device_id = device_id; - - // Print name. - snprintf(icd->base.str, XRT_DEVICE_NAME_LEN, "%s", isdev->str); - snprintf(icd->base.serial, XRT_DEVICE_NAME_LEN, "%s", isdev->serial); - - // Setup inputs, by pointing directly to the shared memory. - assert(isdev->input_count > 0); - icd->base.inputs = &ism->inputs[isdev->first_input_index]; - icd->base.input_count = isdev->input_count; - // Setup outputs, if any point directly into the shared memory. - icd->base.output_count = isdev->output_count; - if (isdev->output_count > 0) { - icd->base.outputs = &ism->outputs[isdev->first_output_index]; - } else { - icd->base.outputs = NULL; - } + // Fills in almost everything a regular device needs. + ipc_client_xdev_init(icd, ipc_c, xtrack, device_id); - if (isdev->binding_profile_count > 0) { - icd->base.binding_profiles = - U_TYPED_ARRAY_CALLOC(struct xrt_binding_profile, isdev->binding_profile_count); - icd->base.binding_profile_count = isdev->binding_profile_count; - } - - for (size_t i = 0; i < isdev->binding_profile_count; i++) { - struct xrt_binding_profile *xbp = &icd->base.binding_profiles[i]; - struct ipc_shared_binding_profile *isbp = - &ism->binding_profiles[isdev->first_binding_profile_index + i]; - - xbp->name = isbp->name; - if (isbp->input_count > 0) { - xbp->inputs = &ism->input_pairs[isbp->first_input_index]; - xbp->input_count = isbp->input_count; - } - if (isbp->output_count > 0) { - xbp->outputs = &ism->output_pairs[isbp->first_output_index]; - xbp->output_count = isbp->output_count; - } - } + // Need to set the destroy function. + icd->base.destroy = ipc_client_device_destroy; // Setup variable tracker. u_var_add_root(icd, icd->base.str, true); u_var_add_ro_u32(icd, &icd->device_id, "device_id"); - // Copy information. - icd->base.device_type = isdev->device_type; - icd->base.supported = isdev->supported; - return &icd->base; } diff --git a/src/xrt/ipc/client/ipc_client_hmd.c b/src/xrt/ipc/client/ipc_client_hmd.c index ab0844f9e..cf90b420b 100644 --- a/src/xrt/ipc/client/ipc_client_hmd.c +++ b/src/xrt/ipc/client/ipc_client_hmd.c @@ -1,4 +1,5 @@ // Copyright 2020-2024, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -22,6 +23,7 @@ #include "util/u_distortion_mesh.h" #include "client/ipc_client.h" +#include "client/ipc_client_xdev.h" #include "client/ipc_client_connection.h" #include "ipc_client_generated.h" @@ -124,49 +126,6 @@ out: * */ -static void -ipc_client_hmd_destroy(struct xrt_device *xdev) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - - // Remove the variable tracking. - u_var_remove_root(ich); - - // We do not own these, so don't free them. - ich->base.inputs = NULL; - ich->base.outputs = NULL; - - // Free this device with the helper. - u_device_free(&ich->base); -} - -static xrt_result_t -ipc_client_hmd_update_inputs(struct xrt_device *xdev) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - - xrt_result_t xret = ipc_call_device_update_input(ich->ipc_c, ich->device_id); - IPC_CHK_ALWAYS_RET(ich->ipc_c, xret, "ipc_call_device_update_input"); -} - -static xrt_result_t -ipc_client_hmd_get_tracked_pose(struct xrt_device *xdev, - enum xrt_input_name name, - int64_t at_timestamp_ns, - struct xrt_space_relation *out_relation) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - xrt_result_t xret; - - xret = ipc_call_device_get_tracked_pose( // - ich->ipc_c, // - ich->device_id, // - name, // - at_timestamp_ns, // - out_relation); // - IPC_CHK_ALWAYS_RET(ich->ipc_c, xret, "ipc_call_device_get_tracked_pose"); -} - static void ipc_client_hmd_get_view_poses(struct xrt_device *xdev, const struct xrt_vec3 *default_eye_relation, @@ -216,23 +175,6 @@ ipc_client_hmd_get_view_poses(struct xrt_device *xdev, } } -static xrt_result_t -ipc_client_hmd_get_face_tracking(struct xrt_device *xdev, - enum xrt_input_name facial_expression_type, - int64_t at_timestamp_ns, - struct xrt_facial_expression_set *out_value) -{ - ipc_client_hmd_t *icd = ipc_client_hmd(xdev); - - xrt_result_t xret = ipc_call_device_get_face_tracking( // - icd->ipc_c, // - icd->device_id, // - facial_expression_type, // - at_timestamp_ns, // - out_value); // - IPC_CHK_ALWAYS_RET(icd->ipc_c, xret, "ipc_call_device_get_face_tracking"); -} - static bool ipc_client_hmd_compute_distortion( struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result) @@ -271,158 +213,6 @@ ipc_client_hmd_is_form_factor_available(struct xrt_device *xdev, enum xrt_form_f return available; } -static enum xrt_result -ipc_client_hmd_begin_plane_detection_ext(struct xrt_device *xdev, - const struct xrt_plane_detector_begin_info_ext *begin_info, - uint64_t plane_detection_id, - uint64_t *out_plane_detection_id) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - - ich->ipc_c->ism->plane_begin_info_ext = *begin_info; - - xrt_result_t r = ipc_call_device_begin_plane_detection_ext(ich->ipc_c, ich->device_id, plane_detection_id, - out_plane_detection_id); - if (r != XRT_SUCCESS) { - IPC_ERROR(ich->ipc_c, "Error sending hmd_begin_plane_detection_ext!"); - return r; - } - - return XRT_SUCCESS; -} - -static enum xrt_result -ipc_client_hmd_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - - xrt_result_t r = ipc_call_device_destroy_plane_detection_ext(ich->ipc_c, ich->device_id, plane_detection_id); - if (r != XRT_SUCCESS) { - IPC_ERROR(ich->ipc_c, "Error sending destroy_plane_detection_ext!"); - return r; - } - - return XRT_SUCCESS; -} - -/*! - * Helper function for @ref xrt_device::get_plane_detection_state. - * - * @public @memberof xrt_device - */ -static inline enum xrt_result -ipc_client_hmd_get_plane_detection_state_ext(struct xrt_device *xdev, - uint64_t plane_detection_id, - enum xrt_plane_detector_state_ext *out_state) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - - xrt_result_t r = - ipc_call_device_get_plane_detection_state_ext(ich->ipc_c, ich->device_id, plane_detection_id, out_state); - if (r != XRT_SUCCESS) { - IPC_ERROR(ich->ipc_c, "Error sending get_plane_detection_state_ext!"); - return r; - } - - return XRT_SUCCESS; -} - -/*! - * Helper function for @ref xrt_device::get_plane_detections. - * - * @public @memberof xrt_device - */ -static inline enum xrt_result -ipc_client_hmd_get_plane_detections_ext(struct xrt_device *xdev, - uint64_t plane_detection_id, - struct xrt_plane_detections_ext *out_detections) -{ - ipc_client_hmd_t *ich = ipc_client_hmd(xdev); - struct ipc_connection *ipc_c = ich->ipc_c; - - ipc_client_connection_lock(ipc_c); - - xrt_result_t xret = ipc_send_device_get_plane_detections_ext_locked(ipc_c, ich->device_id, plane_detection_id); - IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_send_device_get_plane_detections_ext_locked", out); - - // in this case, size == count - uint32_t location_size = 0; - uint32_t polygon_size = 0; - uint32_t vertex_size = 0; - - xret = ipc_receive_device_get_plane_detections_ext_locked(ipc_c, &location_size, &polygon_size, &vertex_size); - IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_receive_device_get_plane_detections_ext_locked", out); - - - // With no locations, the service won't send anything else - if (location_size < 1) { - out_detections->location_count = 0; - goto out; - } - - // realloc arrays in out_detections if necessary, then receive contents - - out_detections->location_count = location_size; - if (out_detections->location_size < location_size) { - U_ARRAY_REALLOC_OR_FREE(out_detections->locations, struct xrt_plane_detector_location_ext, - location_size); - U_ARRAY_REALLOC_OR_FREE(out_detections->polygon_info_start_index, uint32_t, location_size); - out_detections->location_size = location_size; - } - - if (out_detections->polygon_info_size < polygon_size) { - U_ARRAY_REALLOC_OR_FREE(out_detections->polygon_infos, struct xrt_plane_polygon_info_ext, polygon_size); - out_detections->polygon_info_size = polygon_size; - } - - if (out_detections->vertex_size < vertex_size) { - U_ARRAY_REALLOC_OR_FREE(out_detections->vertices, struct xrt_vec2, vertex_size); - out_detections->vertex_size = vertex_size; - } - - if ((location_size > 0 && - (out_detections->locations == NULL || out_detections->polygon_info_start_index == NULL)) || - (polygon_size > 0 && out_detections->polygon_infos == NULL) || - (vertex_size > 0 && out_detections->vertices == NULL)) { - IPC_ERROR(ich->ipc_c, "Error allocating memory for plane detections!"); - out_detections->location_size = 0; - out_detections->polygon_info_size = 0; - out_detections->vertex_size = 0; - xret = XRT_ERROR_IPC_FAILURE; - goto out; - } - - if (location_size > 0) { - // receive location_count * locations - xret = ipc_receive(&ipc_c->imc, out_detections->locations, - sizeof(struct xrt_plane_detector_location_ext) * location_size); - IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_receive(1)", out); - - // receive location_count * polygon_info_start_index - xret = ipc_receive(&ipc_c->imc, out_detections->polygon_info_start_index, - sizeof(uint32_t) * location_size); - IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_receive(2)", out); - } - - - if (polygon_size > 0) { - // receive polygon_count * polygon_infos - xret = ipc_receive(&ipc_c->imc, out_detections->polygon_infos, - sizeof(struct xrt_plane_polygon_info_ext) * polygon_size); - IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_receive(3)", out); - } - - if (vertex_size > 0) { - // receive vertex_count * vertices - xret = ipc_receive(&ipc_c->imc, out_detections->vertices, sizeof(struct xrt_vec2) * vertex_size); - IPC_CHK_WITH_GOTO(ich->ipc_c, xret, "ipc_receive(4)", out); - } - -out: - ipc_client_connection_unlock(ipc_c); - return xret; -} - static xrt_result_t ipc_client_hmd_get_visibility_mask(struct xrt_device *xdev, enum xrt_visibility_mask_type type, @@ -464,71 +254,52 @@ err_mask_unlock: return XRT_ERROR_IPC_FAILURE; } +static void +ipc_client_hmd_destroy(struct xrt_device *xdev) +{ + ipc_client_hmd_t *ich = ipc_client_hmd(xdev); + + // Remove the variable tracking. + u_var_remove_root(ich); + + // Free and de-init the shared things. + ipc_client_xdev_fini(ich); + + // Free this device with the helper. + u_device_free(&ich->base); +} + /*! * @public @memberof ipc_client_hmd */ struct xrt_device * ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin *xtrack, uint32_t device_id) { + // Convenience helper. struct ipc_shared_memory *ism = ipc_c->ism; - struct ipc_shared_device *isdev = &ism->isdevs[device_id]; - - + // Allocate a HMD device. enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD); ipc_client_hmd_t *ich = U_DEVICE_ALLOCATE(ipc_client_hmd_t, flags, 0, 0); - ich->ipc_c = ipc_c; - ich->device_id = device_id; - ich->base.update_inputs = ipc_client_hmd_update_inputs; - ich->base.get_tracked_pose = ipc_client_hmd_get_tracked_pose; - ich->base.get_face_tracking = ipc_client_hmd_get_face_tracking; + + // Fills in almost everything a regular device needs. + ipc_client_xdev_init(ich, ipc_c, xtrack, device_id); + + // Fill in needed HMD functions, and destroy. ich->base.get_view_poses = ipc_client_hmd_get_view_poses; ich->base.compute_distortion = ipc_client_hmd_compute_distortion; - ich->base.begin_plane_detection_ext = ipc_client_hmd_begin_plane_detection_ext; - ich->base.destroy_plane_detection_ext = ipc_client_hmd_destroy_plane_detection_ext; - ich->base.get_plane_detection_state_ext = ipc_client_hmd_get_plane_detection_state_ext; - ich->base.get_plane_detections_ext = ipc_client_hmd_get_plane_detections_ext; - ich->base.destroy = ipc_client_hmd_destroy; ich->base.is_form_factor_available = ipc_client_hmd_is_form_factor_available; ich->base.get_visibility_mask = ipc_client_hmd_get_visibility_mask; + ich->base.destroy = ipc_client_hmd_destroy; - // Start copying the information from the isdev. - ich->base.tracking_origin = xtrack; - ich->base.name = isdev->name; - ich->device_id = device_id; - - // Print name. - snprintf(ich->base.str, XRT_DEVICE_NAME_LEN, "%s", isdev->str); - snprintf(ich->base.serial, XRT_DEVICE_NAME_LEN, "%s", isdev->serial); - - // Setup inputs, by pointing directly to the shared memory. - assert(isdev->input_count > 0); - ich->base.inputs = &ism->inputs[isdev->first_input_index]; - ich->base.input_count = isdev->input_count; - -#if 0 - // Setup info. - struct u_device_simple_info info; - info.display.w_pixels = 1920; - info.display.h_pixels = 1080; - info.display.w_meters = 0.13f; - info.display.h_meters = 0.07f; - info.lens_horizontal_separation_meters = 0.13f / 2.0f; - info.lens_vertical_position_meters = 0.07f / 2.0f; - info.views[0].fov = 85.0f * (M_PI / 180.0f); - info.views[1].fov = 85.0f * (M_PI / 180.0f); - - if (!u_device_setup_split_side_by_side(&ich->base, &info)) { - IPC_ERROR(ich->ipc_c, "Failed to setup basic device info"); - ipc_client_hmd_destroy(&ich->base); - return NULL; - } -#endif + // Setup blend-modes. + ich->base.hmd->blend_mode_count = ipc_c->ism->hmd.blend_mode_count; for (int i = 0; i < XRT_MAX_DEVICE_BLEND_MODES; i++) { ich->base.hmd->blend_modes[i] = ipc_c->ism->hmd.blend_modes[i]; } + + // Setup the views. ich->base.hmd->view_count = ism->hmd.view_count; - ich->base.hmd->blend_mode_count = ipc_c->ism->hmd.blend_mode_count; for (uint32_t i = 0; i < ich->base.hmd->view_count; ++i) { ich->base.hmd->views[i].display.w_pixels = ipc_c->ism->hmd.views[i].display.w_pixels; ich->base.hmd->views[i].display.h_pixels = ipc_c->ism->hmd.views[i].display.h_pixels; @@ -541,9 +312,5 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c, struct xrt_tracking_origin * u_var_add_root(ich, ich->base.str, true); u_var_add_ro_u32(ich, &ich->device_id, "device_id"); - // Copy information. - ich->base.device_type = isdev->device_type; - ich->base.supported = isdev->supported; - return &ich->base; } diff --git a/src/xrt/ipc/client/ipc_client_space_overseer.c b/src/xrt/ipc/client/ipc_client_space_overseer.c index a6abd8d35..705c21d44 100644 --- a/src/xrt/ipc/client/ipc_client_space_overseer.c +++ b/src/xrt/ipc/client/ipc_client_space_overseer.c @@ -7,12 +7,15 @@ * @ingroup ipc_client */ -#include "client/ipc_client.h" -#include "client/ipc_client_connection.h" -#include "shared/ipc_message_channel.h" #include "xrt/xrt_defines.h" #include "xrt/xrt_space.h" +#include "shared/ipc_message_channel.h" + +#include "client/ipc_client.h" +#include "client/ipc_client_xdev.h" +#include "client/ipc_client_connection.h" + #include "ipc_client_generated.h" diff --git a/src/xrt/ipc/client/ipc_client_xdev.c b/src/xrt/ipc/client/ipc_client_xdev.c new file mode 100644 index 000000000..66a78ef7b --- /dev/null +++ b/src/xrt/ipc/client/ipc_client_xdev.c @@ -0,0 +1,449 @@ +// Copyright 2020-2024, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Shared functions for IPC client @ref xrt_device. + * @author Jakob Bornecrantz + * @author Jakob Bornecrantz + * @author Korcan Hussein + * @ingroup ipc_client + */ + +#include "xrt/xrt_device.h" + +#include "os/os_time.h" + +#include "math/m_api.h" + +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_debug.h" +#include "util/u_device.h" + +#include "client/ipc_client.h" +#include "client/ipc_client_connection.h" +#include "client/ipc_client_xdev.h" +#include "ipc_client_generated.h" + + +/* + * + * Functions from xrt_device. + * + */ + +static xrt_result_t +ipc_client_xdev_update_inputs(struct xrt_device *xdev) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_update_input(icx->ipc_c, icx->device_id); + IPC_CHK_ALWAYS_RET(icx->ipc_c, xret, "ipc_call_device_update_input"); +} + +static xrt_result_t +ipc_client_xdev_get_tracked_pose(struct xrt_device *xdev, + enum xrt_input_name name, + int64_t at_timestamp_ns, + struct xrt_space_relation *out_relation) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_get_tracked_pose( // + icx->ipc_c, // + icx->device_id, // + name, // + at_timestamp_ns, // + out_relation); // + IPC_CHK_ALWAYS_RET(icx->ipc_c, xret, "ipc_call_device_get_tracked_pose"); +} + +static void +ipc_client_xdev_get_hand_tracking(struct xrt_device *xdev, + enum xrt_input_name name, + int64_t at_timestamp_ns, + struct xrt_hand_joint_set *out_value, + int64_t *out_timestamp_ns) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_get_hand_tracking( // + icx->ipc_c, // + icx->device_id, // + name, // + at_timestamp_ns, // + out_value, // + out_timestamp_ns); // + IPC_CHK_ONLY_PRINT(icx->ipc_c, xret, "ipc_call_device_get_hand_tracking"); +} + +static xrt_result_t +ipc_client_xdev_get_face_tracking(struct xrt_device *xdev, + enum xrt_input_name facial_expression_type, + int64_t at_timestamp_ns, + struct xrt_facial_expression_set *out_value) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_get_face_tracking( // + icx->ipc_c, // + icx->device_id, // + facial_expression_type, // + at_timestamp_ns, // + out_value); // + IPC_CHK_ALWAYS_RET(icx->ipc_c, xret, "ipc_call_device_get_face_tracking"); +} + +static xrt_result_t +ipc_client_xdev_get_body_skeleton(struct xrt_device *xdev, + enum xrt_input_name body_tracking_type, + struct xrt_body_skeleton *out_value) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_get_body_skeleton( // + icx->ipc_c, // + icx->device_id, // + body_tracking_type, // + out_value); // + IPC_CHK_ALWAYS_RET(icx->ipc_c, xret, "ipc_call_device_get_body_skeleton"); +} + +static xrt_result_t +ipc_client_xdev_get_body_joints(struct xrt_device *xdev, + enum xrt_input_name body_tracking_type, + int64_t desired_timestamp_ns, + struct xrt_body_joint_set *out_value) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_get_body_joints( // + icx->ipc_c, // + icx->device_id, // + body_tracking_type, // + desired_timestamp_ns, // + out_value); // + IPC_CHK_ALWAYS_RET(icx->ipc_c, xret, "ipc_call_device_get_body_joints"); +} + +static void +ipc_client_xdev_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + struct ipc_connection *ipc_c = icx->ipc_c; + + xrt_result_t xret; + if (value->type == XRT_OUTPUT_VALUE_TYPE_PCM_VIBRATION) { + uint32_t samples_sent = MIN(value->pcm_vibration.sample_rate, 4000); + + struct ipc_pcm_haptic_buffer samples = { + .append = value->pcm_vibration.append, + .num_samples = samples_sent, + .sample_rate = value->pcm_vibration.sample_rate, + }; + + ipc_client_connection_lock(ipc_c); + + xret = ipc_send_device_set_haptic_output_locked(ipc_c, icx->device_id, name, &samples); + IPC_CHK_WITH_RET(ipc_c, xret, "ipc_send_device_set_haptic_output_locked", ); + + xrt_result_t alloc_xret; + xret = ipc_receive(&ipc_c->imc, &alloc_xret, sizeof alloc_xret); + if (xret != XRT_SUCCESS || alloc_xret != XRT_SUCCESS) { + goto send_haptic_output_end; + } + + xret = ipc_send(&ipc_c->imc, value->pcm_vibration.buffer, sizeof(float) * samples_sent); + if (xret != XRT_SUCCESS) { + goto send_haptic_output_end; + } + + xret = ipc_receive(&ipc_c->imc, value->pcm_vibration.samples_consumed, + sizeof(*value->pcm_vibration.samples_consumed)); + if (xret != XRT_SUCCESS) { + goto send_haptic_output_end; + } + + send_haptic_output_end: + ipc_client_connection_unlock(ipc_c); + } else { + xret = ipc_call_device_set_output(ipc_c, icx->device_id, name, value); + IPC_CHK_ONLY_PRINT(ipc_c, xret, "ipc_call_device_set_output"); + } +} + +xrt_result_t +ipc_client_xdev_get_output_limits(struct xrt_device *xdev, struct xrt_output_limits *limits) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t xret = ipc_call_device_get_output_limits(icx->ipc_c, icx->device_id, limits); + IPC_CHK_ONLY_PRINT(icx->ipc_c, xret, "ipc_call_device_get_output_limits"); + + return xret; +} + + +/* + * + * Plane detection functions. + * + */ + +static xrt_result_t +ipc_client_xdev_begin_plane_detection_ext(struct xrt_device *xdev, + const struct xrt_plane_detector_begin_info_ext *begin_info, + uint64_t plane_detection_id, + uint64_t *out_plane_detection_id) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + icx->ipc_c->ism->plane_begin_info_ext = *begin_info; + + xrt_result_t r = ipc_call_device_begin_plane_detection_ext(icx->ipc_c, icx->device_id, plane_detection_id, + out_plane_detection_id); + if (r != XRT_SUCCESS) { + IPC_ERROR(icx->ipc_c, "Error sending hmd_begin_plane_detection_ext!"); + return r; + } + + return XRT_SUCCESS; +} + +static xrt_result_t +ipc_client_xdev_destroy_plane_detection_ext(struct xrt_device *xdev, uint64_t plane_detection_id) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t r = ipc_call_device_destroy_plane_detection_ext(icx->ipc_c, icx->device_id, plane_detection_id); + if (r != XRT_SUCCESS) { + IPC_ERROR(icx->ipc_c, "Error sending destroy_plane_detection_ext!"); + return r; + } + + return XRT_SUCCESS; +} + +/*! + * Helper function for @ref xrt_device::get_plane_detection_state. + * + * @public @memberof xrt_device + */ +static xrt_result_t +ipc_client_xdev_get_plane_detection_state_ext(struct xrt_device *xdev, + uint64_t plane_detection_id, + enum xrt_plane_detector_state_ext *out_state) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + + xrt_result_t r = + ipc_call_device_get_plane_detection_state_ext(icx->ipc_c, icx->device_id, plane_detection_id, out_state); + if (r != XRT_SUCCESS) { + IPC_ERROR(icx->ipc_c, "Error sending get_plane_detection_state_ext!"); + return r; + } + + return XRT_SUCCESS; +} + +/*! + * Helper function for @ref xrt_device::get_plane_detections. + * + * @public @memberof xrt_device + */ +static xrt_result_t +ipc_client_xdev_get_plane_detections_ext(struct xrt_device *xdev, + uint64_t plane_detection_id, + struct xrt_plane_detections_ext *out_detections) +{ + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); + struct ipc_connection *ipc_c = icx->ipc_c; + + ipc_client_connection_lock(ipc_c); + + xrt_result_t xret = ipc_send_device_get_plane_detections_ext_locked(ipc_c, icx->device_id, plane_detection_id); + IPC_CHK_WITH_GOTO(icx->ipc_c, xret, "ipc_send_device_get_plane_detections_ext_locked", out); + + // in this case, size == count + uint32_t location_size = 0; + uint32_t polygon_size = 0; + uint32_t vertex_size = 0; + + xret = ipc_receive_device_get_plane_detections_ext_locked(ipc_c, &location_size, &polygon_size, &vertex_size); + IPC_CHK_WITH_GOTO(icx->ipc_c, xret, "ipc_receive_device_get_plane_detections_ext_locked", out); + + + // With no locations, the service won't send anything else + if (location_size < 1) { + out_detections->location_count = 0; + goto out; + } + + // realloc arrays in out_detections if necessary, then receive contents + + out_detections->location_count = location_size; + if (out_detections->location_size < location_size) { + U_ARRAY_REALLOC_OR_FREE(out_detections->locations, struct xrt_plane_detector_location_ext, + location_size); + U_ARRAY_REALLOC_OR_FREE(out_detections->polygon_info_start_index, uint32_t, location_size); + out_detections->location_size = location_size; + } + + if (out_detections->polygon_info_size < polygon_size) { + U_ARRAY_REALLOC_OR_FREE(out_detections->polygon_infos, struct xrt_plane_polygon_info_ext, polygon_size); + out_detections->polygon_info_size = polygon_size; + } + + if (out_detections->vertex_size < vertex_size) { + U_ARRAY_REALLOC_OR_FREE(out_detections->vertices, struct xrt_vec2, vertex_size); + out_detections->vertex_size = vertex_size; + } + + if ((location_size > 0 && + (out_detections->locations == NULL || out_detections->polygon_info_start_index == NULL)) || + (polygon_size > 0 && out_detections->polygon_infos == NULL) || + (vertex_size > 0 && out_detections->vertices == NULL)) { + IPC_ERROR(icx->ipc_c, "Error allocating memory for plane detections!"); + out_detections->location_size = 0; + out_detections->polygon_info_size = 0; + out_detections->vertex_size = 0; + xret = XRT_ERROR_IPC_FAILURE; + goto out; + } + + if (location_size > 0) { + // receive location_count * locations + xret = ipc_receive(&ipc_c->imc, out_detections->locations, + sizeof(struct xrt_plane_detector_location_ext) * location_size); + IPC_CHK_WITH_GOTO(icx->ipc_c, xret, "ipc_receive(1)", out); + + // receive location_count * polygon_info_start_index + xret = ipc_receive(&ipc_c->imc, out_detections->polygon_info_start_index, + sizeof(uint32_t) * location_size); + IPC_CHK_WITH_GOTO(icx->ipc_c, xret, "ipc_receive(2)", out); + } + + + if (polygon_size > 0) { + // receive polygon_count * polygon_infos + xret = ipc_receive(&ipc_c->imc, out_detections->polygon_infos, + sizeof(struct xrt_plane_polygon_info_ext) * polygon_size); + IPC_CHK_WITH_GOTO(icx->ipc_c, xret, "ipc_receive(3)", out); + } + + if (vertex_size > 0) { + // receive vertex_count * vertices + xret = ipc_receive(&ipc_c->imc, out_detections->vertices, sizeof(struct xrt_vec2) * vertex_size); + IPC_CHK_WITH_GOTO(icx->ipc_c, xret, "ipc_receive(4)", out); + } + +out: + ipc_client_connection_unlock(ipc_c); + return xret; +} + + +/* + * + * 'Exported' functions. + * + */ + +void +ipc_client_xdev_init(struct ipc_client_xdev *icx, + struct ipc_connection *ipc_c, + struct xrt_tracking_origin *xtrack, + uint32_t device_id) +{ + // Helpers. + struct ipc_shared_memory *ism = ipc_c->ism; + struct ipc_shared_device *isdev = &ism->isdevs[device_id]; + + // Important fields. + icx->ipc_c = ipc_c; + icx->device_id = device_id; + + // Shared implemented functions. + icx->base.update_inputs = ipc_client_xdev_update_inputs; + icx->base.get_tracked_pose = ipc_client_xdev_get_tracked_pose; + icx->base.get_hand_tracking = ipc_client_xdev_get_hand_tracking; + icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking; + icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton; + icx->base.get_body_joints = ipc_client_xdev_get_body_joints; + icx->base.set_output = ipc_client_xdev_set_output; + icx->base.get_output_limits = ipc_client_xdev_get_output_limits; + + // Plane detection EXT. + icx->base.begin_plane_detection_ext = ipc_client_xdev_begin_plane_detection_ext; + icx->base.destroy_plane_detection_ext = ipc_client_xdev_destroy_plane_detection_ext; + icx->base.get_plane_detection_state_ext = ipc_client_xdev_get_plane_detection_state_ext; + icx->base.get_plane_detections_ext = ipc_client_xdev_get_plane_detections_ext; + + // Not implemented functions, some get overridden. + icx->base.get_view_poses = u_device_ni_get_view_poses; + icx->base.compute_distortion = u_device_ni_compute_distortion; + icx->base.get_visibility_mask = u_device_ni_get_visibility_mask; + icx->base.is_form_factor_available = u_device_ni_is_form_factor_available; + icx->base.get_battery_status = u_device_ni_get_battery_status; + + // Copying the information from the isdev. + icx->base.device_type = isdev->device_type; + icx->base.supported = isdev->supported; + icx->base.tracking_origin = xtrack; + icx->base.name = isdev->name; + + // Print name. + snprintf(icx->base.str, XRT_DEVICE_NAME_LEN, "%s", isdev->str); + snprintf(icx->base.serial, XRT_DEVICE_NAME_LEN, "%s", isdev->serial); + + // Setup inputs, by pointing directly to the shared memory. + assert(isdev->input_count > 0); + icx->base.inputs = &ism->inputs[isdev->first_input_index]; + icx->base.input_count = isdev->input_count; + + // Setup outputs, if any point directly into the shared memory. + icx->base.output_count = isdev->output_count; + if (isdev->output_count > 0) { + icx->base.outputs = &ism->outputs[isdev->first_output_index]; + } else { + icx->base.outputs = NULL; + } + + // Setup binding profiles. + icx->base.binding_profile_count = isdev->binding_profile_count; + if (isdev->binding_profile_count > 0) { + icx->base.binding_profiles = + U_TYPED_ARRAY_CALLOC(struct xrt_binding_profile, isdev->binding_profile_count); + } + + for (size_t i = 0; i < isdev->binding_profile_count; i++) { + struct xrt_binding_profile *xbp = &icx->base.binding_profiles[i]; + struct ipc_shared_binding_profile *isbp = + &ism->binding_profiles[isdev->first_binding_profile_index + i]; + + xbp->name = isbp->name; + if (isbp->input_count > 0) { + xbp->inputs = &ism->input_pairs[isbp->first_input_index]; + xbp->input_count = isbp->input_count; + } + if (isbp->output_count > 0) { + xbp->outputs = &ism->output_pairs[isbp->first_output_index]; + xbp->output_count = isbp->output_count; + } + } +} + +void +ipc_client_xdev_fini(struct ipc_client_xdev *icx) +{ + // We do not own these, so don't free them. + icx->base.inputs = NULL; + icx->base.outputs = NULL; + + // We allocated the bindings profiles. + if (icx->base.binding_profiles != NULL) { + free(icx->base.binding_profiles); + icx->base.binding_profiles = NULL; + } +} diff --git a/src/xrt/ipc/client/ipc_client_xdev.h b/src/xrt/ipc/client/ipc_client_xdev.h new file mode 100644 index 000000000..0c9d31890 --- /dev/null +++ b/src/xrt/ipc/client/ipc_client_xdev.h @@ -0,0 +1,75 @@ +// Copyright 2020-2023, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Shared functions for IPC client @ref xrt_device. + * @author Pete Black + * @author Jakob Bornecrantz + * @author Jakob Bornecrantz + * @author Rylie Pavlik + * @ingroup ipc_client + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + +struct ipc_connection; + +/*! + * An IPC client proxy for an @ref xrt_device. + * + * @implements xrt_device + * @ingroup ipc_client + */ +struct ipc_client_xdev +{ + struct xrt_device base; + + struct ipc_connection *ipc_c; + + uint32_t device_id; +}; + +/*! + * Convenience helper to go from a xdev to @ref ipc_client_xdev. + * + * @ingroup ipc_client + */ +static inline struct ipc_client_xdev * +ipc_client_xdev(struct xrt_device *xdev) +{ + return (struct ipc_client_xdev *)xdev; +} + +/*! + * Initializes a ipc_client_xdev so that it's basically fully usable as a + * @ref xrt_device object. Does not fill in the destroy function or the any + * if the HMD components / functions. + * + * @ingroup ipc_client + * @public @memberof ipc_client_xdev + */ +void +ipc_client_xdev_init(struct ipc_client_xdev *icx, + struct ipc_connection *ipc_c, + struct xrt_tracking_origin *xtrack, + uint32_t device_id); + +/*! + * Frees any memory that was allocated as part of init and resets some pointers. + * + * @ingroup ipc_client + * @public @memberof ipc_client_xdev + */ +void +ipc_client_xdev_fini(struct ipc_client_xdev *icx); + + +#ifdef __cplusplus +} +#endif