Working passthrough for Meta Quest 3 (#66)

* Window is None

* Builds but check manifest

* debug prints

* Started, not passing last "cvt"

* Passthrough works, bevy not visible

* Passthrough working

* Passthrough working

* Working passthrough
This commit is contained in:
Rasmus Hogslätt
2024-02-01 05:05:24 +01:00
committed by GitHub
parent 53af86b073
commit 71a08798ef
9 changed files with 398 additions and 137 deletions

179
src/passthrough.rs Normal file
View File

@@ -0,0 +1,179 @@
use bevy::prelude::*;
use std::{marker::PhantomData, mem, ptr};
use crate::xr_init::XrRenderData;
use openxr as xr;
use xr::{
sys::{
PassthroughCreateInfoFB, PassthroughFB, PassthroughLayerFB, Space,
SystemPassthroughProperties2FB,
},
CompositionLayerBase, CompositionLayerFlags, Graphics, PassthroughCapabilityFlagsFB,
};
use crate::resources::XrInstance;
use crate::resources::XrSession;
pub struct PassthroughLayer(pub xr::sys::PassthroughLayerFB);
pub struct Passthrough(pub xr::sys::PassthroughFB);
fn cvt(x: xr::sys::Result) -> xr::Result<xr::sys::Result> {
if x.into_raw() >= 0 {
Ok(x)
} else {
Err(x)
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub(crate) struct CompositionLayerPassthrough<'a, G: xr::Graphics> {
inner: xr::sys::CompositionLayerPassthroughFB,
_marker: PhantomData<&'a G>,
}
impl<'a, G: Graphics> std::ops::Deref for CompositionLayerPassthrough<'a, G> {
type Target = CompositionLayerBase<'a, G>;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(&self.inner) }
}
}
impl<'a, G: xr::Graphics> CompositionLayerPassthrough<'a, G> {
pub(crate) fn from_xr_passthrough_layer(layer: &PassthroughLayer) -> Self {
Self {
inner: xr::sys::CompositionLayerPassthroughFB {
ty: xr::sys::CompositionLayerPassthroughFB::TYPE,
next: ptr::null(),
flags: CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA,
space: Space::NULL,
layer_handle: layer.0,
},
_marker: PhantomData,
}
}
}
#[inline]
pub fn supports_passthrough(instance: &XrInstance, system: xr::SystemId) -> xr::Result<bool> {
unsafe {
let mut hand = xr::sys::SystemPassthroughProperties2FB {
ty: SystemPassthroughProperties2FB::TYPE,
next: ptr::null(),
capabilities: PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
};
let mut p = xr::sys::SystemProperties::out(&mut hand as *mut _ as _);
cvt((instance.fp().get_system_properties)(
instance.as_raw(),
system,
p.as_mut_ptr(),
))?;
bevy::log::info!(
"From supports_passthrough: Passthrough capabilities: {:?}",
hand.capabilities
);
Ok(
(hand.capabilities & PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY)
== PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
)
}
}
#[inline]
pub fn start_passthrough(
instance: &XrInstance,
xr_session: &XrSession,
) -> xr::Result<(xr::sys::PassthroughFB, xr::sys::PassthroughLayerFB)> {
unsafe {
// Create feature
let mut passthrough_feature = xr::sys::PassthroughFB::NULL;
let mut passthrough_create_info = xr::sys::PassthroughCreateInfoFB {
ty: xr::sys::StructureType::PASSTHROUGH_CREATE_INFO_FB, // XR_TYPE_PASSTHROUGH_CREATE_INFO_FB
next: ptr::null(),
flags: xr::sys::PassthroughFlagsFB::IS_RUNNING_AT_CREATION,
};
// bevy::log::info!("xr_session.as_raw(): {:?}", xr_session.as_raw());
// bevy::log::info!("&passthrough_create_info: {:?}", &passthrough_create_info);
// bevy::log::info!("&mut passthrough_feature: {:?}", &mut passthrough_feature);
// bevy::log::info!(
// "instance.exts().fb_passthrough.unwrap(): {:?}",
// instance.exts().fb_passthrough.is_some()
// );
cvt(
(instance.exts().fb_passthrough.unwrap().create_passthrough)(
xr_session.as_raw(),
&passthrough_create_info as *const _,
&mut passthrough_feature as *mut _,
),
)?;
// bevy::log::info!("Created passthrough feature");
// Create layer
let mut passthrough_layer = xr::sys::PassthroughLayerFB::NULL;
let mut layer_create_info: xr::sys::PassthroughLayerCreateInfoFB =
xr::sys::PassthroughLayerCreateInfoFB {
ty: xr::sys::StructureType::PASSTHROUGH_LAYER_CREATE_INFO_FB, // XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB
next: ptr::null(),
passthrough: passthrough_feature, // XR_PASSTHROUGH_HANDLE
flags: xr::sys::PassthroughFlagsFB::IS_RUNNING_AT_CREATION, // XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB
purpose: xr::sys::PassthroughLayerPurposeFB::RECONSTRUCTION, // XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB
};
cvt((instance
.exts()
.fb_passthrough
.unwrap()
.create_passthrough_layer)(
xr_session.as_raw(),
&layer_create_info as *const _,
&mut passthrough_layer as *mut _,
))?;
// bevy::log::info!("Created passthrough layer");
// // Start layer
// bevy::log::info!("passthrough_feature: {:?}", passthrough_feature);
// // cvt((instance.exts().fb_passthrough.unwrap().passthrough_start)(
// // passthrough_feature,
// // ))?;
// bevy::log::info!("Started passthrough layer");
// bevy::log::info!("Passed everything in start");
Ok((passthrough_feature, passthrough_layer))
}
}
#[inline]
pub fn passthrough_layer_resume(mut xr_data_resource: ResMut<XrRenderData>) -> xr::Result<()> {
unsafe {
let passthrough_layer = &xr_data_resource.xr_passthrough_layer;
{
let passthrough_layer_locked = passthrough_layer.lock().unwrap();
cvt((xr_data_resource
.xr_instance
.exts()
.fb_passthrough
.unwrap()
.passthrough_layer_resume)(
*passthrough_layer_locked
))?;
}
xr_data_resource.xr_passthrough_active = true;
bevy::log::info!("Resumed passthrough layer");
Ok(())
}
}
#[inline]
pub fn passthrough_layer_pause(mut xr_data_resource: ResMut<XrRenderData>) -> xr::Result<()> {
unsafe {
let passthrough_layer = &xr_data_resource.xr_passthrough_layer;
{
let passthrough_layer_locked = passthrough_layer.lock().unwrap();
cvt((xr_data_resource
.xr_instance
.exts()
.fb_passthrough
.unwrap()
.passthrough_layer_pause)(
*passthrough_layer_locked
))?;
}
xr_data_resource.xr_passthrough_active = false;
bevy::log::info!("Paused passthrough layer");
Ok(())
}
}