The open source OpenXR runtime
at main 332 lines 8.5 kB view raw
1// Copyright 2022-2023, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Helpers for system objects like @ref xrt_system_devices. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup aux_util 8 */ 9 10#include "xrt/xrt_device.h" 11#include "xrt/xrt_prober.h" 12 13#include "util/u_misc.h" 14#include "util/u_device.h" 15#include "util/u_logging.h" 16#include "util/u_system_helpers.h" 17 18#include <assert.h> 19#include <limits.h> 20 21 22/* 23 * 24 * Helper functions. 25 * 26 */ 27 28static int32_t 29get_index_for_device(const struct xrt_system_devices *xsysd, const struct xrt_device *xdev) 30{ 31 assert(xsysd->xdev_count <= ARRAY_SIZE(xsysd->xdevs)); 32 assert(xsysd->xdev_count < INT_MAX); 33 34 if (xdev == NULL) { 35 return -1; 36 } 37 38 for (int32_t i = 0; i < (int32_t)xsysd->xdev_count; i++) { 39 if (xsysd->xdevs[i] == xdev) { 40 return i; 41 } 42 } 43 44 return -1; 45} 46 47static const char * 48type_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} 57 58static inline void 59get_hand_tracking_devices(struct xrt_system_devices *xsysd, enum xrt_hand hand, struct xrt_device *out_ht_xdevs[2]) 60{ 61#define XRT_GET_U_HT(HAND) xsysd->static_roles.hand_tracking.unobstructed.HAND 62#define XRT_GET_C_HT(HAND) xsysd->static_roles.hand_tracking.conforming.HAND 63 if (hand == XRT_HAND_LEFT) { 64 out_ht_xdevs[0] = XRT_GET_U_HT(left); 65 out_ht_xdevs[1] = XRT_GET_C_HT(left); 66 } else { 67 out_ht_xdevs[0] = XRT_GET_U_HT(right); 68 out_ht_xdevs[1] = XRT_GET_C_HT(right); 69 } 70#undef XRT_GET_C_HT 71#undef XRT_GET_U_HT 72} 73 74static xrt_result_t 75set_hand_tracking_enabled(struct xrt_system_devices *xsysd, enum xrt_hand hand, bool enable) 76{ 77 struct xrt_device *ht_sources[2] = {0}; 78 get_hand_tracking_devices(xsysd, hand, ht_sources); 79 80 uint32_t ht_sources_size = ARRAY_SIZE(ht_sources); 81 // hand-tracking data-sources can all come from the same xrt-device instance 82 if (ht_sources[0] == ht_sources[1]) { 83 ht_sources_size = 1; 84 } 85 86 typedef xrt_result_t (*set_feature_t)(struct xrt_device *, enum xrt_device_feature_type); 87 const set_feature_t set_feature = enable ? xrt_device_begin_feature : xrt_device_end_feature; 88 89 const enum xrt_device_feature_type ht_feature = 90 (hand == XRT_HAND_LEFT) ? XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT : XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT; 91 92 xrt_result_t xret = XRT_SUCCESS; 93 for (uint32_t i = 0; i < ht_sources_size; ++i) { 94 if (ht_sources[i]) { 95 xret = set_feature(ht_sources[i], ht_feature); 96 } 97 if (xret != XRT_SUCCESS) { 98 break; 99 } 100 } 101 return xret; 102} 103 104 105/* 106 * 107 * Internal functions. 108 * 109 */ 110 111static void 112destroy(struct xrt_system_devices *xsysd) 113{ 114 u_system_devices_close(xsysd); 115 free(xsysd); 116} 117 118static xrt_result_t 119get_roles(struct xrt_system_devices *xsysd, struct xrt_system_roles *out_roles) 120{ 121 struct u_system_devices_static *usysds = u_system_devices_static(xsysd); 122 123 assert(usysds->cached.generation_id == 1); 124 125 *out_roles = usysds->cached; 126 127 return XRT_SUCCESS; 128} 129 130static xrt_result_t 131feature_inc(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 132{ 133 struct u_system_devices_static *usysds = u_system_devices_static(xsysd); 134 135 if (type >= XRT_DEVICE_FEATURE_MAX_ENUM) { 136 return XRT_ERROR_FEATURE_NOT_SUPPORTED; 137 } 138 139 // If it wasn't zero nothing to do. 140 if (!xrt_reference_inc_and_was_zero(&usysds->feature_use[type])) { 141 return XRT_SUCCESS; 142 } 143 144 xrt_result_t xret = XRT_SUCCESS; 145 if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT) { 146 xret = set_hand_tracking_enabled(xsysd, XRT_HAND_LEFT, true); 147 } else if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT) { 148 xret = set_hand_tracking_enabled(xsysd, XRT_HAND_RIGHT, true); 149 } else if (type == XRT_DEVICE_FEATURE_EYE_TRACKING) { 150 xret = xrt_device_begin_feature(xsysd->static_roles.eyes, type); 151 } else { 152 xret = XRT_ERROR_FEATURE_NOT_SUPPORTED; 153 } 154 if (xret != XRT_SUCCESS) { 155 return xret; 156 } 157 158 U_LOG_D("Device-feature %s in use", type_to_small_string(type)); 159 160 return XRT_SUCCESS; 161} 162 163static xrt_result_t 164feature_dec(struct xrt_system_devices *xsysd, enum xrt_device_feature_type type) 165{ 166 struct u_system_devices_static *usysds = u_system_devices_static(xsysd); 167 168 if (type >= XRT_DEVICE_FEATURE_MAX_ENUM) { 169 return XRT_ERROR_FEATURE_NOT_SUPPORTED; 170 } 171 172 // If it is not zero we are done. 173 if (!xrt_reference_dec_and_is_zero(&usysds->feature_use[type])) { 174 return XRT_SUCCESS; 175 } 176 177 xrt_result_t xret; 178 if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_LEFT) { 179 xret = set_hand_tracking_enabled(xsysd, XRT_HAND_LEFT, false); 180 } else if (type == XRT_DEVICE_FEATURE_HAND_TRACKING_RIGHT) { 181 xret = set_hand_tracking_enabled(xsysd, XRT_HAND_RIGHT, false); 182 } else if (type == XRT_DEVICE_FEATURE_EYE_TRACKING) { 183 xret = xrt_device_end_feature(xsysd->static_roles.eyes, type); 184 } else { 185 xret = XRT_ERROR_FEATURE_NOT_SUPPORTED; 186 } 187 if (xret != XRT_SUCCESS) { 188 return xret; 189 } 190 191 U_LOG_D("Device-feature %s no longer in use", type_to_small_string(type)); 192 193 return XRT_SUCCESS; 194} 195 196 197/* 198 * 199 * 'Exported' functions. 200 * 201 */ 202 203struct u_system_devices * 204u_system_devices_allocate(void) 205{ 206 struct u_system_devices *usysd = U_TYPED_CALLOC(struct u_system_devices); 207 usysd->base.destroy = destroy; 208 209 return usysd; 210} 211 212void 213u_system_devices_close(struct xrt_system_devices *xsysd) 214{ 215 struct u_system_devices *usysd = u_system_devices(xsysd); 216 217 for (uint32_t i = 0; i < ARRAY_SIZE(usysd->base.xdevs); i++) { 218 xrt_device_destroy(&usysd->base.xdevs[i]); 219 } 220 221 xrt_frame_context_destroy_nodes(&usysd->xfctx); 222} 223 224 225 226struct u_system_devices_static * 227u_system_devices_static_allocate(void) 228{ 229 struct u_system_devices_static *usysds = U_TYPED_CALLOC(struct u_system_devices_static); 230 usysds->base.base.destroy = destroy; 231 usysds->base.base.get_roles = get_roles; 232 usysds->base.base.feature_inc = feature_inc; 233 usysds->base.base.feature_dec = feature_dec; 234 235 return usysds; 236} 237 238void 239u_system_devices_static_finalize(struct u_system_devices_static *usysds, 240 struct xrt_device *left, 241 struct xrt_device *right, 242 struct xrt_device *gamepad) 243{ 244 struct xrt_system_devices *xsysd = &usysds->base.base; 245 int32_t left_index = get_index_for_device(xsysd, left); 246 int32_t right_index = get_index_for_device(xsysd, right); 247 int32_t gamepad_index = get_index_for_device(xsysd, gamepad); 248 249 U_LOG_D( 250 "Devices:" 251 "\n\t%i: %p" 252 "\n\t%i: %p" 253 "\n\t%i: %p", 254 left_index, (void *)left, // 255 right_index, (void *)right, // 256 gamepad_index, (void *)gamepad); // 257 258 // Consistency checking. 259 assert(usysds->cached.generation_id == 0); 260 assert(left_index < 0 || left != NULL); 261 assert(left_index >= 0 || left == NULL); 262 assert(right_index < 0 || right != NULL); 263 assert(right_index >= 0 || right == NULL); 264 assert(gamepad_index < 0 || gamepad != NULL); 265 assert(gamepad_index >= 0 || gamepad == NULL); 266 267 // Completely clear the struct. 268 usysds->cached = (struct xrt_system_roles)XRT_SYSTEM_ROLES_INIT; 269 usysds->cached.generation_id = 1; 270 usysds->cached.left = left_index; 271 usysds->cached.right = right_index; 272 usysds->cached.gamepad = gamepad_index; 273} 274 275 276/* 277 * 278 * Generic system devices helper. 279 * 280 */ 281 282xrt_result_t 283u_system_devices_create_from_prober(struct xrt_instance *xinst, 284 struct xrt_session_event_sink *broadcast, 285 struct xrt_system_devices **out_xsysd, 286 struct xrt_space_overseer **out_xso) 287{ 288 xrt_result_t xret; 289 290 assert(out_xsysd != NULL); 291 assert(*out_xsysd == NULL); 292 293 294 /* 295 * Create the devices. 296 */ 297 298 struct xrt_prober *xp = NULL; 299 xret = xrt_instance_get_prober(xinst, &xp); 300 if (xret != XRT_SUCCESS) { 301 return xret; 302 } 303 304 xret = xrt_prober_probe(xp); 305 if (xret < 0) { 306 return xret; 307 } 308 309 return xrt_prober_create_system(xp, broadcast, out_xsysd, out_xso); 310} 311 312struct xrt_device * 313u_system_devices_get_ht_device(struct xrt_system_devices *xsysd, enum xrt_input_name name) 314{ 315 for (uint32_t i = 0; i < xsysd->xdev_count; i++) { 316 struct xrt_device *xdev = xsysd->xdevs[i]; 317 318 if (xdev == NULL || !xdev->supported.hand_tracking) { 319 continue; 320 } 321 322 for (uint32_t j = 0; j < xdev->input_count; j++) { 323 struct xrt_input *input = &xdev->inputs[j]; 324 325 if (input->name == name) { 326 return xdev; 327 } 328 } 329 } 330 331 return NULL; 332}