From 0b448f156daaec1a902f14293489948377fd563b Mon Sep 17 00:00:00 2001 From: zmerp Date: Wed, 15 Jan 2025 17:02:13 +0100 Subject: [PATCH] fix(client_openxr): :bug: Fix crash on unsupported eye tracking permission on Pico (#2618) --- .../extra_extensions/eye_gaze_interaction.rs | 35 +++++++++++++++++++ .../client_openxr/src/extra_extensions/mod.rs | 2 ++ alvr/client_openxr/src/interaction.rs | 9 +++-- alvr/client_openxr/src/lib.rs | 1 + 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 alvr/client_openxr/src/extra_extensions/eye_gaze_interaction.rs diff --git a/alvr/client_openxr/src/extra_extensions/eye_gaze_interaction.rs b/alvr/client_openxr/src/extra_extensions/eye_gaze_interaction.rs new file mode 100644 index 0000000000..cb1798509f --- /dev/null +++ b/alvr/client_openxr/src/extra_extensions/eye_gaze_interaction.rs @@ -0,0 +1,35 @@ +use openxr::{self as xr, sys}; +use std::ptr; + +fn get_props(session: &xr::Session, system: xr::SystemId, default_struct: T) -> Option { + let instance = session.instance(); + + let mut props = default_struct; + let mut system_properties = sys::SystemProperties::out((&mut props as *mut T).cast()); + let result = unsafe { + (instance.fp().get_system_properties)( + instance.as_raw(), + system, + system_properties.as_mut_ptr(), + ) + }; + (result.into_raw() >= 0).then_some(props) +} + +pub fn supports_eye_gaze_interaction(session: &xr::Session, system: xr::SystemId) -> bool { + if session.instance().exts().ext_eye_gaze_interaction.is_none() { + return false; + } + + get_props( + session, + system, + sys::SystemEyeGazeInteractionPropertiesEXT { + ty: sys::SystemEyeGazeInteractionPropertiesEXT::TYPE, + next: ptr::null_mut(), + supports_eye_gaze_interaction: sys::FALSE, + }, + ) + .map(|props| props.supports_eye_gaze_interaction.into()) + .unwrap_or(false) +} diff --git a/alvr/client_openxr/src/extra_extensions/mod.rs b/alvr/client_openxr/src/extra_extensions/mod.rs index 6d4a07bee1..0f08f9f709 100644 --- a/alvr/client_openxr/src/extra_extensions/mod.rs +++ b/alvr/client_openxr/src/extra_extensions/mod.rs @@ -1,4 +1,5 @@ mod body_tracking_fb; +mod eye_gaze_interaction; mod eye_tracking_social; mod face_tracking2_fb; mod facial_tracking_htc; @@ -7,6 +8,7 @@ mod passthrough_fb; mod passthrough_htc; pub use body_tracking_fb::*; +pub use eye_gaze_interaction::*; pub use eye_tracking_social::*; pub use face_tracking2_fb::*; pub use facial_tracking_htc::*; diff --git a/alvr/client_openxr/src/interaction.rs b/alvr/client_openxr/src/interaction.rs index 72102f96e0..de4177f03d 100644 --- a/alvr/client_openxr/src/interaction.rs +++ b/alvr/client_openxr/src/interaction.rs @@ -116,6 +116,7 @@ pub struct InteractionContext { impl InteractionContext { pub fn new( xr_session: xr::Session, + xr_system: xr::SystemId, platform: Platform, supports_multimodal: bool, ) -> Self { @@ -270,9 +271,13 @@ impl InteractionContext { ) .unwrap(); - let combined_eyes_source = if xr_instance.exts().ext_eye_gaze_interaction.is_some() - && !platform.is_quest() + // Pico headsets require calling get_system_properties to test for extensions, because all + // extensions function pointers are available even if the feature is not supported by the + // hardware. The full checks are done in supports_eye_gaze_interaction. This is required + // to avoid a crash when requesting the EYE_TRACKING permission. + let combined_eyes_source = if !platform.is_quest() && !platform.is_vive() + && extra_extensions::supports_eye_gaze_interaction(&xr_session, xr_system) { #[cfg(target_os = "android")] if platform.is_pico() { diff --git a/alvr/client_openxr/src/lib.rs b/alvr/client_openxr/src/lib.rs index 639e1cd5f4..b176b99d63 100644 --- a/alvr/client_openxr/src/lib.rs +++ b/alvr/client_openxr/src/lib.rs @@ -267,6 +267,7 @@ pub fn entry_point() { let interaction_context = Arc::new(RwLock::new(InteractionContext::new( xr_session.clone(), + xr_system, platform, exts.other .contains(&META_SIMULTANEOUS_HANDS_AND_CONTROLLERS_EXTENSION_NAME.to_owned()),