The open source OpenXR runtime

Enable eye tracking on demand

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2223>

authored by

Jiali Zhang and committed by
Marge Bot
ed1ea5af 357cf0e9

+336
+78
src/xrt/auxiliary/util/u_system_helpers.c
··· 44 44 return -1; 45 45 } 46 46 47 + static const char * 48 + type_to_small_string(enum xrt_device_feature_type type) 49 + { 50 + switch (type) { 51 + case XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT: return "hand_tracking_left"; 52 + case XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT: return "hand_tracking_right"; 53 + case XRT_DEVICE_FEATURE_EYE_TRACKING: return "eye_tracking"; 54 + default: return "invalid"; 55 + } 56 + } 47 57 48 58 49 59 /* ··· 71 81 return XRT_SUCCESS; 72 82 } 73 83 84 + static xrt_result_t 85 + feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 86 + { 87 + struct u_system_devices_static *usysds = u_system_devices_static(xsysd); 88 + 89 + if (type >= XRT_DEVICE_FEATURE_MAX_ENUM) { 90 + return XRT_ERROR_FEATURE_NOT_SUPPORTED; 91 + } 92 + 93 + // If it wasn't zero nothing to do. 94 + if (!xrt_reference_inc_and_was_zero(&usysds->feature_use[type])) { 95 + return XRT_SUCCESS; 96 + } 97 + 98 + xrt_result_t xret; 99 + if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT) { 100 + xret = xrt_device_begin_feature(xsysd->static_roles.hand_tracking.left, type); 101 + } else if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT) { 102 + xret = xrt_device_begin_feature(xsysd->static_roles.hand_tracking.right, type); 103 + } else if (type == XRT_DEVICE_FEATURE_EYE_TRACKING) { 104 + xret = xrt_device_begin_feature(xsysd->static_roles.eyes, type); 105 + } else { 106 + xret = XRT_ERROR_FEATURE_NOT_SUPPORTED; 107 + } 108 + if (xret != XRT_SUCCESS) { 109 + return xret; 110 + } 111 + 112 + U_LOG_D("Device-feature %s in use", type_to_small_string(type)); 113 + 114 + return XRT_SUCCESS; 115 + } 116 + 117 + static xrt_result_t 118 + feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 119 + { 120 + struct u_system_devices_static *usysds = u_system_devices_static(xsysd); 121 + 122 + if (type >= XRT_DEVICE_FEATURE_MAX_ENUM) { 123 + return XRT_ERROR_FEATURE_NOT_SUPPORTED; 124 + } 125 + 126 + // If it is not zero we are done. 127 + if (!xrt_reference_dec_and_is_zero(&usysds->feature_use[type])) { 128 + return XRT_SUCCESS; 129 + } 130 + 131 + xrt_result_t xret; 132 + if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT) { 133 + xret = xrt_device_end_feature(xsysd->static_roles.hand_tracking.left, type); 134 + } else if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT) { 135 + xret = xrt_device_end_feature(xsysd->static_roles.hand_tracking.right, type); 136 + } else if (type == XRT_DEVICE_FEATURE_EYE_TRACKING) { 137 + xret = xrt_device_end_feature(xsysd->static_roles.eyes, type); 138 + } else { 139 + xret = XRT_ERROR_FEATURE_NOT_SUPPORTED; 140 + } 141 + if (xret != XRT_SUCCESS) { 142 + return xret; 143 + } 144 + 145 + U_LOG_D("Device-feature %s no longer in use", type_to_small_string(type)); 146 + 147 + return XRT_SUCCESS; 148 + } 149 + 74 150 75 151 /* 76 152 * ··· 107 183 struct u_system_devices_static *usysds = U_TYPED_CALLOC(struct u_system_devices_static); 108 184 usysds->base.base.destroy = destroy; 109 185 usysds->base.base.get_roles = get_roles; 186 + usysds->base.base.feature_inc = feature_inc; 187 + usysds->base.base.feature_dec = feature_dec; 110 188 111 189 return usysds; 112 190 }
+3
src/xrt/auxiliary/util/u_system_helpers.h
··· 113 113 114 114 //! Is automatically returned. 115 115 struct xrt_system_roles cached; 116 + 117 + //! Tracks usage of device features. 118 + struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM]; 116 119 }; 117 120 118 121 /*!
+59
src/xrt/include/xrt/xrt_device.h
··· 220 220 }; 221 221 222 222 /*! 223 + * Higher level features for devices. 224 + */ 225 + enum xrt_device_feature_type 226 + { 227 + XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT = 0, 228 + XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT, 229 + XRT_DEVICE_FEATURE_EYE_TRACKING, 230 + XRT_DEVICE_FEATURE_MAX_ENUM, 231 + }; 232 + 233 + /*! 223 234 * @interface xrt_device 224 235 * 225 236 * A single HMD or input device. ··· 520 531 float *out_charge); 521 532 522 533 /*! 534 + * Enable the feature for this device. 535 + * 536 + * @param[in] xdev The device. 537 + * @param[in] type The type of device feature. 538 + */ 539 + xrt_result_t (*begin_feature)(struct xrt_device *xdev, enum xrt_device_feature_type type); 540 + 541 + /*! 542 + * Disable the feature for this device. 543 + * 544 + * @param[in] xdev The device. 545 + * @param[in] type The type of device feature. 546 + */ 547 + xrt_result_t (*end_feature)(struct xrt_device *xdev, enum xrt_device_feature_type type); 548 + 549 + /*! 523 550 * Destroy device. 524 551 */ 525 552 void (*destroy)(struct xrt_device *xdev); ··· 734 761 return XRT_ERROR_NOT_IMPLEMENTED; 735 762 } 736 763 return xdev->get_battery_status(xdev, out_present, out_charging, out_charge); 764 + } 765 + 766 + /*! 767 + * Helper function for @ref xrt_device::begin_feature. 768 + * 769 + * @copydoc xrt_device::begin_feature 770 + * 771 + * @public @memberof xrt_device 772 + */ 773 + static inline xrt_result_t 774 + xrt_device_begin_feature(struct xrt_device *xdev, enum xrt_device_feature_type type) 775 + { 776 + if (xdev->begin_feature == NULL) { 777 + return XRT_ERROR_NOT_IMPLEMENTED; 778 + } 779 + return xdev->begin_feature(xdev, type); 780 + } 781 + 782 + /*! 783 + * Helper function for @ref xrt_device::end_feature. 784 + * 785 + * @copydoc xrt_device::end_feature 786 + * 787 + * @public @memberof xrt_device 788 + */ 789 + static inline xrt_result_t 790 + xrt_device_end_feature(struct xrt_device *xdev, enum xrt_device_feature_type type) 791 + { 792 + if (xdev->end_feature == NULL) { 793 + return XRT_ERROR_NOT_IMPLEMENTED; 794 + } 795 + return xdev->end_feature(xdev, type); 737 796 } 738 797 739 798 /*!
+5
src/xrt/include/xrt/xrt_results.h
··· 193 193 * Some other Android error, typically a logic error that should be impossible to reach. 194 194 */ 195 195 XRT_ERROR_ANDROID = -31, 196 + 197 + /*! 198 + * Returned when a feature is not supported by the device. 199 + */ 200 + XRT_ERROR_FEATURE_NOT_SUPPORTED = -32, 196 201 } xrt_result_t;
+45
src/xrt/include/xrt/xrt_system.h
··· 13 13 14 14 #include "xrt/xrt_compiler.h" 15 15 #include "xrt/xrt_defines.h" 16 + #include "xrt/xrt_device.h" 16 17 17 18 18 19 #ifdef __cplusplus ··· 302 303 xrt_result_t (*get_roles)(struct xrt_system_devices *xsysd, struct xrt_system_roles *out_roles); 303 304 304 305 /*! 306 + * Increment the usage count of a feature. 307 + * When the feature is used for the first time, then the feature will be begun. 308 + * 309 + * @param xsysd Pointer to self 310 + * @param feature Which feature is being counted. 311 + */ 312 + xrt_result_t (*feature_inc)(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type); 313 + 314 + /*! 315 + * Decrement the usage count of a feature. 316 + * When the feature is not used by the current application any more, then the feature will be ended. 317 + * 318 + * @param xsysd Pointer to self 319 + * @param feature Which feature is being counted. 320 + */ 321 + xrt_result_t (*feature_dec)(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type); 322 + 323 + /*! 305 324 * Destroy all the devices that are owned by this system devices. 306 325 * 307 326 * Code consuming this interface should use @ref xrt_system_devices_destroy. ··· 322 341 xrt_system_devices_get_roles(struct xrt_system_devices *xsysd, struct xrt_system_roles *out_roles) 323 342 { 324 343 return xsysd->get_roles(xsysd, out_roles); 344 + } 345 + 346 + /*! 347 + * @copydoc xrt_system_devices::feature_inc 348 + * 349 + * Helper for calling through the function pointer. 350 + * 351 + * @public @memberof xrt_system_devices 352 + */ 353 + static inline xrt_result_t 354 + xrt_system_devices_feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 355 + { 356 + return xsysd->feature_inc(xsysd, type); 357 + } 358 + 359 + /*! 360 + * @copydoc xrt_system_devices::feature_dec 361 + * 362 + * Helper for calling through the function pointer. 363 + * 364 + * @public @memberof xrt_system_devices 365 + */ 366 + static inline xrt_result_t 367 + xrt_system_devices_feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 368 + { 369 + return xsysd->feature_dec(xsysd, type); 325 370 } 326 371 327 372 /*!
+39
src/xrt/ipc/client/ipc_client_system_devices.c
··· 21 21 22 22 //! Connection to service. 23 23 struct ipc_connection *ipc_c; 24 + 25 + struct xrt_reference feature_use[XRT_DEVICE_FEATURE_MAX_ENUM]; 24 26 }; 25 27 26 28 ··· 51 53 return ipc_call_system_devices_get_roles(usysd->ipc_c, out_roles); 52 54 } 53 55 56 + static xrt_result_t 57 + ipc_client_system_devices_feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 58 + { 59 + struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd); 60 + xrt_result_t xret; 61 + 62 + assert(type < XRT_DEVICE_FEATURE_MAX_ENUM); 63 + 64 + // If it wasn't zero nothing to do. 65 + if (!xrt_reference_inc_and_was_zero(&usysd->feature_use[type])) { 66 + return XRT_SUCCESS; 67 + } 68 + 69 + xret = ipc_call_system_devices_begin_feature(usysd->ipc_c, type); 70 + IPC_CHK_ALWAYS_RET(usysd->ipc_c, xret, "ipc_call_system_devices_begin_feature"); 71 + } 72 + 73 + static xrt_result_t 74 + ipc_client_system_devices_feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 75 + { 76 + struct ipc_client_system_devices *usysd = ipc_system_devices(xsysd); 77 + xrt_result_t xret; 78 + 79 + assert(type < XRT_DEVICE_FEATURE_MAX_ENUM); 80 + 81 + // If it is not zero we are done. 82 + if (!xrt_reference_dec_and_is_zero(&usysd->feature_use[type])) { 83 + return XRT_SUCCESS; 84 + } 85 + 86 + xret = ipc_call_system_devices_end_feature(usysd->ipc_c, type); 87 + IPC_CHK_ALWAYS_RET(usysd->ipc_c, xret, "ipc_call_system_devices_end_feature"); 88 + } 89 + 90 + 54 91 static void 55 92 ipc_client_system_devices_destroy(struct xrt_system_devices *xsysd) 56 93 { ··· 74 111 struct ipc_client_system_devices *icsd = U_TYPED_CALLOC(struct ipc_client_system_devices); 75 112 icsd->base.base.get_roles = ipc_client_system_devices_get_roles; 76 113 icsd->base.base.destroy = ipc_client_system_devices_destroy; 114 + icsd->base.base.feature_inc = ipc_client_system_devices_feature_inc; 115 + icsd->base.base.feature_dec = ipc_client_system_devices_feature_dec; 77 116 icsd->ipc_c = ipc_c; 78 117 79 118 return &icsd->base.base;
+3
src/xrt/ipc/server/ipc_server.h
··· 131 131 //! Which of the references spaces is the client using. 132 132 bool ref_space_used[XRT_SPACE_REFERENCE_TYPE_COUNT]; 133 133 134 + //! Which of the device features is the client using. 135 + bool device_feature_used[XRT_DEVICE_FEATURE_MAX_ENUM]; 136 + 134 137 //! Socket fd used for client comms 135 138 struct ipc_message_channel imc; 136 139
+69
src/xrt/ipc/server/ipc_server_handler.c
··· 114 114 } 115 115 116 116 static xrt_result_t 117 + validate_device_feature_type(volatile struct ipc_client_state *ics, enum xrt_device_feature_type type) 118 + { 119 + if ((uint32_t)type >= XRT_DEVICE_FEATURE_MAX_ENUM) { 120 + IPC_ERROR(ics->server, "Invalid device feature type %u", type); 121 + return XRT_ERROR_FEATURE_NOT_SUPPORTED; 122 + } 123 + 124 + return XRT_SUCCESS; 125 + } 126 + 127 + 128 + static xrt_result_t 117 129 validate_space_id(volatile struct ipc_client_state *ics, int64_t space_id, struct xrt_space **out_xspc) 118 130 { 119 131 if (space_id < 0) { ··· 2148 2160 ipc_handle_system_devices_get_roles(volatile struct ipc_client_state *ics, struct xrt_system_roles *out_roles) 2149 2161 { 2150 2162 return xrt_system_devices_get_roles(ics->server->xsysd, out_roles); 2163 + } 2164 + 2165 + xrt_result_t 2166 + ipc_handle_system_devices_begin_feature(volatile struct ipc_client_state *ics, enum xrt_device_feature_type type) 2167 + { 2168 + struct xrt_system_devices *xsysd = ics->server->xsysd; 2169 + xrt_result_t xret; 2170 + 2171 + xret = validate_device_feature_type(ics, type); 2172 + if (xret != XRT_SUCCESS) { 2173 + return XRT_ERROR_IPC_FAILURE; 2174 + } 2175 + 2176 + // Is this feature already used? 2177 + if (ics->device_feature_used[type]) { 2178 + IPC_ERROR(ics->server, "feature '%u' already used!", type); 2179 + return XRT_ERROR_IPC_FAILURE; 2180 + } 2181 + 2182 + xret = xrt_system_devices_feature_inc(xsysd, type); 2183 + if (xret != XRT_SUCCESS) { 2184 + IPC_ERROR(ics->server, "xrt_system_devices_feature_inc failed"); 2185 + return xret; 2186 + } 2187 + 2188 + // Can now mark it as used. 2189 + ics->device_feature_used[type] = true; 2190 + 2191 + return XRT_SUCCESS; 2192 + } 2193 + 2194 + xrt_result_t 2195 + ipc_handle_system_devices_end_feature(volatile struct ipc_client_state *ics, enum xrt_device_feature_type type) 2196 + { 2197 + struct xrt_system_devices *xsysd = ics->server->xsysd; 2198 + xrt_result_t xret; 2199 + 2200 + xret = validate_device_feature_type(ics, type); 2201 + if (xret != XRT_SUCCESS) { 2202 + return XRT_ERROR_IPC_FAILURE; 2203 + } 2204 + 2205 + if (!ics->device_feature_used[type]) { 2206 + IPC_ERROR(ics->server, "feature '%u' not used!", type); 2207 + return XRT_ERROR_IPC_FAILURE; 2208 + } 2209 + 2210 + xret = xrt_system_devices_feature_dec(xsysd, type); 2211 + if (xret != XRT_SUCCESS) { 2212 + IPC_ERROR(ics->server, "xrt_system_devices_feature_dec failed"); 2213 + return xret; 2214 + } 2215 + 2216 + // Now we can mark it as not used. 2217 + ics->device_feature_used[type] = false; 2218 + 2219 + return XRT_SUCCESS; 2151 2220 } 2152 2221 2153 2222 xrt_result_t
+11
src/xrt/ipc/server/ipc_server_per_client_thread.c
··· 90 90 ics->ref_space_used[i] = false; 91 91 } 92 92 93 + // Make a still in use device features as no longer used. 94 + for (uint32_t i = 0; i < ARRAY_SIZE(ics->device_feature_used); i++) { 95 + bool used = ics->device_feature_used[i]; 96 + if (!used) { 97 + continue; 98 + } 99 + 100 + xrt_system_devices_feature_dec(ics->server->xsysd, (enum xrt_device_feature_type)i); 101 + ics->device_feature_used[i] = false; 102 + } 103 + 93 104 // Should we stop the server when a client disconnects? 94 105 if (ics->server->exit_on_disconnect) { 95 106 ics->server->running = false;
+12
src/xrt/ipc/shared/proto.json
··· 62 62 ] 63 63 }, 64 64 65 + "system_devices_begin_feature": { 66 + "in": [ 67 + {"name": "type", "type": "enum xrt_device_feature_type"} 68 + ] 69 + }, 70 + 71 + "system_devices_end_feature": { 72 + "in": [ 73 + {"name": "type", "type": "enum xrt_device_feature_type"} 74 + ] 75 + }, 76 + 65 77 "system_compositor_get_info": { 66 78 "out": [ 67 79 {"name": "info", "type": "struct xrt_system_compositor_info"}
+12
src/xrt/state_trackers/oxr/oxr_space.c
··· 72 72 if (xret != XRT_SUCCESS) { 73 73 oxr_warn(log, "Failed to create pose space"); 74 74 } else { 75 + struct xrt_system_devices *xsysd = spc->sess->sys->xsysd; 76 + if (xdev == xsysd->static_roles.eyes) { 77 + // eye tracking is being used 78 + xrt_system_devices_feature_inc(xsysd, XRT_DEVICE_FEATURE_EYE_TRACKING); 79 + } 80 + 75 81 spc->action.xdev = xdev; 76 82 spc->action.name = name; 77 83 } ··· 126 132 enum xrt_reference_space_type xtype = oxr_ref_space_to_xrt(spc->space_type); 127 133 if (xtype != XRT_SPACE_REFERENCE_TYPE_INVALID) { 128 134 xrt_space_overseer_ref_space_dec(spc->sess->sys->xso, xtype); 135 + } 136 + 137 + struct xrt_system_devices *xsysd = spc->sess->sys->xsysd; 138 + if (spc->action.xdev && spc->action.xdev == xsysd->static_roles.eyes) { 139 + // eye tracking isn't being used anymore 140 + xrt_system_devices_feature_dec(xsysd, XRT_DEVICE_FEATURE_EYE_TRACKING); 129 141 } 130 142 131 143 xrt_space_reference(&spc->xdev_pose.xs, NULL);