The open source OpenXR runtime

xrt, ipc, st/oxr: Implement XR_EXT_user_presence

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

authored by

Sapphire and committed by
Marge Bot
a90410b6 a69f7298

+139 -3
+2
CMakeLists.txt
··· 366 366 option(XRT_FEATURE_OPENXR_OVERLAY "Enable XR_EXTX_overlay" ON) 367 367 option(XRT_FEATURE_OPENXR_PERFORMANCE_SETTINGS "Enable XR_EXT_performance_settings" OFF) 368 368 option(XRT_FEATURE_OPENXR_PLANE_DETECTION "Enable XR_EXT_plane_detection" OFF) 369 + option(XRT_FEATURE_OPENXR_USER_PRESENCE "Enable XR_EXT_user_presence" ON) 369 370 option(XRT_FEATURE_OPENXR_VISIBILITY_MASK "Enable XR_KHR_visibility_mask" ON) 370 371 option(XRT_FEATURE_OPENXR_VULKAN_SWAPCHAIN_FORMAT_LIST "Enable XR_KHR_vulkan_swapchain_format_list" ON) 371 372 option(XRT_FEATURE_OPENXR_XDEV_SPACE "Enable XR_MNDX_xdev_space" ON) ··· 628 629 message(STATUS "# FEATURE_OPENXR_OVERLAY: ${XRT_FEATURE_OPENXR_OVERLAY}") 629 630 message(STATUS "# FEATURE_OPENXR_PERFORMANCE_SETTINGS: ${XRT_FEATURE_OPENXR_PERFORMANCE_SETTINGS}") 630 631 message(STATUS "# FEATURE_OPENXR_PLANE_DETECTION: ${XRT_FEATURE_OPENXR_PLANE_DETECTION}") 632 + message(STATUS "# FEATURE_OPENXR_USER_PRESENCE: ${XRT_FEATURE_OPENXR_USER_PRESENCE}") 631 633 message(STATUS "# FEATURE_OPENXR_SPACE_LOCAL_FLOOR: ${XRT_FEATURE_OPENXR_SPACE_LOCAL_FLOOR}") 632 634 message(STATUS "# FEATURE_OPENXR_SPACE_UNBOUNDED: ${XRT_FEATURE_OPENXR_SPACE_UNBOUNDED}") 633 635 message(STATUS "# FEATURE_OPENXR_VISIBILITY_MASK: ${XRT_FEATURE_OPENXR_VISIBILITY_MASK}")
+1
scripts/generate_oxr_ext_support.py
··· 72 72 ['XR_EXT_performance_settings', 'XRT_FEATURE_OPENXR_PERFORMANCE_SETTINGS'], 73 73 ['XR_EXT_plane_detection', 'XRT_FEATURE_OPENXR_PLANE_DETECTION'], 74 74 ['XR_EXT_samsung_odyssey_controller', 'XRT_FEATURE_OPENXR_INTERACTION_WINMR'], 75 + ['XR_EXT_user_presence', 'XRT_FEATURE_OPENXR_USER_PRESENCE'], 75 76 # Vendor extensions, sorted alphabetically. 76 77 ['XR_BD_controller_interaction', 'XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE'], 77 78 ['XR_FB_body_tracking', 'XRT_FEATURE_OPENXR_BODY_TRACKING_FB'],
+1
src/xrt/include/xrt/xrt_config_build.h.cmake_in
··· 69 69 #cmakedefine XRT_FEATURE_OPENXR_LAYER_FB_PASSTHROUGH 70 70 #cmakedefine XRT_FEATURE_OPENXR_OVERLAY 71 71 #cmakedefine XRT_FEATURE_OPENXR_PLANE_DETECTION 72 + #cmakedefine XRT_FEATURE_OPENXR_USER_PRESENCE 72 73 #cmakedefine XRT_FEATURE_OPENXR_SPACE_LOCAL_FLOOR 73 74 #cmakedefine XRT_FEATURE_OPENXR_SPACE_UNBOUNDED 74 75 #cmakedefine XRT_FEATURE_OPENXR_VISIBILITY_MASK
+26
src/xrt/include/xrt/xrt_device.h
··· 256 256 bool position_tracking; 257 257 bool hand_tracking; 258 258 bool eye_gaze; 259 + bool presence; 259 260 bool force_feedback; 260 261 bool ref_space_usage; 261 262 bool form_factor_check; ··· 450 451 * @param[out] limits The returned limits. 451 452 */ 452 453 xrt_result_t (*get_output_limits)(struct xrt_device *xdev, struct xrt_output_limits *limits); 454 + 455 + /*! 456 + * @brief Get current presence status of the device. 457 + * 458 + * @param[in] xdev The device. 459 + * @param[out] presence The returned presence status. 460 + */ 461 + xrt_result_t (*get_presence)(struct xrt_device *xdev, bool *presence); 453 462 454 463 /*! 455 464 * Begin a plane detection request ··· 753 762 { 754 763 if (xdev->get_output_limits) { 755 764 return xdev->get_output_limits(xdev, limits); 765 + } else { 766 + return XRT_ERROR_NOT_IMPLEMENTED; 767 + } 768 + } 769 + 770 + /*! 771 + * Helper function for @ref xrt_device::get_presence. 772 + * 773 + * @copydoc xrt_device::get_presence 774 + * 775 + * @public @memberof xrt_device 776 + */ 777 + static inline xrt_result_t 778 + xrt_device_get_presence(struct xrt_device *xdev, bool *presence) 779 + { 780 + if (xdev->get_presence) { 781 + return xdev->get_presence(xdev, presence); 756 782 } else { 757 783 return XRT_ERROR_NOT_IMPLEMENTED; 758 784 }
+14 -1
src/xrt/include/xrt/xrt_session.h
··· 63 63 XRT_SESSION_EVENT_PASSTHRU_STATE_CHANGE = 8, 64 64 65 65 // ! The visibility mask of given view has changed 66 - XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE = 9 66 + XRT_SESSION_EVENT_VISIBILITY_MASK_CHANGE = 9, 67 + 68 + //! User presence has changed (hmd may have been put on or removed) 69 + XRT_SESSION_EVENT_USER_PRESENCE_CHANGE = 10, 67 70 }; 68 71 69 72 /*! ··· 177 180 }; 178 181 179 182 /*! 183 + * User presence changed event 184 + */ 185 + struct xrt_session_event_user_presence_change 186 + { 187 + enum xrt_session_event_type type; 188 + bool is_user_present; 189 + }; 190 + 191 + /*! 180 192 * Union of all session events, used to return multiple events through one call. 181 193 * Each event struct must start with a @ref xrt_session_event_type field. 182 194 * ··· 194 206 struct xrt_session_event_perf_change performance; 195 207 struct xrt_session_event_passthrough_state_change passthru; 196 208 struct xrt_session_event_visibility_mask_change mask_change; 209 + struct xrt_session_event_user_presence_change presence_change; 197 210 }; 198 211 199 212 /*!
+13
src/xrt/ipc/client/ipc_client_xdev.c
··· 128 128 } 129 129 130 130 static xrt_result_t 131 + ipc_client_xdev_get_presence(struct xrt_device *xdev, bool *presence) 132 + { 133 + struct ipc_client_xdev *icx = ipc_client_xdev(xdev); 134 + 135 + xrt_result_t xret = ipc_call_device_get_presence( // 136 + icx->ipc_c, // 137 + icx->device_id, // 138 + presence); // 139 + IPC_CHK_ALWAYS_RET(icx->ipc_c, xret, "ipc_call_device_get_presence"); 140 + } 141 + 142 + static xrt_result_t 131 143 ipc_client_xdev_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 132 144 { 133 145 struct ipc_client_xdev *icx = ipc_client_xdev(xdev); ··· 373 385 icx->base.get_face_tracking = ipc_client_xdev_get_face_tracking; 374 386 icx->base.get_body_skeleton = ipc_client_xdev_get_body_skeleton; 375 387 icx->base.get_body_joints = ipc_client_xdev_get_body_joints; 388 + icx->base.get_presence = ipc_client_xdev_get_presence; 376 389 icx->base.set_output = ipc_client_xdev_set_output; 377 390 icx->base.get_output_limits = ipc_client_xdev_get_output_limits; 378 391
+7
src/xrt/ipc/server/ipc_server_handler.c
··· 2238 2238 } 2239 2239 2240 2240 xrt_result_t 2241 + ipc_handle_device_get_presence(volatile struct ipc_client_state *ics, uint32_t id, bool *presence) 2242 + { 2243 + struct xrt_device *xdev = get_xdev(ics, id); 2244 + return xrt_device_get_presence(xdev, presence); 2245 + } 2246 + 2247 + xrt_result_t 2241 2248 ipc_handle_device_set_output(volatile struct ipc_client_state *ics, 2242 2249 uint32_t id, 2243 2250 enum xrt_output_name name,
+2 -2
src/xrt/ipc/shared/ipc_protocol.h
··· 139 139 struct xrt_device_supported supported; 140 140 }; 141 141 142 - static_assert(sizeof(struct ipc_shared_device) == 564, 142 + static_assert(sizeof(struct ipc_shared_device) == 568, 143 143 "invalid structure size, maybe different 32/64 bits sizes or padding"); 144 144 145 145 /*! ··· 291 291 struct xrt_plane_detector_begin_info_ext plane_begin_info_ext; 292 292 }; 293 293 294 - static_assert(sizeof(struct ipc_shared_memory) == 6499920, 294 + static_assert(sizeof(struct ipc_shared_memory) == 6500048, 295 295 "invalid structure size, maybe different 32/64 bits sizes or padding"); 296 296 297 297 /*!
+9
src/xrt/ipc/shared/proto.json
··· 505 505 ] 506 506 }, 507 507 508 + "device_get_presence": { 509 + "in": [ 510 + {"name": "id", "type": "uint32_t"} 511 + ], 512 + "out": [ 513 + {"name": "presence", "type": "bool"} 514 + ] 515 + }, 516 + 508 517 "device_set_output": { 509 518 "in": [ 510 519 {"name": "id", "type": "uint32_t"},
+19
src/xrt/state_trackers/oxr/oxr_event.c
··· 343 343 } 344 344 #endif // OXR_HAVE_KHR_visibility_mask 345 345 346 + #ifdef OXR_HAVE_EXT_user_presence 347 + XrResult 348 + oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent) 349 + { 350 + struct oxr_instance *inst = sess->sys->inst; 351 + XrEventDataUserPresenceChangedEXT *changed; 352 + struct oxr_event *event = NULL; 353 + 354 + ALLOC(log, inst, &event, &changed); 355 + changed->type = XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT; 356 + changed->session = oxr_session_to_openxr(sess); 357 + changed->isUserPresent = isUserPresent; 358 + event->result = XR_SUCCESS; 359 + lock(inst); 360 + push(inst, event); 361 + unlock(inst); 362 + } 363 + #endif // OXR_HAVE_EXT_user_presence 364 + 346 365 XrResult 347 366 oxr_event_remove_session_events(struct oxr_logger *log, struct oxr_session *sess) 348 367 {
+12
src/xrt/state_trackers/oxr/oxr_extension_support.h
··· 441 441 442 442 443 443 /* 444 + * XR_EXT_user_presence 445 + */ 446 + #if defined(XR_EXT_user_presence) && defined(XRT_FEATURE_OPENXR_USER_PRESENCE) 447 + #define OXR_HAVE_EXT_user_presence 448 + #define OXR_EXTENSION_SUPPORT_EXT_user_presence(_) _(EXT_user_presence, EXT_USER_PRESENCE) 449 + #else 450 + #define OXR_EXTENSION_SUPPORT_EXT_user_presence(_) 451 + #endif 452 + 453 + 454 + /* 444 455 * XR_BD_controller_interaction 445 456 */ 446 457 #if defined(XR_BD_controller_interaction) && defined(XRT_FEATURE_OPENXR_INTERACTION_BYTEDANCE) ··· 865 876 OXR_EXTENSION_SUPPORT_EXT_performance_settings(_) \ 866 877 OXR_EXTENSION_SUPPORT_EXT_plane_detection(_) \ 867 878 OXR_EXTENSION_SUPPORT_EXT_samsung_odyssey_controller(_) \ 879 + OXR_EXTENSION_SUPPORT_EXT_user_presence(_) \ 868 880 OXR_EXTENSION_SUPPORT_BD_controller_interaction(_) \ 869 881 OXR_EXTENSION_SUPPORT_FB_body_tracking(_) \ 870 882 OXR_EXTENSION_SUPPORT_FB_composition_layer_alpha_blend(_) \
+5
src/xrt/state_trackers/oxr/oxr_objects.h
··· 2910 2910 }; 2911 2911 #endif // OXR_HAVE_EXT_plane_detection 2912 2912 2913 + #ifdef OXR_HAVE_EXT_user_presence 2914 + XrResult 2915 + oxr_event_push_XrEventDataUserPresenceChangedEXT(struct oxr_logger *log, struct oxr_session *sess, bool isUserPresent); 2916 + #endif // OXR_HAVE_EXT_user_presence 2917 + 2913 2918 /*! 2914 2919 * @} 2915 2920 */
+16
src/xrt/state_trackers/oxr/oxr_session.c
··· 257 257 258 258 xrt_result_t xret = xrt_comp_begin_session(xc, &begin_session_info); 259 259 OXR_CHECK_XRET(log, sess, xret, xrt_comp_begin_session); 260 + 261 + #ifdef OXR_HAVE_EXT_user_presence 262 + struct xrt_device *xdev = GET_XDEV_BY_ROLE(sess->sys, head); 263 + if (extensions->EXT_user_presence && xdev->supported.presence) { 264 + bool presence = false; 265 + xret = xrt_device_get_presence(xdev, &presence); 266 + OXR_CHECK_XRET(log, sess, xret, xrt_device_get_presence); 267 + oxr_event_push_XrEventDataUserPresenceChangedEXT(log, sess, presence); 268 + } 269 + #endif 260 270 } else { 261 271 // Headless, pretend we got event from the compositor. 262 272 sess->compositor_visible = true; ··· 480 490 #ifdef OXR_HAVE_KHR_visibility_mask 481 491 oxr_event_push_XrEventDataVisibilityMaskChangedKHR(log, sess, sess->sys->view_config_type, 482 492 xse.mask_change.view_index); 493 + break; 483 494 #endif // OXR_HAVE_KHR_visibility_mask 495 + case XRT_SESSION_EVENT_USER_PRESENCE_CHANGE: 496 + #ifdef OXR_HAVE_EXT_user_presence 497 + oxr_event_push_XrEventDataUserPresenceChangedEXT(log, sess, 498 + xse.presence_change.is_user_present); 499 + #endif // OXR_HAVE_EXT_user_presence 484 500 break; 485 501 default: U_LOG_W("unhandled event type! %d", xse.type); break; 486 502 }
+12
src/xrt/state_trackers/oxr/oxr_system.c
··· 521 521 } 522 522 #endif // OXR_HAVE_EXT_plane_detection 523 523 524 + #ifdef OXR_HAVE_EXT_user_presence 525 + XrSystemUserPresencePropertiesEXT *user_presence_props = NULL; 526 + if (sys->inst->extensions.EXT_user_presence) { 527 + user_presence_props = OXR_GET_OUTPUT_FROM_CHAIN(properties, XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT, 528 + XrSystemUserPresencePropertiesEXT); 529 + } 530 + 531 + if (user_presence_props) { 532 + user_presence_props->supportsUserPresence = xdev->supported.presence; 533 + } 534 + #endif // OXR_HAVE_EXT_user_presence 535 + 524 536 #ifdef OXR_HAVE_META_body_tracking_full_body 525 537 XrSystemPropertiesBodyTrackingFullBodyMETA *full_body_tracking_meta_props = NULL; 526 538 if (sys->inst->extensions.META_body_tracking_full_body) {