From fb9ec378c8283d68433f7539f48a6bd22b6c0ad2 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Sun, 19 May 2024 04:48:49 +0200 Subject: [PATCH] change scheduling Signed-off-by: Schmarni --- crates/bevy_openxr/examples/sessions.rs | 69 +++++++++ .../bevy_openxr/src/openxr/action_binding.rs | 12 +- .../src/openxr/action_set_attaching.rs | 8 +- .../src/openxr/features/handtracking.rs | 15 +- .../src/openxr/features/passthrough.rs | 1 + crates/bevy_openxr/src/openxr/init.rs | 24 ++- crates/bevy_openxr/src/openxr/mod.rs | 5 + .../bevy_openxr/src/openxr/reference_space.rs | 29 ++-- crates/bevy_openxr/src/openxr/render.rs | 3 +- crates/bevy_openxr/src/openxr/resources.rs | 92 +---------- crates/bevy_openxr/src/openxr/session.rs | 144 ++++++++++++++++++ crates/bevy_xr/src/session.rs | 17 ++- 12 files changed, 292 insertions(+), 127 deletions(-) create mode 100644 crates/bevy_openxr/examples/sessions.rs create mode 100644 crates/bevy_openxr/src/openxr/session.rs diff --git a/crates/bevy_openxr/examples/sessions.rs b/crates/bevy_openxr/examples/sessions.rs new file mode 100644 index 0000000..c6b7d1e --- /dev/null +++ b/crates/bevy_openxr/examples/sessions.rs @@ -0,0 +1,69 @@ +//! A simple 3D scene with light shining over a cube sitting on a plane. + +use bevy::prelude::*; +use bevy_openxr::add_xr_plugins; + +fn main() { + App::new() + .add_plugins(add_xr_plugins(DefaultPlugins)) + .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) + .add_systems(Startup, setup) + .add_systems(Update, handle_input) + .run(); +} + +fn handle_input( + keys: Res>, + mut end: EventWriter, + mut destroy: EventWriter, + mut begin: EventWriter, + mut create: EventWriter, +) { + if keys.just_pressed(KeyCode::KeyE) { + end.send_default(); + } + if keys.just_pressed(KeyCode::KeyD) { + destroy.send_default(); + } + if keys.just_pressed(KeyCode::KeyB) { + begin.send_default(); + } + if keys.just_pressed(KeyCode::KeyC) { + create.send_default(); + } +} + +/// set up a simple 3D scene +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // circular base + commands.spawn(PbrBundle { + mesh: meshes.add(Circle::new(4.0)), + material: materials.add(Color::WHITE), + transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)), + ..default() + }); + // cube + commands.spawn(PbrBundle { + mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), + material: materials.add(Color::rgb_u8(124, 144, 255)), + transform: Transform::from_xyz(0.0, 0.5, 0.0), + ..default() + }); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); + commands.spawn(Camera3dBundle { + transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), + ..default() + }); +} diff --git a/crates/bevy_openxr/src/openxr/action_binding.rs b/crates/bevy_openxr/src/openxr/action_binding.rs index a5de40b..3240e84 100644 --- a/crates/bevy_openxr/src/openxr/action_binding.rs +++ b/crates/bevy_openxr/src/openxr/action_binding.rs @@ -5,19 +5,23 @@ use bevy::ecs::schedule::ScheduleLabel; use bevy::ecs::system::RunSystemOnce; use bevy::prelude::*; use bevy::utils::HashMap; -use bevy_xr::session::{status_changed_to, XrStatus}; use openxr::sys::ActionSuggestedBinding; -use crate::resources::OxrInstance; +use crate::{init::OxrPreUpdateSet, resources::OxrInstance, session::OxrSessionStatusEvent}; impl Plugin for OxrActionBindingPlugin { fn build(&self, app: &mut App) { app.add_schedule(Schedule::new(OxrSendActionBindings)); app.add_event::(); app.add_systems( - Update, + PostUpdate, run_action_binding_sugestion - .run_if(status_changed_to(XrStatus::Ready).and_then(run_once())), + .run_if(|mut session_state: EventReader| { + session_state + .read() + .any(|s| *s == OxrSessionStatusEvent::Created) + }) + .after(OxrPreUpdateSet::HandleEvents), ); } } diff --git a/crates/bevy_openxr/src/openxr/action_set_attaching.rs b/crates/bevy_openxr/src/openxr/action_set_attaching.rs index d8a04f8..9eeedc8 100644 --- a/crates/bevy_openxr/src/openxr/action_set_attaching.rs +++ b/crates/bevy_openxr/src/openxr/action_set_attaching.rs @@ -1,4 +1,4 @@ -use crate::resources::OxrSession; +use crate::session::{OxrSession, OxrSessionStatusEvent}; use bevy::prelude::*; use bevy_xr::session::status_changed_to; @@ -7,7 +7,11 @@ impl Plugin for OxrActionAttachingPlugin { app.add_event::(); app.add_systems( PostUpdate, - attach_sets.run_if(status_changed_to(bevy_xr::session::XrStatus::Ready)), + attach_sets.run_if(|mut session_status_event: EventReader| { + session_status_event + .read() + .any(|s| *s == OxrSessionStatusEvent::Created) + }), ); } } diff --git a/crates/bevy_openxr/src/openxr/features/handtracking.rs b/crates/bevy_openxr/src/openxr/features/handtracking.rs index d044313..9c1c73a 100644 --- a/crates/bevy_openxr/src/openxr/features/handtracking.rs +++ b/crates/bevy_openxr/src/openxr/features/handtracking.rs @@ -2,14 +2,15 @@ use bevy::prelude::*; use bevy_xr::hands::{LeftHand, RightHand}; use bevy_xr::{ hands::{HandBone, HandBoneRadius}, - session::{session_running, status_changed_to, XrStatus}, + session::{session_running, XrSessionCreated, XrSessionEnding}, }; use openxr::SpaceLocationFlags; use crate::{ init::OxrTrackingRoot, reference_space::{OxrPrimaryReferenceSpace, OxrReferenceSpace}, - resources::{OxrSession, OxrTime}, + resources::OxrTime, + session::OxrSession, }; pub struct HandTrackingPlugin { @@ -27,14 +28,8 @@ impl Plugin for HandTrackingPlugin { fn build(&self, app: &mut App) { app.add_systems(PreUpdate, locate_hands.run_if(session_running)); if self.default_hands { - app.add_systems( - PreUpdate, - clean_up_default_hands.run_if(status_changed_to(XrStatus::Exiting)), - ); - app.add_systems( - PostUpdate, - spawn_default_hands.run_if(status_changed_to(XrStatus::Ready)), - ); + app.add_systems(XrSessionEnding, clean_up_default_hands); + app.add_systems(XrSessionCreated, spawn_default_hands); } } } diff --git a/crates/bevy_openxr/src/openxr/features/passthrough.rs b/crates/bevy_openxr/src/openxr/features/passthrough.rs index f8fcea8..9dcf898 100644 --- a/crates/bevy_openxr/src/openxr/features/passthrough.rs +++ b/crates/bevy_openxr/src/openxr/features/passthrough.rs @@ -7,6 +7,7 @@ use openxr::PassthroughCapabilityFlagsFB; use crate::layer_builder::PassthroughLayer; use crate::resources::*; +use crate::session::OxrSession; use crate::types::*; pub struct OxrPassthroughPlugin; diff --git a/crates/bevy_openxr/src/openxr/init.rs b/crates/bevy_openxr/src/openxr/init.rs index d557465..c21920a 100644 --- a/crates/bevy_openxr/src/openxr/init.rs +++ b/crates/bevy_openxr/src/openxr/init.rs @@ -1,3 +1,4 @@ +use bevy::ecs::system::RunSystemOnce; use bevy::prelude::*; use bevy::render::extract_resource::ExtractResourcePlugin; use bevy::render::renderer::RenderAdapter; @@ -22,6 +23,7 @@ use bevy_xr::session::BeginXrSession; use bevy_xr::session::CreateXrSession; use bevy_xr::session::DestroyXrSession; use bevy_xr::session::EndXrSession; +use bevy_xr::session::XrRenderSessionEnding; use bevy_xr::session::XrSharedStatus; use bevy_xr::session::XrStatus; use bevy_xr::session::XrStatusChanged; @@ -30,6 +32,8 @@ use crate::error::OxrError; use crate::graphics::*; use crate::reference_space::OxrPrimaryReferenceSpace; use crate::resources::*; +use crate::session::OxrSession; +use crate::session::OxrSessionStatusEvent; use crate::types::*; pub fn session_started(started: Option>) -> bool { @@ -514,6 +518,7 @@ pub fn poll_events( instance: Res, status: Res, mut changed_event: EventWriter, + mut session_status_events: EventWriter, ) { let _span = info_span!("xr_poll_events"); let mut buffer = Default::default(); @@ -531,13 +536,21 @@ pub fn poll_events( info!("entered XR state {:?}", state); let new_status = match state { - SessionState::IDLE => XrStatus::Idle, + SessionState::IDLE => { + if status.get() == XrStatus::Available { + session_status_events.send(OxrSessionStatusEvent::Created); + } + XrStatus::Idle + } SessionState::READY => XrStatus::Ready, SessionState::SYNCHRONIZED | SessionState::VISIBLE | SessionState::FOCUSED => { XrStatus::Running } SessionState::STOPPING => XrStatus::Stopping, - SessionState::EXITING | SessionState::LOSS_PENDING => XrStatus::Exiting, + SessionState::EXITING | SessionState::LOSS_PENDING => { + session_status_events.send(OxrSessionStatusEvent::AboutToBeDestroyed); + XrStatus::Exiting + } _ => unreachable!(), }; changed_event.send(XrStatusChanged(new_status)); @@ -555,19 +568,16 @@ pub fn reset_per_frame_resources(mut cleanup: ResMut) { } pub fn destroy_xr_session(mut commands: Commands) { - commands.remove_resource::(); commands.remove_resource::(); commands.remove_resource::(); commands.remove_resource::(); - commands.remove_resource::(); - commands.insert_resource(OxrCleanupSession(true)); } pub fn destroy_xr_session_render(world: &mut World) { world.remove_resource::(); world.remove_resource::(); - world.remove_resource::(); world.remove_resource::(); world.remove_resource::(); - world.remove_resource::(); + world.run_schedule(XrRenderSessionEnding); + world.run_system_once(apply_deferred); } diff --git a/crates/bevy_openxr/src/openxr/mod.rs b/crates/bevy_openxr/src/openxr/mod.rs index b4428e2..6615370 100644 --- a/crates/bevy_openxr/src/openxr/mod.rs +++ b/crates/bevy_openxr/src/openxr/mod.rs @@ -13,6 +13,7 @@ use render::OxrRenderPlugin; use self::{ features::{handtracking::HandTrackingPlugin, passthrough::OxrPassthroughPlugin}, reference_space::OxrReferenceSpacePlugin, + session::OxrSessionPlugin, }; pub mod action_binding; @@ -28,6 +29,7 @@ pub mod layer_builder; pub mod reference_space; pub mod render; pub mod resources; +pub mod session; pub mod types; pub fn add_xr_plugins(plugins: G) -> PluginGroupBuilder { @@ -37,6 +39,7 @@ pub fn add_xr_plugins(plugins: G) -> PluginGroupBuilder { .disable::() .add_before::(XrSessionPlugin) .add_before::(OxrInitPlugin::default()) + .add(OxrSessionPlugin) .add(OxrReferenceSpacePlugin::default()) .add(OxrRenderPlugin) .add(OxrPassthroughPlugin) @@ -46,6 +49,8 @@ pub fn add_xr_plugins(plugins: G) -> PluginGroupBuilder { .add(action_binding::OxrActionBindingPlugin) .add(action_set_syncing::OxrActionSyncingPlugin) // .add(XrActionPlugin) + // we should probably handle the exiting ourselfs so that we can correctly end the + // session and instance .set(WindowPlugin { primary_window: Some(Window { transparent: true, diff --git a/crates/bevy_openxr/src/openxr/reference_space.rs b/crates/bevy_openxr/src/openxr/reference_space.rs index 730027f..14b1b5f 100644 --- a/crates/bevy_openxr/src/openxr/reference_space.rs +++ b/crates/bevy_openxr/src/openxr/reference_space.rs @@ -4,9 +4,11 @@ use bevy::{ prelude::*, render::extract_resource::{ExtractResource, ExtractResourcePlugin}, }; -use bevy_xr::session::{status_changed_to, XrStatus}; +use bevy_xr::session::{ + status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionEnding, XrStatus, +}; -use crate::{init::OxrPreUpdateSet, resources::OxrSession}; +use crate::{init::OxrPreUpdateSet, session::OxrSession}; pub struct OxrReferenceSpacePlugin { pub default_primary_ref_space: openxr::ReferenceSpaceType, @@ -20,8 +22,7 @@ impl Default for OxrReferenceSpacePlugin { } #[derive(Resource)] -struct OxrPrimaryReferenceSpaceType(openxr::ReferenceSpaceType); -// TODO: this will keep the session alive so we need to remove this in the render world too +struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType); /// The Default Reference space used for locating things #[derive(Resource, Deref, ExtractResource, Clone)] pub struct OxrPrimaryReferenceSpace(pub Arc); @@ -32,20 +33,24 @@ pub struct OxrReferenceSpace(pub openxr::Space); impl Plugin for OxrReferenceSpacePlugin { fn build(&self, app: &mut App) { - app.insert_resource(OxrPrimaryReferenceSpaceType(self.default_primary_ref_space)); + app.insert_resource(OxrDefaultPrimaryReferenceSpaceType(self.default_primary_ref_space)); app.add_plugins(ExtractResourcePlugin::::default()); - app.add_systems( - PreUpdate, - set_primary_ref_space - .run_if(status_changed_to(XrStatus::Ready)) - .in_set(OxrPreUpdateSet::UpdateCriticalComponents), - ); + app.add_systems(XrSessionCreated, set_primary_ref_space); + app.add_systems(XrSessionEnding, cleanup); + app.add_systems(XrRenderSessionEnding, cleanup); + } +} + +fn cleanup(mut cmds: Commands, query: Query>) { + cmds.remove_resource::(); + for e in &query { + cmds.entity(e).remove::(); } } fn set_primary_ref_space( session: Res, - space_type: Res, + space_type: Res, mut cmds: Commands, ) { match session.create_reference_space(space_type.0, openxr::Posef::IDENTITY) { diff --git a/crates/bevy_openxr/src/openxr/render.rs b/crates/bevy_openxr/src/openxr/render.rs index bbd1741..eba6f90 100644 --- a/crates/bevy_openxr/src/openxr/render.rs +++ b/crates/bevy_openxr/src/openxr/render.rs @@ -16,9 +16,10 @@ use bevy_xr::{ }; use openxr::ViewStateFlags; + use crate::{ init::{session_started, OxrPreUpdateSet, OxrTrackingRoot}, - layer_builder::ProjectionLayer, + layer_builder::ProjectionLayer, session::OxrSession, }; use crate::{reference_space::OxrPrimaryReferenceSpace, resources::*}; diff --git a/crates/bevy_openxr/src/openxr/resources.rs b/crates/bevy_openxr/src/openxr/resources.rs index c6a59c5..f20766a 100644 --- a/crates/bevy_openxr/src/openxr/resources.rs +++ b/crates/bevy_openxr/src/openxr/resources.rs @@ -8,6 +8,7 @@ use openxr::AnyGraphics; use crate::error::OxrError; use crate::graphics::*; use crate::layer_builder::{CompositionLayer, LayerProvider}; +use crate::session::OxrSession; use crate::types::*; /// Wrapper around an [`Entry`](openxr::Entry) with some methods overridden to use bevy types. @@ -147,95 +148,6 @@ impl OxrInstance { } } -/// Graphics agnostic wrapper around [openxr::Session]. -/// -/// See [`openxr::Session`] for other available methods. -#[derive(Resource, Deref, Clone)] -pub struct OxrSession( - /// A session handle with [`AnyGraphics`]. - /// Having this here allows the majority of [`Session`](openxr::Session)'s methods to work without having to rewrite them. - #[deref] - pub(crate) openxr::Session, - /// A [`GraphicsWrap`] with [`openxr::Session`] as the inner type. - /// This is so that we can still operate on functions that don't take [`AnyGraphics`] as the generic. - pub(crate) GraphicsWrap, -); - -impl GraphicsType for OxrSession { - type Inner = openxr::Session; -} - -impl From> for OxrSession { - fn from(session: openxr::Session) -> Self { - Self::from_inner(session) - } -} - -impl OxrSession { - /// Creates a new [`OxrSession`] from an [`openxr::Session`]. - /// In the majority of cases, you should use [`create_session`](OxrInstance::create_session) instead. - pub fn from_inner(session: openxr::Session) -> Self { - Self(session.clone().into_any_graphics(), G::wrap(session)) - } - - /// Returns [`GraphicsWrap`] with [`openxr::Session`] as the inner type. - /// - /// This can be useful if you need access to the original [`openxr::Session`] with the graphics API still specified. - pub fn typed_session(&self) -> &GraphicsWrap { - &self.1 - } - - /// Enumerates all available swapchain formats and converts them to wgpu's [`TextureFormat`](wgpu::TextureFormat). - /// - /// Calls [`enumerate_swapchain_formats`](openxr::Session::enumerate_swapchain_formats) internally. - pub fn enumerate_swapchain_formats(&self) -> Result> { - graphics_match!( - &self.1; - session => Ok(session.enumerate_swapchain_formats()?.into_iter().filter_map(Api::into_wgpu_format).collect()) - ) - } - - /// Creates an [OxrSwapchain]. - /// - /// Calls [`create_swapchain`](openxr::Session::create_swapchain) internally. - pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result { - Ok(OxrSwapchain(graphics_match!( - &self.1; - session => session.create_swapchain(&info.try_into()?)? => OxrSwapchain - ))) - } - - /// Creates a passthrough. - /// - /// Requires [`XR_FB_passthrough`](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_FB_passthrough). - /// - /// Calls [`create_passthrough`](openxr::Session::create_passthrough) internally. - pub fn create_passthrough(&self, flags: openxr::PassthroughFlagsFB) -> Result { - Ok(OxrPassthrough( - graphics_match! { - &self.1; - session => session.create_passthrough(flags)? - }, - flags, - )) - } - - /// Creates a passthrough layer that can be used to make a [`CompositionLayerPassthrough`](crate::layer_builder::CompositionLayerPassthrough) for frame submission. - /// - /// Requires [`XR_FB_passthrough`](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_FB_passthrough). - /// - /// Calls [`create_passthrough_layer`](openxr::Session::create_passthrough_layer) internally. - pub fn create_passthrough_layer( - &self, - passthrough: &OxrPassthrough, - purpose: openxr::PassthroughLayerPurposeFB, - ) -> Result { - Ok(OxrPassthroughLayer(graphics_match! { - &self.1; - session => session.create_passthrough_layer(&passthrough.0, passthrough.1, purpose)? - })) - } -} /// Graphics agnostic wrapper around [openxr::FrameStream] #[derive(Resource)] @@ -397,7 +309,7 @@ pub struct OxrSystemId(pub openxr::SystemId); pub struct OxrPassthrough( #[deref] pub openxr::Passthrough, /// The flags are stored here so that they don't need to be passed in again when creating an [`OxrPassthroughLayer`]. - openxr::PassthroughFlagsFB, + pub openxr::PassthroughFlagsFB, ); impl OxrPassthrough { diff --git a/crates/bevy_openxr/src/openxr/session.rs b/crates/bevy_openxr/src/openxr/session.rs new file mode 100644 index 0000000..bba1f9a --- /dev/null +++ b/crates/bevy_openxr/src/openxr/session.rs @@ -0,0 +1,144 @@ +use crate::init::OxrPreUpdateSet; +use crate::resources::{OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSwapchain}; +use crate::types::{Result, SwapchainCreateInfo}; +use bevy::ecs::system::{RunSystemOnce, SystemState}; +use bevy::prelude::*; +use bevy_xr::session::{XrRenderSessionEnding, XrSessionCreated, XrSessionEnding}; +use openxr::AnyGraphics; + +use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap}; + +#[derive(Event, Clone, Copy, PartialEq, Eq, Hash)] +pub enum OxrSessionStatusEvent { + Created, + AboutToBeDestroyed, +} + +pub struct OxrSessionPlugin; + +impl Plugin for OxrSessionPlugin { + fn build(&self, app: &mut App) { + app.add_event::(); + app.add_systems( + PreUpdate, + run_session_status_schedules.in_set(OxrPreUpdateSet::HandleEvents), + ); + app.add_systems(XrSessionEnding, clean_session); + app.add_systems(XrRenderSessionEnding, |mut cmds: Commands| { + cmds.remove_resource::() + }); + } +} + +fn clean_session(mut cmds: Commands) { + cmds.remove_resource::(); + cmds.insert_resource(OxrCleanupSession(true)); +} + +fn run_session_status_schedules(world: &mut World) { + let mut state = SystemState::>::new(world); + let mut e = state.get_mut(world); + let events = e.read().copied().collect::>(); + for e in events.iter() { + match e { + OxrSessionStatusEvent::Created => { + world.run_schedule(XrSessionCreated); + world.run_system_once(apply_deferred); + } + OxrSessionStatusEvent::AboutToBeDestroyed => { + world.run_schedule(XrSessionEnding); + world.run_system_once(apply_deferred); + } + } + } +} + +/// Graphics agnostic wrapper around [openxr::Session]. +/// +/// See [`openxr::Session`] for other available methods. +#[derive(Resource, Deref, Clone)] +pub struct OxrSession( + /// A session handle with [`AnyGraphics`]. + /// Having this here allows the majority of [`Session`](openxr::Session)'s methods to work without having to rewrite them. + #[deref] + pub(crate) openxr::Session, + /// A [`GraphicsWrap`] with [`openxr::Session`] as the inner type. + /// This is so that we can still operate on functions that don't take [`AnyGraphics`] as the generic. + pub(crate) GraphicsWrap, +); + +impl GraphicsType for OxrSession { + type Inner = openxr::Session; +} + +impl From> for OxrSession { + fn from(session: openxr::Session) -> Self { + Self::from_inner(session) + } +} + +impl OxrSession { + /// Creates a new [`OxrSession`] from an [`openxr::Session`]. + /// In the majority of cases, you should use [`create_session`](OxrInstance::create_session) instead. + pub fn from_inner(session: openxr::Session) -> Self { + Self(session.clone().into_any_graphics(), G::wrap(session)) + } + + /// Returns [`GraphicsWrap`] with [`openxr::Session`] as the inner type. + /// + /// This can be useful if you need access to the original [`openxr::Session`] with the graphics API still specified. + pub fn typed_session(&self) -> &GraphicsWrap { + &self.1 + } + + /// Enumerates all available swapchain formats and converts them to wgpu's [`TextureFormat`](wgpu::TextureFormat). + /// + /// Calls [`enumerate_swapchain_formats`](openxr::Session::enumerate_swapchain_formats) internally. + pub fn enumerate_swapchain_formats(&self) -> Result> { + graphics_match!( + &self.1; + session => Ok(session.enumerate_swapchain_formats()?.into_iter().filter_map(Api::into_wgpu_format).collect()) + ) + } + + /// Creates an [OxrSwapchain]. + /// + /// Calls [`create_swapchain`](openxr::Session::create_swapchain) internally. + pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result { + Ok(OxrSwapchain(graphics_match!( + &self.1; + session => session.create_swapchain(&info.try_into()?)? => OxrSwapchain + ))) + } + + /// Creates a passthrough. + /// + /// Requires [`XR_FB_passthrough`](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_FB_passthrough). + /// + /// Calls [`create_passthrough`](openxr::Session::create_passthrough) internally. + pub fn create_passthrough(&self, flags: openxr::PassthroughFlagsFB) -> Result { + Ok(OxrPassthrough( + graphics_match! { + &self.1; + session => session.create_passthrough(flags)? + }, + flags, + )) + } + + /// Creates a passthrough layer that can be used to make a [`CompositionLayerPassthrough`](crate::layer_builder::CompositionLayerPassthrough) for frame submission. + /// + /// Requires [`XR_FB_passthrough`](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_FB_passthrough). + /// + /// Calls [`create_passthrough_layer`](openxr::Session::create_passthrough_layer) internally. + pub fn create_passthrough_layer( + &self, + passthrough: &OxrPassthrough, + purpose: openxr::PassthroughLayerPurposeFB, + ) -> Result { + Ok(OxrPassthroughLayer(graphics_match! { + &self.1; + session => session.create_passthrough_layer(&passthrough.0, passthrough.1, purpose)? + })) + } +} diff --git a/crates/bevy_xr/src/session.rs b/crates/bevy_xr/src/session.rs index 7783f94..dae1cd0 100644 --- a/crates/bevy_xr/src/session.rs +++ b/crates/bevy_xr/src/session.rs @@ -1,11 +1,13 @@ use std::sync::{Arc, RwLock}; -use bevy::prelude::*; +use bevy::{ecs::schedule::ScheduleLabel, prelude::*}; pub struct XrSessionPlugin; impl Plugin for XrSessionPlugin { fn build(&self, app: &mut App) { + app.init_schedule(XrSessionCreated); + app.init_schedule(XrSessionEnding); app.add_event::() .add_event::() .add_event::() @@ -16,8 +18,21 @@ impl Plugin for XrSessionPlugin { handle_session.run_if(resource_exists::), ); } + fn finish(&self, app: &mut App) { + // This is in finnish because we need the RenderPlugin to already be added. + app.init_schedule(XrRenderSessionEnding); + } } +#[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub struct XrSessionCreated; + +#[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub struct XrSessionEnding; + +#[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub struct XrRenderSessionEnding; + #[derive(Event, Clone, Copy, Deref)] pub struct XrStatusChanged(pub XrStatus);