From fb9ec378c8283d68433f7539f48a6bd22b6c0ad2 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Sun, 19 May 2024 04:48:49 +0200 Subject: [PATCH 1/7] 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); From 31c1daf2d4bc70eebfbb2b8d2d3d98e3c5d57b9e Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 23 May 2024 22:05:14 +0200 Subject: [PATCH 2/7] session ending works but segfaults on my machine Signed-off-by: Schmarni --- crates/bevy_openxr/examples/sessions.rs | 4 ++++ .../src/openxr/features/handtracking.rs | 4 ++-- crates/bevy_openxr/src/openxr/init.rs | 9 ++++--- .../bevy_openxr/src/openxr/reference_space.rs | 4 ++-- crates/bevy_openxr/src/openxr/render.rs | 17 ++++++++++--- crates/bevy_openxr/src/openxr/resources.rs | 10 ++++++++ crates/bevy_openxr/src/openxr/session.rs | 24 +++++++++++++++---- crates/bevy_xr/src/session.rs | 12 ++++++---- 8 files changed, 64 insertions(+), 20 deletions(-) diff --git a/crates/bevy_openxr/examples/sessions.rs b/crates/bevy_openxr/examples/sessions.rs index c6b7d1e..1b4e480 100644 --- a/crates/bevy_openxr/examples/sessions.rs +++ b/crates/bevy_openxr/examples/sessions.rs @@ -20,15 +20,19 @@ fn handle_input( mut create: EventWriter, ) { if keys.just_pressed(KeyCode::KeyE) { + info!("sending end"); end.send_default(); } if keys.just_pressed(KeyCode::KeyD) { + info!("sending destroy"); destroy.send_default(); } if keys.just_pressed(KeyCode::KeyB) { + info!("sending begin"); begin.send_default(); } if keys.just_pressed(KeyCode::KeyC) { + info!("sending create"); create.send_default(); } } diff --git a/crates/bevy_openxr/src/openxr/features/handtracking.rs b/crates/bevy_openxr/src/openxr/features/handtracking.rs index 9c1c73a..fa87a87 100644 --- a/crates/bevy_openxr/src/openxr/features/handtracking.rs +++ b/crates/bevy_openxr/src/openxr/features/handtracking.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use bevy_xr::hands::{LeftHand, RightHand}; use bevy_xr::{ hands::{HandBone, HandBoneRadius}, - session::{session_running, XrSessionCreated, XrSessionEnding}, + session::{session_running, XrSessionCreated, XrSessionExiting}, }; use openxr::SpaceLocationFlags; @@ -28,7 +28,7 @@ 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(XrSessionEnding, clean_up_default_hands); + app.add_systems(XrSessionExiting, clean_up_default_hands); app.add_systems(XrSessionCreated, spawn_default_hands); } } diff --git a/crates/bevy_openxr/src/openxr/init.rs b/crates/bevy_openxr/src/openxr/init.rs index c21920a..aee5bf8 100644 --- a/crates/bevy_openxr/src/openxr/init.rs +++ b/crates/bevy_openxr/src/openxr/init.rs @@ -131,7 +131,7 @@ impl Plugin for OxrInitPlugin { .run_if(status_equals(XrStatus::Ready)), end_xr_session .run_if(on_event::()) - .run_if(status_equals(XrStatus::Stopping)), + .run_if(status_equals(XrStatus::Running)), destroy_xr_session .run_if(on_event::()) .run_if(status_equals(XrStatus::Exiting)), @@ -489,8 +489,11 @@ pub fn begin_xr_session(session: Res, session_started: Res, session_started: Res) { let _span = info_span!("xr_end_session"); - session.end().expect("Failed to end session"); - session_started.set(false); + session + .request_exit() + .expect("Failed to request session exit"); + // session.end().expect("Failed to end session"); + // session_started.set(false); } /// This system transfers important render resources from the main world to the render world when a session is created. diff --git a/crates/bevy_openxr/src/openxr/reference_space.rs b/crates/bevy_openxr/src/openxr/reference_space.rs index 14b1b5f..2516c03 100644 --- a/crates/bevy_openxr/src/openxr/reference_space.rs +++ b/crates/bevy_openxr/src/openxr/reference_space.rs @@ -5,7 +5,7 @@ use bevy::{ render::extract_resource::{ExtractResource, ExtractResourcePlugin}, }; use bevy_xr::session::{ - status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionEnding, XrStatus, + status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionExiting, XrStatus, }; use crate::{init::OxrPreUpdateSet, session::OxrSession}; @@ -36,7 +36,7 @@ impl Plugin for OxrReferenceSpacePlugin { app.insert_resource(OxrDefaultPrimaryReferenceSpaceType(self.default_primary_ref_space)); app.add_plugins(ExtractResourcePlugin::::default()); app.add_systems(XrSessionCreated, set_primary_ref_space); - app.add_systems(XrSessionEnding, cleanup); + app.add_systems(XrSessionExiting, cleanup); app.add_systems(XrRenderSessionEnding, cleanup); } } diff --git a/crates/bevy_openxr/src/openxr/render.rs b/crates/bevy_openxr/src/openxr/render.rs index eba6f90..d7a07e7 100644 --- a/crates/bevy_openxr/src/openxr/render.rs +++ b/crates/bevy_openxr/src/openxr/render.rs @@ -12,11 +12,10 @@ use bevy::{ }; use bevy_xr::{ camera::{XrCamera, XrCameraBundle, XrProjection}, - session::session_running, + session::{session_running, XrSessionExiting}, }; use openxr::ViewStateFlags; - use crate::{ init::{session_started, OxrPreUpdateSet, OxrTrackingRoot}, layer_builder::ProjectionLayer, session::OxrSession, @@ -45,7 +44,8 @@ impl Plugin for OxrRenderPlugin { .run_if(session_running) .before(TransformSystem::TransformPropagate), ) - .add_systems(Last, wait_frame.run_if(session_started)); + .add_systems(Last, wait_frame.run_if(session_started)) + .add_systems(XrSessionExiting, clean_views); app.sub_app_mut(RenderApp) .add_systems( Render, @@ -73,6 +73,17 @@ impl Plugin for OxrRenderPlugin { pub const XR_TEXTURE_INDEX: u32 = 3383858418; +pub fn clean_views( + mut manual_texture_views: ResMut, + mut commands: Commands, + cam_query: Query<(Entity, &XrCamera)>, +) { + for (e, cam) in &cam_query { + manual_texture_views.remove(&ManualTextureViewHandle(XR_TEXTURE_INDEX + cam.0)); + commands.entity(e).despawn_recursive(); + } +} + // TODO: have cameras initialized externally and then recieved by this function. /// This is needed to properly initialize the texture views so that bevy will set them to the correct resolution despite them being updated in the render world. pub fn init_views( diff --git a/crates/bevy_openxr/src/openxr/resources.rs b/crates/bevy_openxr/src/openxr/resources.rs index f20766a..15786d9 100644 --- a/crates/bevy_openxr/src/openxr/resources.rs +++ b/crates/bevy_openxr/src/openxr/resources.rs @@ -218,6 +218,11 @@ pub struct OxrFrameWaiter(pub openxr::FrameWaiter); /// Graphics agnostic wrapper around [openxr::Swapchain] #[derive(Resource)] pub struct OxrSwapchain(pub GraphicsWrap); +impl Drop for OxrSwapchain { + fn drop(&mut self) { + info!("Dropping Swapchain"); + } +} impl GraphicsType for OxrSwapchain { type Inner = openxr::Swapchain; @@ -287,6 +292,11 @@ impl OxrSwapchain { /// Stores the generated swapchain images. #[derive(Debug, Deref, Resource, Clone)] pub struct OxrSwapchainImages(pub Arc>); +impl Drop for OxrSwapchainImages { + fn drop(&mut self) { + info!("Dropping Swapchain Images"); + } +} /// Thread safe wrapper around [openxr::Space] representing the stage. // #[derive(Deref, Clone, Resource)] diff --git a/crates/bevy_openxr/src/openxr/session.rs b/crates/bevy_openxr/src/openxr/session.rs index bba1f9a..76088b4 100644 --- a/crates/bevy_openxr/src/openxr/session.rs +++ b/crates/bevy_openxr/src/openxr/session.rs @@ -1,9 +1,13 @@ use crate::init::OxrPreUpdateSet; -use crate::resources::{OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSwapchain}; +use crate::resources::{ + OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSessionStarted, OxrSwapchain, +}; use crate::types::{Result, SwapchainCreateInfo}; use bevy::ecs::system::{RunSystemOnce, SystemState}; use bevy::prelude::*; -use bevy_xr::session::{XrRenderSessionEnding, XrSessionCreated, XrSessionEnding}; +use bevy_xr::session::{ + status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionExiting, XrStatus, +}; use openxr::AnyGraphics; use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap}; @@ -23,13 +27,23 @@ impl Plugin for OxrSessionPlugin { PreUpdate, run_session_status_schedules.in_set(OxrPreUpdateSet::HandleEvents), ); - app.add_systems(XrSessionEnding, clean_session); + app.add_systems(XrSessionExiting, clean_session); app.add_systems(XrRenderSessionEnding, |mut cmds: Commands| { - cmds.remove_resource::() + cmds.remove_resource::(); + cmds.remove_resource::(); }); + app.add_systems( + PreUpdate, + handle_stopping_state.run_if(status_changed_to(XrStatus::Stopping)), + ); } } +fn handle_stopping_state(session: Res, session_started: Res) { + session.end().expect("Failed to end session"); + session_started.set(false); +} + fn clean_session(mut cmds: Commands) { cmds.remove_resource::(); cmds.insert_resource(OxrCleanupSession(true)); @@ -46,7 +60,7 @@ fn run_session_status_schedules(world: &mut World) { world.run_system_once(apply_deferred); } OxrSessionStatusEvent::AboutToBeDestroyed => { - world.run_schedule(XrSessionEnding); + world.run_schedule(XrSessionExiting); world.run_system_once(apply_deferred); } } diff --git a/crates/bevy_xr/src/session.rs b/crates/bevy_xr/src/session.rs index dae1cd0..004d2be 100644 --- a/crates/bevy_xr/src/session.rs +++ b/crates/bevy_xr/src/session.rs @@ -1,13 +1,13 @@ use std::sync::{Arc, RwLock}; -use bevy::{ecs::schedule::ScheduleLabel, prelude::*}; +use bevy::{ecs::schedule::ScheduleLabel, prelude::*, render::RenderApp}; pub struct XrSessionPlugin; impl Plugin for XrSessionPlugin { fn build(&self, app: &mut App) { app.init_schedule(XrSessionCreated); - app.init_schedule(XrSessionEnding); + app.init_schedule(XrSessionExiting); app.add_event::() .add_event::() .add_event::() @@ -20,7 +20,9 @@ impl Plugin for XrSessionPlugin { } fn finish(&self, app: &mut App) { // This is in finnish because we need the RenderPlugin to already be added. - app.init_schedule(XrRenderSessionEnding); + app.get_sub_app_mut(RenderApp) + .unwrap() + .init_schedule(XrRenderSessionEnding); } } @@ -28,7 +30,7 @@ impl Plugin for XrSessionPlugin { pub struct XrSessionCreated; #[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub struct XrSessionEnding; +pub struct XrSessionExiting; #[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct XrRenderSessionEnding; @@ -93,7 +95,7 @@ pub fn handle_session( } XrStatus::Running => {} XrStatus::Stopping => { - end_session.send_default(); + // end_session.send_default(); } XrStatus::Exiting => { destroy_session.send_default(); From 546202fdfa6e7cfea5455ef5f0e33c06bb8f00f3 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 24 May 2024 17:11:38 +0200 Subject: [PATCH 3/7] works but destroys the session manually because one space somewhere survives session exit Signed-off-by: Schmarni --- crates/bevy_openxr/examples/sessions.rs | 5 +++ .../src/openxr/features/handtracking.rs | 3 +- crates/bevy_openxr/src/openxr/init.rs | 16 +++++++-- crates/bevy_openxr/src/openxr/resources.rs | 12 ++----- crates/bevy_openxr/src/openxr/session.rs | 34 ++++++++++++++----- crates/bevy_xr/src/session.rs | 8 ++--- 6 files changed, 53 insertions(+), 25 deletions(-) diff --git a/crates/bevy_openxr/examples/sessions.rs b/crates/bevy_openxr/examples/sessions.rs index 1b4e480..e3ca3e5 100644 --- a/crates/bevy_openxr/examples/sessions.rs +++ b/crates/bevy_openxr/examples/sessions.rs @@ -2,6 +2,7 @@ use bevy::prelude::*; use bevy_openxr::add_xr_plugins; +use bevy_xr::session::{XrSharedStatus, XrStatus}; fn main() { App::new() @@ -18,6 +19,7 @@ fn handle_input( mut destroy: EventWriter, mut begin: EventWriter, mut create: EventWriter, + state: Res, ) { if keys.just_pressed(KeyCode::KeyE) { info!("sending end"); @@ -35,6 +37,9 @@ fn handle_input( info!("sending create"); create.send_default(); } + if keys.just_pressed(KeyCode::KeyI) { + info!("current state: {:?}", state.get()); + } } /// set up a simple 3D scene diff --git a/crates/bevy_openxr/src/openxr/features/handtracking.rs b/crates/bevy_openxr/src/openxr/features/handtracking.rs index fa87a87..f681cda 100644 --- a/crates/bevy_openxr/src/openxr/features/handtracking.rs +++ b/crates/bevy_openxr/src/openxr/features/handtracking.rs @@ -115,7 +115,8 @@ fn clean_up_default_hands( query: Query, With)>>, ) { for e in &query { - cmds.entity(e).despawn(); + info!("removing_hand_entity"); + cmds.entity(e).despawn_recursive(); } } diff --git a/crates/bevy_openxr/src/openxr/init.rs b/crates/bevy_openxr/src/openxr/init.rs index aee5bf8..0306feb 100644 --- a/crates/bevy_openxr/src/openxr/init.rs +++ b/crates/bevy_openxr/src/openxr/init.rs @@ -24,6 +24,7 @@ use bevy_xr::session::CreateXrSession; use bevy_xr::session::DestroyXrSession; use bevy_xr::session::EndXrSession; use bevy_xr::session::XrRenderSessionEnding; +use bevy_xr::session::XrSessionExiting; use bevy_xr::session::XrSharedStatus; use bevy_xr::session::XrStatus; use bevy_xr::session::XrStatusChanged; @@ -132,13 +133,11 @@ impl Plugin for OxrInitPlugin { end_xr_session .run_if(on_event::()) .run_if(status_equals(XrStatus::Running)), - destroy_xr_session - .run_if(on_event::()) - .run_if(status_equals(XrStatus::Exiting)), ) .in_set(OxrPreUpdateSet::HandleEvents), ), ) + .add_systems(XrSessionExiting, destroy_xr_session) .add_systems( PostUpdate, update_root_transform.after(TransformSystem::TransformPropagate), @@ -456,6 +455,7 @@ pub fn create_xr_session( system_id: Res, mut commands: Commands, ) { + info!("creating session!"); match init_xr_session( device.wgpu_device(), &instance, @@ -481,6 +481,7 @@ pub fn create_xr_session( pub fn begin_xr_session(session: Res, session_started: Res) { let _span = info_span!("xr_begin_session"); + info!("begining session!"); session .begin(openxr::ViewConfigurationType::PRIMARY_STEREO) .expect("Failed to begin session"); @@ -489,6 +490,7 @@ pub fn begin_xr_session(session: Res, session_started: Res, session_started: Res) { let _span = info_span!("xr_end_session"); + info!("ending session!"); session .request_exit() .expect("Failed to request session exit"); @@ -542,6 +544,7 @@ pub fn poll_events( SessionState::IDLE => { if status.get() == XrStatus::Available { session_status_events.send(OxrSessionStatusEvent::Created); + info!("sending create info"); } XrStatus::Idle } @@ -552,6 +555,7 @@ pub fn poll_events( SessionState::STOPPING => XrStatus::Stopping, SessionState::EXITING | SessionState::LOSS_PENDING => { session_status_events.send(OxrSessionStatusEvent::AboutToBeDestroyed); + info!("sending destroy info"); XrStatus::Exiting } _ => unreachable!(), @@ -583,4 +587,10 @@ pub fn destroy_xr_session_render(world: &mut World) { world.remove_resource::(); world.run_schedule(XrRenderSessionEnding); world.run_system_once(apply_deferred); + if let Some(sess) = world.remove_resource::() { + unsafe { + (sess.instance().fp().destroy_session)(sess.as_raw()); + } + Box::leak(Box::new(sess)); + } } diff --git a/crates/bevy_openxr/src/openxr/resources.rs b/crates/bevy_openxr/src/openxr/resources.rs index 15786d9..db8b07d 100644 --- a/crates/bevy_openxr/src/openxr/resources.rs +++ b/crates/bevy_openxr/src/openxr/resources.rs @@ -148,7 +148,6 @@ impl OxrInstance { } } - /// Graphics agnostic wrapper around [openxr::FrameStream] #[derive(Resource)] pub struct OxrFrameStream(pub GraphicsWrap); @@ -283,20 +282,15 @@ impl OxrSwapchain { images.push(Api::to_wgpu_img(image, device, format, resolution)?); } } - Ok(OxrSwapchainImages(images.into())) + Ok(OxrSwapchainImages(images.leak())) } ) } } /// Stores the generated swapchain images. -#[derive(Debug, Deref, Resource, Clone)] -pub struct OxrSwapchainImages(pub Arc>); -impl Drop for OxrSwapchainImages { - fn drop(&mut self) { - info!("Dropping Swapchain Images"); - } -} +#[derive(Debug, Deref, Resource, Clone, Copy)] +pub struct OxrSwapchainImages(pub &'static [wgpu::Texture]); /// Thread safe wrapper around [openxr::Space] representing the stage. // #[derive(Deref, Clone, Resource)] diff --git a/crates/bevy_openxr/src/openxr/session.rs b/crates/bevy_openxr/src/openxr/session.rs index 76088b4..9a65ae8 100644 --- a/crates/bevy_openxr/src/openxr/session.rs +++ b/crates/bevy_openxr/src/openxr/session.rs @@ -5,8 +5,11 @@ use crate::resources::{ use crate::types::{Result, SwapchainCreateInfo}; use bevy::ecs::system::{RunSystemOnce, SystemState}; use bevy::prelude::*; +use bevy::render::extract_resource::ExtractResourcePlugin; +use bevy::render::RenderApp; use bevy_xr::session::{ - status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionExiting, XrStatus, + status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionExiting, XrSharedStatus, + XrStatus, }; use openxr::AnyGraphics; @@ -28,10 +31,11 @@ impl Plugin for OxrSessionPlugin { run_session_status_schedules.in_set(OxrPreUpdateSet::HandleEvents), ); app.add_systems(XrSessionExiting, clean_session); - app.add_systems(XrRenderSessionEnding, |mut cmds: Commands| { - cmds.remove_resource::(); - cmds.remove_resource::(); - }); + app.sub_app_mut(RenderApp) + .add_systems(XrRenderSessionEnding, |mut cmds: Commands| { + // cmds.remove_resource::(); + cmds.remove_resource::(); + }); app.add_systems( PreUpdate, handle_stopping_state.run_if(status_changed_to(XrStatus::Stopping)), @@ -44,9 +48,13 @@ fn handle_stopping_state(session: Res, session_started: Res(); - cmds.insert_resource(OxrCleanupSession(true)); +fn clean_session(world: &mut World) { + world.insert_resource(OxrCleanupSession(true)); + // It should be impossible to call this if the session is Unavailable + world + .get_resource::() + .unwrap() + .set(XrStatus::Available); } fn run_session_status_schedules(world: &mut World) { @@ -62,6 +70,11 @@ fn run_session_status_schedules(world: &mut World) { OxrSessionStatusEvent::AboutToBeDestroyed => { world.run_schedule(XrSessionExiting); world.run_system_once(apply_deferred); + if let Some(sess) = world.remove_resource::() { + // unsafe { + // (sess.instance().fp().destroy_session)(sess.as_raw()); + // } + } } } } @@ -80,6 +93,11 @@ pub struct OxrSession( /// This is so that we can still operate on functions that don't take [`AnyGraphics`] as the generic. pub(crate) GraphicsWrap, ); +impl Drop for OxrSession { + fn drop(&mut self) { + info!("dropping session"); + } +} impl GraphicsType for OxrSession { type Inner = openxr::Session; diff --git a/crates/bevy_xr/src/session.rs b/crates/bevy_xr/src/session.rs index 004d2be..76e209b 100644 --- a/crates/bevy_xr/src/session.rs +++ b/crates/bevy_xr/src/session.rs @@ -13,10 +13,10 @@ impl Plugin for XrSessionPlugin { .add_event::() .add_event::() .add_event::() - .add_systems( - PreUpdate, - handle_session.run_if(resource_exists::), - ); + // .add_systems( + // PreUpdate, + // 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. From 5f5fd152bbc4c086166a9f26e2f9781a87ab799e Mon Sep 17 00:00:00 2001 From: Schmarni Date: Wed, 29 May 2024 08:26:52 +0200 Subject: [PATCH 4/7] add resource to disable auto session creation and change autocreation to disable itself after the each autocreation Signed-off-by: Schmarni --- crates/bevy_xr/src/session.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/crates/bevy_xr/src/session.rs b/crates/bevy_xr/src/session.rs index 76e209b..9da4b2a 100644 --- a/crates/bevy_xr/src/session.rs +++ b/crates/bevy_xr/src/session.rs @@ -6,6 +6,7 @@ pub struct XrSessionPlugin; impl Plugin for XrSessionPlugin { fn build(&self, app: &mut App) { + app.init_resource::(); app.init_schedule(XrSessionCreated); app.init_schedule(XrSessionExiting); app.add_event::() @@ -13,10 +14,10 @@ impl Plugin for XrSessionPlugin { .add_event::() .add_event::() .add_event::() - // .add_systems( - // PreUpdate, - // handle_session.run_if(resource_exists::), - /* ) */; + .add_systems( + PreUpdate, + 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. @@ -26,6 +27,17 @@ impl Plugin for XrSessionPlugin { } } +/// Automatically starts session when it's available, gets set to false after the start event was +/// sent +#[derive(Clone, Copy, Resource, Deref, DerefMut)] +pub struct XrCreateSessionWhenAvailabe(pub bool); + +impl Default for XrCreateSessionWhenAvailabe { + fn default() -> Self { + XrCreateSessionWhenAvailabe(true) + } +} + #[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct XrSessionCreated; @@ -79,15 +91,19 @@ pub fn handle_session( mut previous_status: Local>, mut create_session: EventWriter, mut begin_session: EventWriter, - mut end_session: EventWriter, + // mut end_session: EventWriter, mut destroy_session: EventWriter, + mut should_start_session: ResMut, ) { let current_status = status.get(); if *previous_status != Some(current_status) { match current_status { XrStatus::Unavailable => {} XrStatus::Available => { - create_session.send_default(); + if **should_start_session { + create_session.send_default(); + **should_start_session = false; + } } XrStatus::Idle => {} XrStatus::Ready => { From 40c767c2d242972227e5af178c07e0f162e825e4 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Thu, 30 May 2024 11:14:03 +0200 Subject: [PATCH 5/7] remove point light from sessions example and other small changes Signed-off-by: Schmarni --- crates/bevy_openxr/examples/sessions.rs | 10 +--------- crates/bevy_openxr/src/openxr/action_set_syncing.rs | 2 +- crates/bevy_openxr/src/openxr/init.rs | 7 +++++-- crates/bevy_openxr/src/openxr/session.rs | 7 +------ 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/crates/bevy_openxr/examples/sessions.rs b/crates/bevy_openxr/examples/sessions.rs index e3ca3e5..b85a2d9 100644 --- a/crates/bevy_openxr/examples/sessions.rs +++ b/crates/bevy_openxr/examples/sessions.rs @@ -10,6 +10,7 @@ fn main() { .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup) .add_systems(Update, handle_input) + .insert_resource(AmbientLight::default()) .run(); } @@ -62,15 +63,6 @@ fn setup( 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_set_syncing.rs b/crates/bevy_openxr/src/openxr/action_set_syncing.rs index 9ff3ddb..6b04224 100644 --- a/crates/bevy_openxr/src/openxr/action_set_syncing.rs +++ b/crates/bevy_openxr/src/openxr/action_set_syncing.rs @@ -1,4 +1,4 @@ -use crate::{init::OxrPreUpdateSet, resources::OxrSession}; +use crate::{init::OxrPreUpdateSet, session::OxrSession}; use bevy::prelude::*; use bevy_xr::session::session_running; diff --git a/crates/bevy_openxr/src/openxr/init.rs b/crates/bevy_openxr/src/openxr/init.rs index 0306feb..c9200ed 100644 --- a/crates/bevy_openxr/src/openxr/init.rs +++ b/crates/bevy_openxr/src/openxr/init.rs @@ -494,8 +494,6 @@ pub fn end_xr_session(session: Res, session_started: Res() { + // This is needed because there is one space that survives the session exit schedule and + // holds on to the session. this causes an error message but does not seem to cause any + // actuall issues. unsafe { (sess.instance().fp().destroy_session)(sess.as_raw()); } + // leaking the session so that it does not call destroy_session at a later point. might not + // actually be needed. Box::leak(Box::new(sess)); } } diff --git a/crates/bevy_openxr/src/openxr/session.rs b/crates/bevy_openxr/src/openxr/session.rs index 9a65ae8..f770b91 100644 --- a/crates/bevy_openxr/src/openxr/session.rs +++ b/crates/bevy_openxr/src/openxr/session.rs @@ -33,7 +33,6 @@ impl Plugin for OxrSessionPlugin { app.add_systems(XrSessionExiting, clean_session); app.sub_app_mut(RenderApp) .add_systems(XrRenderSessionEnding, |mut cmds: Commands| { - // cmds.remove_resource::(); cmds.remove_resource::(); }); app.add_systems( @@ -70,11 +69,7 @@ fn run_session_status_schedules(world: &mut World) { OxrSessionStatusEvent::AboutToBeDestroyed => { world.run_schedule(XrSessionExiting); world.run_system_once(apply_deferred); - if let Some(sess) = world.remove_resource::() { - // unsafe { - // (sess.instance().fp().destroy_session)(sess.as_raw()); - // } - } + world.remove_resource::(); } } } From 0e2a5dbf6635ceaac596e61f70f7340fc13d9636 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 31 May 2024 10:48:03 +0200 Subject: [PATCH 6/7] merge both Exit schedules, fix reference space living after the session exits in the render world and general cleanup Signed-off-by: Schmarni --- .../src/openxr/features/handtracking.rs | 10 +++--- crates/bevy_openxr/src/openxr/init.rs | 22 +++--------- .../bevy_openxr/src/openxr/reference_space.rs | 16 +++++---- crates/bevy_openxr/src/openxr/resources.rs | 6 ---- crates/bevy_openxr/src/openxr/session.rs | 34 ++++++++++++------- crates/bevy_xr/src/session.rs | 5 +-- 6 files changed, 42 insertions(+), 51 deletions(-) diff --git a/crates/bevy_openxr/src/openxr/features/handtracking.rs b/crates/bevy_openxr/src/openxr/features/handtracking.rs index f681cda..f784c3b 100644 --- a/crates/bevy_openxr/src/openxr/features/handtracking.rs +++ b/crates/bevy_openxr/src/openxr/features/handtracking.rs @@ -39,7 +39,7 @@ fn spawn_default_hands( session: Res, root: Query>, ) { - info!("spawning hands"); + dbg!("spawning default hands"); let Ok(root) = root.get_single() else { error!("unable to get tracking root, skipping hand creation"); return; @@ -71,6 +71,7 @@ fn spawn_default_hands( for bone in HandBone::get_all_bones() { let bone_left = cmds .spawn(( + DefaultHandBone, SpatialBundle::default(), bone, HandBoneRadius(0.0), @@ -79,6 +80,7 @@ fn spawn_default_hands( .id(); let bone_right = cmds .spawn(( + DefaultHandBone, SpatialBundle::default(), bone, HandBoneRadius(0.0), @@ -107,15 +109,15 @@ fn spawn_default_hands( #[derive(Component)] struct DefaultHandTracker; #[derive(Component)] -struct DefaultHandBones; +struct DefaultHandBone; #[allow(clippy::type_complexity)] fn clean_up_default_hands( mut cmds: Commands, - query: Query, With)>>, + query: Query, With)>>, ) { for e in &query { - info!("removing_hand_entity"); + dbg!("removing default hand entity"); cmds.entity(e).despawn_recursive(); } } diff --git a/crates/bevy_openxr/src/openxr/init.rs b/crates/bevy_openxr/src/openxr/init.rs index c9200ed..32d1c84 100644 --- a/crates/bevy_openxr/src/openxr/init.rs +++ b/crates/bevy_openxr/src/openxr/init.rs @@ -23,7 +23,6 @@ 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::XrSessionExiting; use bevy_xr::session::XrSharedStatus; use bevy_xr::session::XrStatus; @@ -167,7 +166,7 @@ impl Plugin for OxrInitPlugin { Render, destroy_xr_session_render .run_if(resource_equals(OxrCleanupSession(true))) - .after(RenderSet::ExtractCommands), + .after(RenderSet::Cleanup), ) .add_systems( ExtractSchedule, @@ -455,7 +454,6 @@ pub fn create_xr_session( system_id: Res, mut commands: Commands, ) { - info!("creating session!"); match init_xr_session( device.wgpu_device(), &instance, @@ -481,7 +479,6 @@ pub fn create_xr_session( pub fn begin_xr_session(session: Res, session_started: Res) { let _span = info_span!("xr_begin_session"); - info!("begining session!"); session .begin(openxr::ViewConfigurationType::PRIMARY_STEREO) .expect("Failed to begin session"); @@ -490,7 +487,6 @@ pub fn begin_xr_session(session: Res, session_started: Res, session_started: Res) { let _span = info_span!("xr_end_session"); - info!("ending session!"); session .request_exit() .expect("Failed to request session exit"); @@ -553,7 +549,7 @@ pub fn poll_events( SessionState::STOPPING => XrStatus::Stopping, SessionState::EXITING | SessionState::LOSS_PENDING => { session_status_events.send(OxrSessionStatusEvent::AboutToBeDestroyed); - info!("sending destroy info"); + info!("sending destroy info"); XrStatus::Exiting } _ => unreachable!(), @@ -583,17 +579,7 @@ pub fn destroy_xr_session_render(world: &mut World) { world.remove_resource::(); world.remove_resource::(); world.remove_resource::(); - world.run_schedule(XrRenderSessionEnding); + world.run_schedule(XrSessionExiting); world.run_system_once(apply_deferred); - if let Some(sess) = world.remove_resource::() { - // This is needed because there is one space that survives the session exit schedule and - // holds on to the session. this causes an error message but does not seem to cause any - // actuall issues. - unsafe { - (sess.instance().fp().destroy_session)(sess.as_raw()); - } - // leaking the session so that it does not call destroy_session at a later point. might not - // actually be needed. - Box::leak(Box::new(sess)); - } + world.remove_resource::(); } diff --git a/crates/bevy_openxr/src/openxr/reference_space.rs b/crates/bevy_openxr/src/openxr/reference_space.rs index 2516c03..96a4d61 100644 --- a/crates/bevy_openxr/src/openxr/reference_space.rs +++ b/crates/bevy_openxr/src/openxr/reference_space.rs @@ -2,11 +2,12 @@ use std::sync::Arc; use bevy::{ prelude::*, - render::extract_resource::{ExtractResource, ExtractResourcePlugin}, -}; -use bevy_xr::session::{ - status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionExiting, XrStatus, + render::{ + extract_resource::{ExtractResource, ExtractResourcePlugin}, + RenderApp, + }, }; +use bevy_xr::session::{status_changed_to, XrSessionCreated, XrSessionExiting, XrStatus}; use crate::{init::OxrPreUpdateSet, session::OxrSession}; @@ -33,11 +34,14 @@ pub struct OxrReferenceSpace(pub openxr::Space); impl Plugin for OxrReferenceSpacePlugin { fn build(&self, app: &mut App) { - app.insert_resource(OxrDefaultPrimaryReferenceSpaceType(self.default_primary_ref_space)); + app.insert_resource(OxrDefaultPrimaryReferenceSpaceType( + self.default_primary_ref_space, + )); app.add_plugins(ExtractResourcePlugin::::default()); app.add_systems(XrSessionCreated, set_primary_ref_space); app.add_systems(XrSessionExiting, cleanup); - app.add_systems(XrRenderSessionEnding, cleanup); + app.sub_app_mut(RenderApp) + .add_systems(XrSessionExiting, cleanup); } } diff --git a/crates/bevy_openxr/src/openxr/resources.rs b/crates/bevy_openxr/src/openxr/resources.rs index db8b07d..cc143d7 100644 --- a/crates/bevy_openxr/src/openxr/resources.rs +++ b/crates/bevy_openxr/src/openxr/resources.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use bevy::prelude::*; use bevy::render::extract_resource::ExtractResource; -use openxr::AnyGraphics; use crate::error::OxrError; use crate::graphics::*; @@ -217,11 +216,6 @@ pub struct OxrFrameWaiter(pub openxr::FrameWaiter); /// Graphics agnostic wrapper around [openxr::Swapchain] #[derive(Resource)] pub struct OxrSwapchain(pub GraphicsWrap); -impl Drop for OxrSwapchain { - fn drop(&mut self) { - info!("Dropping Swapchain"); - } -} impl GraphicsType for OxrSwapchain { type Inner = openxr::Swapchain; diff --git a/crates/bevy_openxr/src/openxr/session.rs b/crates/bevy_openxr/src/openxr/session.rs index f770b91..d3125a5 100644 --- a/crates/bevy_openxr/src/openxr/session.rs +++ b/crates/bevy_openxr/src/openxr/session.rs @@ -3,13 +3,12 @@ use crate::resources::{ OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSessionStarted, OxrSwapchain, }; use crate::types::{Result, SwapchainCreateInfo}; -use bevy::ecs::system::{RunSystemOnce, SystemState}; +use bevy::ecs::event::ManualEventReader; +use bevy::ecs::system::RunSystemOnce; use bevy::prelude::*; -use bevy::render::extract_resource::ExtractResourcePlugin; use bevy::render::RenderApp; use bevy_xr::session::{ - status_changed_to, XrRenderSessionEnding, XrSessionCreated, XrSessionExiting, XrSharedStatus, - XrStatus, + status_changed_to, XrSessionCreated, XrSessionExiting, XrSharedStatus, XrStatus, }; use openxr::AnyGraphics; @@ -32,7 +31,7 @@ impl Plugin for OxrSessionPlugin { ); app.add_systems(XrSessionExiting, clean_session); app.sub_app_mut(RenderApp) - .add_systems(XrRenderSessionEnding, |mut cmds: Commands| { + .add_systems(XrSessionExiting, |mut cmds: Commands| { cmds.remove_resource::(); }); app.add_systems( @@ -56,10 +55,23 @@ fn clean_session(world: &mut World) { .set(XrStatus::Available); } +#[derive(Resource, Default)] +struct SessionStatusReader(ManualEventReader); + 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::>(); + let mut reader = world + .remove_resource::() + .unwrap_or_default(); + + let events = reader + .0 + .read( + world + .get_resource::>() + .unwrap(), + ) + .copied() + .collect::>(); for e in events.iter() { match e { OxrSessionStatusEvent::Created => { @@ -73,6 +85,7 @@ fn run_session_status_schedules(world: &mut World) { } } } + world.insert_resource(reader); } /// Graphics agnostic wrapper around [openxr::Session]. @@ -88,11 +101,6 @@ pub struct OxrSession( /// This is so that we can still operate on functions that don't take [`AnyGraphics`] as the generic. pub(crate) GraphicsWrap, ); -impl Drop for OxrSession { - fn drop(&mut self) { - info!("dropping session"); - } -} impl GraphicsType for OxrSession { type Inner = openxr::Session; diff --git a/crates/bevy_xr/src/session.rs b/crates/bevy_xr/src/session.rs index 9da4b2a..e70b835 100644 --- a/crates/bevy_xr/src/session.rs +++ b/crates/bevy_xr/src/session.rs @@ -23,7 +23,7 @@ impl Plugin for XrSessionPlugin { // This is in finnish because we need the RenderPlugin to already be added. app.get_sub_app_mut(RenderApp) .unwrap() - .init_schedule(XrRenderSessionEnding); + .init_schedule(XrSessionExiting); } } @@ -44,9 +44,6 @@ pub struct XrSessionCreated; #[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct XrSessionExiting; -#[derive(ScheduleLabel, Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub struct XrRenderSessionEnding; - #[derive(Event, Clone, Copy, Deref)] pub struct XrStatusChanged(pub XrStatus); From dd1293c0fc472a044df3d44c8bea3c7d0ff10c6f Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 31 May 2024 11:19:13 +0200 Subject: [PATCH 7/7] fix compile errors after rebase Signed-off-by: Schmarni --- crates/bevy_xr_utils/src/xr_utils_actions.rs | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/bevy_xr_utils/src/xr_utils_actions.rs b/crates/bevy_xr_utils/src/xr_utils_actions.rs index 4a0cef5..ded0b19 100644 --- a/crates/bevy_xr_utils/src/xr_utils_actions.rs +++ b/crates/bevy_xr_utils/src/xr_utils_actions.rs @@ -1,9 +1,9 @@ //! This plugin and module are here to ease the creation of actions withing openxr //! The general idea is any plugin can create entities in startup before XRUtilsActionSystemSet::CreateEvents //! this plugin will then create the neccessary actions sets, actions, and bindings and get them ready for use. -//! +//! //! example creating actions -//! +//! //! //create a set //! let set = commands //! .spawn(( @@ -39,10 +39,10 @@ //! //TODO look into a better system //! commands.entity(action).add_child(binding); //! commands.entity(set).add_child(action); -//! +//! //! then you can read the action states after XRUtilsActionSystemSet::SyncActionStates //! for example -//! +//! //! fn read_action_with_marker_component( //! mut action_query: Query<&XRUtilsActionState, With>, //! ) { @@ -51,13 +51,12 @@ //! info!("action state is: {:?}", state); //! } //! } -//! -//! +//! +//! use bevy::prelude::*; use bevy_openxr::{ - action_binding::OxrSuggestActionBinding, - action_set_attaching::OxrAttachActionSet, - resources::{OxrInstance, OxrSession}, + action_binding::OxrSuggestActionBinding, action_set_attaching::OxrAttachActionSet, + resources::OxrInstance, session::OxrSession, }; use openxr::{ActiveActionSet, Path, Vector2f}; use std::borrow::Cow; @@ -65,7 +64,10 @@ use std::borrow::Cow; pub struct XRUtilsActionsPlugin; impl Plugin for XRUtilsActionsPlugin { fn build(&self, app: &mut App) { - app.add_systems(Startup, create_openxr_events.in_set(XRUtilsActionSystemSet::CreateEvents)); + app.add_systems( + Startup, + create_openxr_events.in_set(XRUtilsActionSystemSet::CreateEvents), + ); app.add_systems(Update, sync_active_action_sets); app.add_systems( Update,