Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(client_openxr): 🐛 Try fixing crash on Quest 2 related to multimodal #2654

Merged
merged 2 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions alvr/client_openxr/src/extra_extensions/eye_gaze_interaction.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
use openxr::{self as xr, sys};
use std::ptr;

fn get_props<G, T>(session: &xr::Session<G>, system: xr::SystemId, default_struct: T) -> Option<T> {
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<G>(session: &xr::Session<G>, system: xr::SystemId) -> bool {
if session.instance().exts().ext_eye_gaze_interaction.is_none() {
return false;
}

get_props(
super::get_props(
session,
system,
sys::SystemEyeGazeInteractionPropertiesEXT {
Expand Down
20 changes: 20 additions & 0 deletions alvr/client_openxr/src/extra_extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,23 @@ fn xr_res(result: sys::Result) -> xr::Result<()> {
Err(result)
}
}

fn get_props<G, T>(
session: &xr::Session<G>,
system: xr::SystemId,
default_struct: T,
) -> xr::Result<T> {
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(),
)
};

xr_res(result).map(|_| props)
}
182 changes: 117 additions & 65 deletions alvr/client_openxr/src/extra_extensions/multimodal_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,87 +12,139 @@ pub const META_SIMULTANEOUS_HANDS_AND_CONTROLLERS_EXTENSION_NAME: &str =
"XR_META_simultaneous_hands_and_controllers";
pub const META_DETACHED_CONTROLLERS_EXTENSION_NAME: &str = "XR_META_detached_controllers";

static TYPE_SYSTEM_SIMULTANEOUS_HANDS_AND_CONTROLLERS_PROPERTIES_META: Lazy<xr::StructureType> =
Lazy::new(|| xr::StructureType::from_raw(1000532001));
static TYPE_SIMULTANEOUS_HANDS_AND_CONTROLLERS_TRACKING_RESUME_INFO_META: Lazy<xr::StructureType> =
Lazy::new(|| xr::StructureType::from_raw(1000532002));
static TYPE_SIMULTANEOUS_HANDS_AND_CONTROLLERS_TRACKING_PAUSE_INFO_META: Lazy<xr::StructureType> =
Lazy::new(|| xr::StructureType::from_raw(1000532003));

#[repr(C)]
pub struct SimultaneousHandsAndControllersTrackingResumeInfoMETA {
struct SystemSymultaneousHandsAndControllersPropertiesMETA {
ty: xr::StructureType,
next: *const c_void,
supports_simultaneous_hands_and_controllers: sys::Bool32,
}

#[repr(C)]
struct SimultaneousHandsAndControllersTrackingResumeInfoMETA {
ty: xr::StructureType,
next: *const c_void,
}
#[repr(C)]
pub struct SimultaneousHandsAndControllersTrackingPauseInfoMETA {
struct SimultaneousHandsAndControllersTrackingPauseInfoMETA {
ty: xr::StructureType,
next: *const c_void,
}

pub type ResumeSimultaneousHandsAndControllersTrackingMETA =
unsafe extern "system" fn(
sys::Session,
*const SimultaneousHandsAndControllersTrackingResumeInfoMETA,
) -> sys::Result;
pub type PauseSimultaneousHandsAndControllersTrackingMETA =
unsafe extern "system" fn(
sys::Session,
*const SimultaneousHandsAndControllersTrackingPauseInfoMETA,
) -> sys::Result;

pub fn resume_simultaneous_hands_and_controllers_tracking_meta<G>(
session: &xr::Session<G>,
) -> xr::Result<()> {
let resume_simultaneous_hands_and_controllers_tracking_meta = unsafe {
let mut resume_simultaneous_hands_and_controllers_tracking_meta = None;
let _ = (session.instance().fp().get_instance_proc_addr)(
session.instance().as_raw(),
c"xrResumeSimultaneousHandsAndControllersTrackingMETA".as_ptr(),
&mut resume_simultaneous_hands_and_controllers_tracking_meta,
);

resume_simultaneous_hands_and_controllers_tracking_meta.map(|pfn| {
mem::transmute::<VoidFunction, ResumeSimultaneousHandsAndControllersTrackingMETA>(pfn)
})
}
.ok_or(sys::Result::ERROR_EXTENSION_NOT_PRESENT)?;

let resume_info = SimultaneousHandsAndControllersTrackingResumeInfoMETA {
ty: *TYPE_SIMULTANEOUS_HANDS_AND_CONTROLLERS_TRACKING_RESUME_INFO_META,
next: ptr::null(),
};
unsafe {
super::xr_res(resume_simultaneous_hands_and_controllers_tracking_meta(
session.as_raw(),
&resume_info,
))
}
type ResumeSimultaneousHandsAndControllersTrackingMETA = unsafe extern "system" fn(
sys::Session,
*const SimultaneousHandsAndControllersTrackingResumeInfoMETA,
) -> sys::Result;
type PauseSimultaneousHandsAndControllersTrackingMETA = unsafe extern "system" fn(
sys::Session,
*const SimultaneousHandsAndControllersTrackingPauseInfoMETA,
) -> sys::Result;

pub struct MultimodalMeta {
session: xr::Session<xr::AnyGraphics>,
resume_simultaneous_hands_and_controllers_tracking_meta:
ResumeSimultaneousHandsAndControllersTrackingMETA,
pause_simultaneous_hands_and_controllers_tracking_meta:
PauseSimultaneousHandsAndControllersTrackingMETA,
}

pub fn pause_simultaneous_hands_and_controllers_tracking_meta<G>(
session: &xr::Session<G>,
) -> xr::Result<()> {
let pause_simultaneous_hands_and_controllers_tracking_meta = unsafe {
let mut pause_simultaneous_hands_and_controllers_tracking_meta = None;
let _ = (session.instance().fp().get_instance_proc_addr)(
session.instance().as_raw(),
c"xrPauseSimultaneousHandsAndControllersTrackingMETA".as_ptr(),
&mut pause_simultaneous_hands_and_controllers_tracking_meta,
);

pause_simultaneous_hands_and_controllers_tracking_meta.map(|pfn| {
mem::transmute::<VoidFunction, PauseSimultaneousHandsAndControllersTrackingMETA>(pfn)
})
impl MultimodalMeta {
pub fn new<G>(
session: xr::Session<G>,
extra_extensions: &[String],
system: xr::SystemId,
) -> xr::Result<Self> {
if !extra_extensions
.contains(&META_SIMULTANEOUS_HANDS_AND_CONTROLLERS_EXTENSION_NAME.to_owned())
|| !extra_extensions.contains(&META_DETACHED_CONTROLLERS_EXTENSION_NAME.to_owned())
{
return Err(sys::Result::ERROR_EXTENSION_NOT_PRESENT);
}

let resume_simultaneous_hands_and_controllers_tracking_meta = unsafe {
let mut resume_simultaneous_hands_and_controllers_tracking_meta = None;
let _ = (session.instance().fp().get_instance_proc_addr)(
session.instance().as_raw(),
c"xrResumeSimultaneousHandsAndControllersTrackingMETA".as_ptr(),
&mut resume_simultaneous_hands_and_controllers_tracking_meta,
);

resume_simultaneous_hands_and_controllers_tracking_meta.map(|pfn| {
mem::transmute::<VoidFunction, ResumeSimultaneousHandsAndControllersTrackingMETA>(
pfn,
)
})
}
.ok_or(sys::Result::ERROR_EXTENSION_NOT_PRESENT)?;

let pause_simultaneous_hands_and_controllers_tracking_meta = unsafe {
let mut pause_simultaneous_hands_and_controllers_tracking_meta = None;
let _ = (session.instance().fp().get_instance_proc_addr)(
session.instance().as_raw(),
c"xrPauseSimultaneousHandsAndControllersTrackingMETA".as_ptr(),
&mut pause_simultaneous_hands_and_controllers_tracking_meta,
);

pause_simultaneous_hands_and_controllers_tracking_meta.map(|pfn| {
mem::transmute::<VoidFunction, PauseSimultaneousHandsAndControllersTrackingMETA>(
pfn,
)
})
}
.ok_or(sys::Result::ERROR_EXTENSION_NOT_PRESENT)?;

let props = super::get_props(
&session,
system,
SystemSymultaneousHandsAndControllersPropertiesMETA {
ty: *TYPE_SYSTEM_SIMULTANEOUS_HANDS_AND_CONTROLLERS_PROPERTIES_META,
next: std::ptr::null(),
supports_simultaneous_hands_and_controllers: xr::sys::FALSE,
},
)?;

if props.supports_simultaneous_hands_and_controllers.into() {
Ok(Self {
session: session.into_any_graphics(),
resume_simultaneous_hands_and_controllers_tracking_meta,
pause_simultaneous_hands_and_controllers_tracking_meta,
})
} else {
Err(sys::Result::ERROR_FEATURE_UNSUPPORTED)
}
}

pub fn resume(&self) -> xr::Result<()> {
let resume_info = SimultaneousHandsAndControllersTrackingResumeInfoMETA {
ty: *TYPE_SIMULTANEOUS_HANDS_AND_CONTROLLERS_TRACKING_RESUME_INFO_META,
next: ptr::null(),
};
unsafe {
super::xr_res((self
.resume_simultaneous_hands_and_controllers_tracking_meta)(
self.session.as_raw(),
&resume_info,
))
}
}
.ok_or(sys::Result::ERROR_EXTENSION_NOT_PRESENT)?;

let pause_info = SimultaneousHandsAndControllersTrackingPauseInfoMETA {
ty: *TYPE_SIMULTANEOUS_HANDS_AND_CONTROLLERS_TRACKING_PAUSE_INFO_META,
next: ptr::null(),
};
unsafe {
super::xr_res(pause_simultaneous_hands_and_controllers_tracking_meta(
session.as_raw(),
&pause_info,
))

pub fn pause(&self) -> xr::Result<()> {
let pause_info = SimultaneousHandsAndControllersTrackingPauseInfoMETA {
ty: *TYPE_SIMULTANEOUS_HANDS_AND_CONTROLLERS_TRACKING_PAUSE_INFO_META,
next: ptr::null(),
};
unsafe {
super::xr_res((self
.pause_simultaneous_hands_and_controllers_tracking_meta)(
self.session.as_raw(),
&pause_info,
))
}
}
}
31 changes: 18 additions & 13 deletions alvr/client_openxr/src/interaction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
extra_extensions::{
self, BodyTrackerFB, EyeTrackerSocial, FaceTracker2FB, FacialTrackerHTC,
self, BodyTrackerFB, EyeTrackerSocial, FaceTracker2FB, FacialTrackerHTC, MultimodalMeta,
BODY_JOINT_SET_FULL_BODY_META, FULL_BODY_JOINT_COUNT_META,
FULL_BODY_JOINT_LEFT_FOOT_BALL_META, FULL_BODY_JOINT_LEFT_LOWER_LEG_META,
FULL_BODY_JOINT_RIGHT_FOOT_BALL_META, FULL_BODY_JOINT_RIGHT_LOWER_LEG_META,
Expand Down Expand Up @@ -108,6 +108,7 @@ pub struct InteractionContext {
pub action_set: xr::ActionSet,
pub button_actions: HashMap<u64, ButtonAction>,
pub hands_interaction: [HandInteraction; 2],
multimodal_handle: Option<MultimodalMeta>,
pub multimodal_hands_enabled: bool,
pub face_sources: FaceSources,
pub body_sources: BodySources,
Expand All @@ -116,9 +117,9 @@ pub struct InteractionContext {
impl InteractionContext {
pub fn new(
xr_session: xr::Session<xr::OpenGlEs>,
extra_extensions: &[String],
xr_system: xr::SystemId,
platform: Platform,
supports_multimodal: bool,
) -> Self {
let xr_instance = xr_session.instance();

Expand Down Expand Up @@ -229,9 +230,13 @@ impl InteractionContext {
"/user/hand/right/output/haptic",
));

let multimodal_handle = create_ext_object("MultimodalMeta", Some(true), || {
MultimodalMeta::new(xr_session.clone(), extra_extensions, xr_system)
});

let left_detached_controller_pose_action;
let right_detached_controller_pose_action;
if supports_multimodal {
if multimodal_handle.is_some() {
// Note: when multimodal input is enabled, both controllers and hands will always be active.
// To be able to detect when controllers are actually held, we have to register detached
// controllers pose; the controller pose will be diverted to the detached controllers when
Expand Down Expand Up @@ -355,6 +360,7 @@ impl InteractionContext {
skeleton_tracker: right_hand_tracker,
},
],
multimodal_handle,
multimodal_hands_enabled: false,
face_sources: FaceSources {
combined_eyes_source,
Expand All @@ -371,8 +377,9 @@ impl InteractionContext {

pub fn select_sources(&mut self, config: &InteractionSourcesConfig) {
// First of all, disable/delete all sources. This ensures there are no conflicts
extra_extensions::pause_simultaneous_hands_and_controllers_tracking_meta(&self.xr_session)
.ok();
if let Some(handle) = &mut self.multimodal_handle {
handle.pause().ok();
}
self.multimodal_hands_enabled = false;
self.face_sources.eye_tracker_fb = None;
self.face_sources.face_tracker_fb = None;
Expand Down Expand Up @@ -407,14 +414,12 @@ impl InteractionContext {

// Note: We cannot enable multimodal if fb body tracking is active. It would result in a
// ERROR_RUNTIME_FAILURE crash.
if config.body_tracking.is_none()
&& config.prefers_multimodal_input
&& extra_extensions::resume_simultaneous_hands_and_controllers_tracking_meta(
&self.xr_session,
)
.is_ok()
{
self.multimodal_hands_enabled = true;
if config.body_tracking.is_none() && config.prefers_multimodal_input {
if let Some(handle) = &mut self.multimodal_handle {
if handle.resume().is_ok() {
self.multimodal_hands_enabled = true;
}
}
}

self.face_sources.eye_tracker_fb = create_ext_object(
Expand Down
3 changes: 1 addition & 2 deletions alvr/client_openxr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,9 @@ pub fn entry_point() {

let interaction_context = Arc::new(RwLock::new(InteractionContext::new(
xr_session.clone(),
&exts.other,
xr_system,
platform,
exts.other
.contains(&META_SIMULTANEOUS_HANDS_AND_CONTROLLERS_EXTENSION_NAME.to_owned()),
)));

let mut lobby = Lobby::new(
Expand Down
Loading