diff --git a/Cargo.toml b/Cargo.toml index 3835e21..bf88e48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ wgpu-hal = "0.16.0" [dev-dependencies] bevy = { git = "https://github.com/awtterpip/bevy" } +color-eyre = "0.6.2" [[example]] name = "xr" diff --git a/examples/xr.rs b/examples/xr.rs index 1bac15f..ca99a3c 100644 --- a/examples/xr.rs +++ b/examples/xr.rs @@ -1,170 +1,402 @@ -//! A simple 3D scene with light shining over a cube sitting on a plane. -use bevy_openxr::{DefaultXrPlugins, LEFT_XR_TEXTURE_HANDLE, RIGHT_XR_TEXTURE_HANDLE}; +use bevy::core_pipeline::core_3d; +use bevy::core_pipeline::tonemapping::{DebandDither, Tonemapping}; +use bevy::ecs::prelude::{Bundle, Component, ReflectComponent}; + +use bevy::math::Mat4; +use bevy::prelude::Camera3d; +use bevy::reflect::{std_traits::ReflectDefault, Reflect}; +use bevy::render::view::ColorGrading; +use bevy::render::{ + camera::{Camera, CameraProjection, CameraRenderGraph}, + primitives::Frustum, + view::VisibleEntities, +}; +use bevy::transform::components::{GlobalTransform, Transform}; +// mostly copied from https://github.com/blaind/bevy_openxr/tree/main/crates/bevy_openxr/src/render_graph/camera +use openxr::Fovf; + +#[derive(Bundle)] +pub struct XrCameraBundle { + pub camera: Camera, + pub camera_render_graph: CameraRenderGraph, + pub xr_projection: XRProjection, + pub visible_entities: VisibleEntities, + pub frustum: Frustum, + pub transform: Transform, + pub global_transform: GlobalTransform, + pub camera_3d: Camera3d, + pub tonemapping: Tonemapping, + pub dither: DebandDither, + pub color_grading: ColorGrading, +} + +// NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference +impl Default for XrCameraBundle { + fn default() -> Self { + Self { + camera_render_graph: CameraRenderGraph::new(core_3d::graph::NAME), + camera: Default::default(), + xr_projection: Default::default(), + visible_entities: Default::default(), + frustum: Default::default(), + transform: Default::default(), + global_transform: Default::default(), + camera_3d: Default::default(), + tonemapping: Default::default(), + dither: DebandDither::Enabled, + color_grading: ColorGrading::default(), + } + } +} + +#[derive(Debug, Clone, Component, Reflect)] +#[reflect(Component, Default)] +pub struct XRProjection { + pub near: f32, + pub far: f32, + #[reflect(ignore)] + pub fov: Fovf, +} + +impl Default for XRProjection { + fn default() -> Self { + Self { + near: 0.1, + far: 1000., + fov: Default::default(), + } + } +} + +impl XRProjection { + pub fn new(near: f32, far: f32, fov: Fovf) -> Self { + XRProjection { near, far, fov } + } +} + +impl CameraProjection for XRProjection { + // ============================================================================= + // math code adapted from + // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/common/xr_linear.h + // Copyright (c) 2017 The Khronos Group Inc. + // Copyright (c) 2016 Oculus VR, LLC. + // SPDX-License-Identifier: Apache-2.0 + // ============================================================================= + fn get_projection_matrix(&self) -> Mat4 { + // symmetric perspective for debugging + // let x_fov = (self.fov.angle_left.abs() + self.fov.angle_right.abs()); + // let y_fov = (self.fov.angle_up.abs() + self.fov.angle_down.abs()); + // return Mat4::perspective_infinite_reverse_rh(y_fov, x_fov / y_fov, self.near); + + let fov = self.fov; + let is_vulkan_api = false; // FIXME wgpu probably abstracts this + let near_z = self.near; + let far_z = -1.; // use infinite proj + // let far_z = self.far; + + let tan_angle_left = fov.angle_left.tan(); + let tan_angle_right = fov.angle_right.tan(); + + let tan_angle_down = fov.angle_down.tan(); + let tan_angle_up = fov.angle_up.tan(); + + let tan_angle_width = tan_angle_right - tan_angle_left; + + // Set to tanAngleDown - tanAngleUp for a clip space with positive Y + // down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with + // positive Y up (OpenGL / D3D / Metal). + // const float tanAngleHeight = + // graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown); + let tan_angle_height = if is_vulkan_api { + tan_angle_down - tan_angle_up + } else { + tan_angle_up - tan_angle_down + }; + + // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). + // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). + // const float offsetZ = + // (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0; + // FIXME handle enum of graphics apis + let offset_z = 0.; + + let mut cols: [f32; 16] = [0.0; 16]; + + if far_z <= near_z { + // place the far plane at infinity + cols[0] = 2. / tan_angle_width; + cols[4] = 0.; + cols[8] = (tan_angle_right + tan_angle_left) / tan_angle_width; + cols[12] = 0.; + + cols[1] = 0.; + cols[5] = 2. / tan_angle_height; + cols[9] = (tan_angle_up + tan_angle_down) / tan_angle_height; + cols[13] = 0.; + + cols[2] = 0.; + cols[6] = 0.; + cols[10] = -1.; + cols[14] = -(near_z + offset_z); + + cols[3] = 0.; + cols[7] = 0.; + cols[11] = -1.; + cols[15] = 0.; + + // bevy uses the _reverse_ infinite projection + // https://dev.theomader.com/depth-precision/ + let z_reversal = Mat4::from_cols_array_2d(&[ + [1f32, 0., 0., 0.], + [0., 1., 0., 0.], + [0., 0., -1., 0.], + [0., 0., 1., 1.], + ]); + + return z_reversal * Mat4::from_cols_array(&cols); + } else { + // normal projection + cols[0] = 2. / tan_angle_width; + cols[4] = 0.; + cols[8] = (tan_angle_right + tan_angle_left) / tan_angle_width; + cols[12] = 0.; + + cols[1] = 0.; + cols[5] = 2. / tan_angle_height; + cols[9] = (tan_angle_up + tan_angle_down) / tan_angle_height; + cols[13] = 0.; + + cols[2] = 0.; + cols[6] = 0.; + cols[10] = -(far_z + offset_z) / (far_z - near_z); + cols[14] = -(far_z * (near_z + offset_z)) / (far_z - near_z); + + cols[3] = 0.; + cols[7] = 0.; + cols[11] = -1.; + cols[15] = 0.; + } + + Mat4::from_cols_array(&cols) + } + + fn update(&mut self, _width: f32, _height: f32) {} + + fn far(&self) -> f32 { + self.far + } +} + +use bevy::render::camera::CameraProjectionPlugin; +use bevy::render::view::{update_frusta, VisibilitySystems}; +use bevy::transform::TransformSystem; use bevy::{prelude::*, render::camera::RenderTarget}; -use bevy::prelude::Component; -use bevy::render::camera::Viewport; use bevy_openxr::input::XrInput; -use bevy_openxr::resources::{XrInstance, XrSession, XrViews}; +use bevy_openxr::resources::{XrFrameState, XrSession, XrViews}; +use bevy_openxr::{DefaultXrPlugins, LEFT_XR_TEXTURE_HANDLE, RIGHT_XR_TEXTURE_HANDLE}; +use openxr::ActiveActionSet; fn main() { - App::new() - .add_plugins(DefaultXrPlugins) - .add_systems(Startup, setup) - .add_systems(Update, head_movement) - .run(); + color_eyre::install().unwrap(); + + info!("Running `openxr-6dof` skill"); + App::new() + .add_plugins(DefaultXrPlugins) + .add_plugins(CameraProjectionPlugin::::default()) + .add_systems(Startup, setup) + .add_systems(PreUpdate, head_movement) + .add_systems(PreUpdate, hands) + .add_systems( + PostUpdate, + update_frusta:: + .after(TransformSystem::TransformPropagate) + .before(VisibilitySystems::UpdatePerspectiveFrusta), + ) + .run(); } #[derive(Component)] enum CameraType { - Left, - Right, - Middle, + Left, + Right, + Middle, } - /// set up a simple 3D scene fn setup( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, ) { - // plane - commands.spawn(PbrBundle { - mesh: meshes.add(shape::Plane::from_size(5.0).into()), - material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), - ..default() - }); - // cube - commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), - material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), - transform: Transform::from_xyz(0.0, 0.5, 0.0), - ..default() - }); - // light - commands.spawn(PointLightBundle { - point_light: PointLight { - intensity: 1500.0, - shadows_enabled: true, - ..default() - }, - transform: Transform::from_xyz(4.0, 8.0, 4.0), - ..default() - }); - // camera - commands.spawn((Camera3dBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }, CameraType::Middle)); + // plane + commands.spawn(PbrBundle { + mesh: meshes.add(shape::Plane::from_size(5.0).into()), + material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + ..default() + }); + // cube + commands.spawn(PbrBundle { + mesh: meshes.add(Mesh::from(shape::Cube { size: 0.1 })), + material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), + transform: Transform::from_xyz(0.0, 0.5, 0.0), + ..default() + }); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); + // camera + commands.spawn(( + Camera3dBundle { + transform: Transform::from_xyz(-2.0, 2.5, 5.0) + .looking_at(Vec3::ZERO, Vec3::Y), + ..default() + }, + CameraType::Middle, + )); - // let viewport = Viewport{ - // physical_position: Default::default(), - // physical_size: UVec2::splat(2000), - // depth: 0.0..1.0, - // }; - - commands.spawn((Camera3dBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - camera: Camera { - order: -1, - target: RenderTarget::TextureView(LEFT_XR_TEXTURE_HANDLE), - viewport: None, - ..default() - }, - ..default() - }, CameraType::Left)); - commands.spawn((Camera3dBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - camera: Camera { - order: -1, - target: RenderTarget::TextureView(RIGHT_XR_TEXTURE_HANDLE), - viewport: None, - ..default() - }, - ..default() - }, CameraType::Right)); + commands.spawn(( + XrCameraBundle { + transform: Transform::from_xyz(-2.0, 2.5, 5.0) + .looking_at(Vec3::ZERO, Vec3::Y), + camera: Camera { + order: -1, + target: RenderTarget::TextureView(LEFT_XR_TEXTURE_HANDLE), + viewport: None, + ..default() + }, + ..default() + }, + CameraType::Left, + )); + commands.spawn(( + XrCameraBundle { + transform: Transform::from_xyz(-2.0, 2.5, 5.0) + .looking_at(Vec3::ZERO, Vec3::Y), + camera: Camera { + order: -1, + target: RenderTarget::TextureView(RIGHT_XR_TEXTURE_HANDLE), + viewport: None, + ..default() + }, + ..default() + }, + CameraType::Right, + )); } -fn head_movement(views: ResMut, mut query: Query<(&mut Transform, &Camera, &CameraType)>) { - let views = views.lock().unwrap(); - let mut f = || -> Option<()> { - let midpoint = (views.get(0)?.pose.position.to_vec3() - + views.get(1)?.pose.position.to_vec3()) - / 2.; - for (mut t, _, camera_type) in query.iter_mut() { - match camera_type { - CameraType::Left => { - t.translation = views.get(0)?.pose.position.to_vec3() - }, - CameraType::Right => { - t.translation = views.get(1)?.pose.position.to_vec3() - }, - CameraType::Middle => { - t.translation = midpoint; - }, - } - } - let left_rot = views.get(0).unwrap().pose.orientation.to_quat(); - let right_rot = views.get(1).unwrap().pose.orientation.to_quat(); - let mid_rot = if left_rot.dot(right_rot) >= 0. { - left_rot.slerp(right_rot, 0.5) - } else { - right_rot.slerp(left_rot, 0.5) - }; - for (mut t, _, camera_type) in query.iter_mut() { - match camera_type { - CameraType::Left => { - t.rotation = left_rot - }, - CameraType::Right => { - t.rotation = right_rot - }, - CameraType::Middle => { - t.rotation = mid_rot; - }, - } - } +fn hands( + mut gizmos: Gizmos, + xr_input: Res, + session: Res, + frame_state: Res, +) { + //let pose = xr_input.left_action.create_space(Session::clone(&session), Path, Posef::IDENTITY).unwrap(); + let act = ActiveActionSet::new(&xr_input.action_set); + session.sync_actions(&[act]).unwrap(); + frame_state.lock().unwrap().map(|a| { + //let b = pose.locate(&*xr_input.stage, a.predicted_display_time).unwrap(); + let b = xr_input + .left_space + .relate(&xr_input.stage, a.predicted_display_time) + .unwrap(); + gizmos.rect( + b.0.pose.position.to_vec3(), + b.0.pose.orientation.to_quat(), + Vec2::new(0.05, 0.2), + Color::YELLOW_GREEN, + ); + let c = xr_input + .right_space + .relate(&xr_input.stage, a.predicted_display_time) + .unwrap(); + gizmos.rect( + c.0.pose.position.to_vec3(), + c.0.pose.orientation.to_quat(), + Vec2::new(0.05, 0.2), + Color::YELLOW_GREEN, + ) + }); +} - // for (mut projection, mut transform, eye) in cam.iter_mut() { - // let view_idx = match eye { - // Eye::Left => 0, - // Eye::Right => 1, - // }; - // let view = views.get(view_idx).unwrap(); - // - // projection.fov = view.fov; - // - // transform.rotation = view.pose.orientation.to_quat(); - // let pos = view.pose.position; - // transform.translation = pos.to_vec3(); - // } +fn head_movement( + views: ResMut, + mut query: Query<(&mut Transform, &mut Camera, &CameraType, &mut XRProjection)>, +) { + let views = views.lock().unwrap(); + let mut f = || -> Option<()> { + let midpoint = (views.get(0)?.pose.position.to_vec3() + + views.get(1)?.pose.position.to_vec3()) + / 2.; + for (mut t, _, camera_type, _) in query.iter_mut() { + match camera_type { + CameraType::Left => { + t.translation = views.get(0)?.pose.position.to_vec3() + } + CameraType::Right => { + t.translation = views.get(1)?.pose.position.to_vec3() + } + CameraType::Middle => { + t.translation = midpoint; + } + } + } + let left_rot = views.get(0).unwrap().pose.orientation.to_quat(); + let right_rot = views.get(1).unwrap().pose.orientation.to_quat(); + let mid_rot = if left_rot.dot(right_rot) >= 0. { + left_rot.slerp(right_rot, 0.5) + } else { + right_rot.slerp(left_rot, 0.5) + }; + for (mut t, _, camera_type, _) in query.iter_mut() { + match camera_type { + CameraType::Left => t.rotation = left_rot, + CameraType::Right => t.rotation = right_rot, + CameraType::Middle => { + t.rotation = mid_rot; + } + } + } - Some(()) - }; - f(); + for (mut transform, _cam, camera_type, mut xr_projection) in query.iter_mut() { + let view_idx = match camera_type { + CameraType::Left => 0, + CameraType::Right => 1, + CameraType::Middle => panic!(), + }; + let view = views.get(view_idx).unwrap(); + xr_projection.fov = view.fov; + + transform.rotation = view.pose.orientation.to_quat(); + let pos = view.pose.position; + transform.translation = pos.to_vec3(); + } + + Some(()) + }; + f(); } pub trait Vec3Conv { - fn to_vec3(&self) -> Vec3; + fn to_vec3(&self) -> Vec3; } impl Vec3Conv for openxr::Vector3f { - fn to_vec3(&self) -> Vec3 { - Vec3::new(self.x, self.y, self.z) - } + fn to_vec3(&self) -> Vec3 { + Vec3::new(self.x, self.y, self.z) + } } pub trait QuatConv { - fn to_quat(&self) -> Quat; + fn to_quat(&self) -> Quat; } impl QuatConv for openxr::Quaternionf { - fn to_quat(&self) -> Quat { - Quat::from_xyzw(self.x, self.y, self.z, self.w) - } -} - -// fn head_movement(right_camera: Query<(&mut Transform, &RightCamera), Without>, left_camera: Query<(&mut Transform, &LeftCamera), Without>, xr_input: Res, instance: Res, session: Res) { -// -// // let stage = -// // session.create_reference_space(openxr::ReferenceSpaceType::VIEW, openxr::Posef::IDENTITY).unwrap(); -// // eprintln!("a: {:#?}", stage.locate(&xr_input.stage, xr_input.action_set.).unwrap().pose); -// } \ No newline at end of file + fn to_quat(&self) -> Quat { + Quat::from_xyzw(self.x, self.y, self.z, self.w) + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3c9d4b0..ddbd364 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,22 @@ +mod graphics; pub mod input; pub mod resource_macros; pub mod resources; -mod graphics; use std::sync::{Arc, Mutex}; +use bevy::app::PluginGroupBuilder; use bevy::ecs::system::SystemState; use bevy::prelude::*; -use bevy::render::camera::{ManualTextureViews, ManualTextureView, ManualTextureViewHandle}; -use bevy::render::{FutureRendererResources, RenderPlugin, RenderApp, Render, RenderSet}; +use bevy::render::camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews}; +use bevy::render::renderer::{RenderAdapterInfo, RenderAdapter, RenderDevice, RenderQueue}; +use bevy::render::settings::RenderSettings; +use bevy::render::{Render, RenderApp, RenderPlugin, RenderSet}; use bevy::window::{PrimaryWindow, RawHandleWrapper}; use input::XrInput; -use resources::*; use openxr as xr; +use resources::*; +use wgpu::Instance; const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO; @@ -25,7 +29,7 @@ pub struct OpenXrPlugin; #[derive(Resource)] pub struct FutureXrResources( - pub Arc< + pub Arc< Mutex< Option<( XrInstance, @@ -44,36 +48,44 @@ pub struct FutureXrResources( impl Plugin for OpenXrPlugin { fn build(&self, app: &mut App) { - let future_renderer_resources_wrapper = Arc::new(Mutex::new(None)); - app.insert_resource(FutureRendererResources( - future_renderer_resources_wrapper.clone(), - )); - let future_xr_resources_wrapper = Arc::new(Mutex::new(None)); - app.insert_resource(FutureXrResources( - future_xr_resources_wrapper.clone() - )); + app.insert_resource(FutureXrResources(future_xr_resources_wrapper.clone())); let mut system_state: SystemState>> = SystemState::new(&mut app.world); let primary_window = system_state.get(&app.world).get_single().ok().cloned(); - bevy::tasks::IoTaskPool::get() - .spawn_local(async move { - let (device, queue, adapter_info, render_adapter, instance, xr_instance, session, blend_mode, session_running, frame_waiter, swapchain, input, views, frame_state) = graphics::initialize_xr_graphics(primary_window).unwrap(); - debug!("Configured wgpu adapter Limits: {:#?}", device.limits()); - debug!("Configured wgpu adapter Features: {:#?}", device.features()); - let mut future_renderer_resources_inner = - future_renderer_resources_wrapper.lock().unwrap(); - *future_renderer_resources_inner = - Some((device, queue, adapter_info, render_adapter, instance)); - let mut future_xr_resources_inner = future_xr_resources_wrapper.lock().unwrap(); - *future_xr_resources_inner = - Some((xr_instance, session, blend_mode, session_running, frame_waiter, swapchain, input, views, frame_state)); - }) - .detach(); - - + let ( + device, + queue, + adapter_info, + render_adapter, + instance, + xr_instance, + session, + blend_mode, + session_running, + frame_waiter, + swapchain, + input, + views, + frame_state, + ) = graphics::initialize_xr_graphics(primary_window).unwrap(); + debug!("Configured wgpu adapter Limits: {:#?}", device.limits()); + debug!("Configured wgpu adapter Features: {:#?}", device.features()); + let mut future_xr_resources_inner = future_xr_resources_wrapper.lock().unwrap(); + *future_xr_resources_inner = Some(( + xr_instance, + session, + blend_mode, + session_running, + frame_waiter, + swapchain, + input, + views, + frame_state, + )); + app.add_plugins(DefaultPlugins.set(RenderPlugin { render_settings: RenderSettings::Manual(device, queue, adapter_info, render_adapter, Mutex::new(instance))})); } fn ready(&self, app: &App) -> bool { @@ -84,13 +96,20 @@ impl Plugin for OpenXrPlugin { } fn finish(&self, app: &mut App) { - if let Some(future_renderer_resources) = - app.world.remove_resource::() - { - let (instance, session, blend_mode, session_running, frame_waiter, swapchain, input, views, frame_state) = - future_renderer_resources.0.lock().unwrap().take().unwrap(); + if let Some(future_renderer_resources) = app.world.remove_resource::() { + let ( + xr_instance, + session, + blend_mode, + session_running, + frame_waiter, + swapchain, + input, + views, + frame_state, + ) = future_renderer_resources.0.lock().unwrap().take().unwrap(); - app.insert_resource(instance.clone()) + app.insert_resource(xr_instance.clone()) .insert_resource(session.clone()) .insert_resource(blend_mode.clone()) .insert_resource(session_running.clone()) @@ -120,7 +139,8 @@ impl Plugin for OpenXrPlugin { drop(swapchain_mut); let render_app = app.sub_app_mut(RenderApp); - render_app.insert_resource(instance) + render_app + .insert_resource(xr_instance) .insert_resource(session) .insert_resource(blend_mode) .insert_resource(session_running) @@ -130,19 +150,25 @@ impl Plugin for OpenXrPlugin { .insert_resource(views) .insert_resource(frame_state); - render_app.add_systems(Render, (pre_frame.in_set(RenderSet::Prepare).before(post_frame), post_frame.in_set(RenderSet::Prepare), post_queue_submit.in_set(RenderSet::Cleanup))); + render_app.add_systems( + Render, + ( + pre_frame.in_set(RenderSet::Prepare).before(post_frame), + post_frame.in_set(RenderSet::Prepare), + post_queue_submit.in_set(RenderSet::Cleanup), + ), + ); } - } } pub struct DefaultXrPlugins; impl PluginGroup for DefaultXrPlugins { - fn build(self) -> bevy::app::PluginGroupBuilder { - DefaultPlugins - .build() - .add_before::(OpenXrPlugin) + fn build(self) -> PluginGroupBuilder { + let mut group = PluginGroupBuilder::start::(); + group = group.add(OpenXrPlugin); + group } } @@ -155,7 +181,7 @@ pub fn pre_frame( swapchain: Res, xr_input: Res, mut manual_texture_views: ResMut, -){ +) { while let Some(event) = instance.poll_event(&mut Default::default()).unwrap() { use xr::Event::*; match event { @@ -172,15 +198,11 @@ pub fn pre_frame( session.end().unwrap(); session_running.store(false, std::sync::atomic::Ordering::Relaxed); } - xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => { - return - } + xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => return, _ => {} } } - InstanceLossPending(_) => { - return - } + InstanceLossPending(_) => return, EventsLost(e) => { warn!("lost {} XR events", e.lost_event_count()); } @@ -190,7 +212,7 @@ pub fn pre_frame( if !session_running.load(std::sync::atomic::Ordering::Relaxed) { // Don't grind up the CPU std::thread::sleep(std::time::Duration::from_millis(10)); - return + return; } *frame_state.lock().unwrap() = Some(frame_waiter.lock().unwrap().wait().unwrap()); @@ -228,11 +250,18 @@ pub fn post_frame( session: Res, xr_frame_state: Res, ) { - *views.lock().unwrap() = session.locate_views( - VIEW_TYPE, - xr_frame_state.lock().unwrap().unwrap().predicted_display_time, - &input.stage, - ).unwrap().1; + *views.lock().unwrap() = session + .locate_views( + VIEW_TYPE, + xr_frame_state + .lock() + .unwrap() + .unwrap() + .predicted_display_time, + &input.stage, + ) + .unwrap() + .1; } pub fn post_queue_submit( @@ -245,5 +274,9 @@ pub fn post_queue_submit( let xr_frame_state = xr_frame_state.lock().unwrap().unwrap(); let views = &*views.lock().unwrap(); let stage = &input.stage; - swapchain.lock().unwrap().post_queue_submit(xr_frame_state, views, stage, **environment_blend_mode).unwrap(); -} \ No newline at end of file + swapchain + .lock() + .unwrap() + .post_queue_submit(xr_frame_state, views, stage, **environment_blend_mode) + .unwrap(); +}