From be6a053b55299310b7352f5c0bc53199cac368d3 Mon Sep 17 00:00:00 2001 From: Schmarni Date: Fri, 2 May 2025 16:43:39 +0200 Subject: [PATCH] refactor: create OxrSessionConfig and make that the only way to configure things like BlendModes Signed-off-by: Schmarni --- crates/bevy_openxr/examples/3d_scene.rs | 31 ++++++------ crates/bevy_openxr/examples/overlay.rs | 9 ++-- crates/bevy_openxr/examples/sessions.rs | 15 ++---- .../src/openxr/features/passthrough.rs | 48 ++++++++++--------- crates/bevy_openxr/src/openxr/init.rs | 37 +++++--------- crates/bevy_openxr/src/openxr/resources.rs | 32 +++++++++---- crates/bevy_openxr/src/openxr/types.rs | 9 ---- 7 files changed, 88 insertions(+), 93 deletions(-) diff --git a/crates/bevy_openxr/examples/3d_scene.rs b/crates/bevy_openxr/examples/3d_scene.rs index f405f2a..f291179 100644 --- a/crates/bevy_openxr/examples/3d_scene.rs +++ b/crates/bevy_openxr/examples/3d_scene.rs @@ -1,27 +1,28 @@ //! A simple 3D scene with light shining over a cube sitting on a plane. use bevy::{prelude::*, render::pipelined_rendering::PipelinedRenderingPlugin}; -use bevy_mod_openxr::{add_xr_plugins, init::OxrInitPlugin}; +use bevy_mod_openxr::{add_xr_plugins, resources::OxrSessionConfig}; use openxr::EnvironmentBlendMode; -fn main() { +fn main() -> AppExit { App::new() - .add_plugins( - add_xr_plugins(DefaultPlugins.build().disable::()).set( - OxrInitPlugin { - blend_modes: Some(vec![ - EnvironmentBlendMode::ALPHA_BLEND, - EnvironmentBlendMode::ADDITIVE, - EnvironmentBlendMode::OPAQUE, - ]), - ..Default::default() - }, - ), - ) + .add_plugins(add_xr_plugins( + // Disabling Pipelined Rendering should reduce latency a little bit for button inputs + // and increase accuracy for hand tracking, controller positions and similar, + // the views are updated right before rendering so they are as accurate as possible + DefaultPlugins.build().disable::(), + )) + .insert_resource(OxrSessionConfig { + blend_modes: Some(vec![ + EnvironmentBlendMode::ALPHA_BLEND, + EnvironmentBlendMode::OPAQUE, + ]), + ..default() + }) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup) .insert_resource(ClearColor(Color::NONE)) - .run(); + .run() } /// set up a simple 3D scene diff --git a/crates/bevy_openxr/examples/overlay.rs b/crates/bevy_openxr/examples/overlay.rs index 183b482..a2beb3e 100644 --- a/crates/bevy_openxr/examples/overlay.rs +++ b/crates/bevy_openxr/examples/overlay.rs @@ -3,7 +3,7 @@ use bevy::prelude::*; use bevy_mod_openxr::{ add_xr_plugins, features::overlay::OxrOverlaySessionEvent, init::OxrInitPlugin, - types::OxrExtensions, + resources::OxrSessionConfig, types::OxrExtensions, }; use openxr::EnvironmentBlendMode; @@ -16,14 +16,17 @@ fn main() { exts.extx_overlay = true; exts }, + ..OxrInitPlugin::default() + })) + .insert_resource(OxrSessionConfig { blend_modes: Some({ vec![ EnvironmentBlendMode::ALPHA_BLEND, EnvironmentBlendMode::OPAQUE, ] }), - ..OxrInitPlugin::default() - })) + ..OxrSessionConfig::default() + }) .insert_resource(ClearColor(Color::NONE)) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup) diff --git a/crates/bevy_openxr/examples/sessions.rs b/crates/bevy_openxr/examples/sessions.rs index 2b14816..c8e981e 100644 --- a/crates/bevy_openxr/examples/sessions.rs +++ b/crates/bevy_openxr/examples/sessions.rs @@ -1,24 +1,17 @@ //! A simple 3D scene with light shining over a cube sitting on a plane. use bevy::prelude::*; -use bevy_mod_openxr::{add_xr_plugins, init::OxrInitPlugin}; +use bevy_mod_openxr::add_xr_plugins; use bevy_mod_xr::session::{XrSessionPlugin, XrState}; -fn main() { +fn main() -> AppExit { App::new() - .add_plugins( - add_xr_plugins(DefaultPlugins) - .set(XrSessionPlugin { auto_handle: true }) - .set(OxrInitPlugin { - blend_modes: Some(vec![openxr::EnvironmentBlendMode::OPAQUE]), - ..Default::default() - }), - ) + .add_plugins(add_xr_plugins(DefaultPlugins).set(XrSessionPlugin { auto_handle: true })) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_systems(Startup, setup) .add_systems(Update, handle_input) .insert_resource(AmbientLight::default()) - .run(); + .run() } fn handle_input( diff --git a/crates/bevy_openxr/src/openxr/features/passthrough.rs b/crates/bevy_openxr/src/openxr/features/passthrough.rs index e69b9d4..1993fe5 100644 --- a/crates/bevy_openxr/src/openxr/features/passthrough.rs +++ b/crates/bevy_openxr/src/openxr/features/passthrough.rs @@ -5,6 +5,7 @@ use bevy::render::RenderSet; use openxr::sys::SystemPassthroughProperties2FB; use openxr::PassthroughCapabilityFlagsFB; +use crate::exts::OxrEnabledExtensions; use crate::layer_builder::PassthroughLayer; use crate::resources::*; use crate::session::OxrSession; @@ -14,25 +15,31 @@ pub struct OxrPassthroughPlugin; impl Plugin for OxrPassthroughPlugin { fn build(&self, app: &mut App) { - let resources = app + if app .world() - .get_resource::() - .and_then(|instance| { - app.world() - .get_resource::() - .map(|system_id| (instance, system_id)) - }); - if resources.is_some_and(|(instance, system)| { - supports_passthrough(instance, *system).is_ok_and(|s| s) - }) { - app.sub_app_mut(RenderApp).add_systems( - Render, - insert_passthrough - .in_set(RenderSet::PrepareAssets) - .run_if(resource_added::), - ); - } else { - error!("Passthrough is not supported with this runtime") + .get_resource::() + .is_some_and(|e| e.fb_passthrough) + { + let resources = app + .world() + .get_resource::() + .and_then(|instance| { + app.world() + .get_resource::() + .map(|system_id| (instance, system_id)) + }); + if resources.is_some_and(|(instance, system)| { + supports_passthrough(instance, *system).is_ok_and(|s| s) + }) { + app.sub_app_mut(RenderApp).add_systems( + Render, + insert_passthrough + .in_set(RenderSet::PrepareAssets) + .run_if(resource_added::), + ); + } else { + error!("Passthrough is not supported with this runtime") + } } } } @@ -82,10 +89,7 @@ pub fn create_passthrough( } #[inline] -pub fn supports_passthrough( - instance: &OxrInstance, - system: OxrSystemId, -) -> OxrResult { +pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> OxrResult { if instance.exts().fb_passthrough.is_none() { return Ok(false); } diff --git a/crates/bevy_openxr/src/openxr/init.rs b/crates/bevy_openxr/src/openxr/init.rs index 94673d4..45076a1 100644 --- a/crates/bevy_openxr/src/openxr/init.rs +++ b/crates/bevy_openxr/src/openxr/init.rs @@ -54,14 +54,8 @@ pub struct OxrInitPlugin { /// Extensions wanted for this session. // TODO!() This should be changed to take a simpler list of features wanted that this crate supports. i.e. hand tracking pub exts: OxrExtensions, - /// List of blend modes the openxr session can use. If [None], pick the first available blend mode. - pub blend_modes: Option>, /// List of backends the openxr session can use. If [None], pick the first available backend. pub backends: Option>, - /// List of formats the openxr session can use. If [None], pick the first available format - pub formats: Option>, - /// List of resolutions that the openxr swapchain can use. If [None] pick the first available resolution. - pub resolutions: Option>, /// Passed into the render plugin when added to the app. pub synchronous_pipeline_compilation: bool, pub render_debug_flags: RenderDebugFlags, @@ -76,10 +70,7 @@ impl Default for OxrInitPlugin { exts.enable_hand_tracking(); exts }, - blend_modes: Some(vec![openxr::EnvironmentBlendMode::OPAQUE]), backends: default(), - formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]), - resolutions: default(), synchronous_pipeline_compilation: false, render_debug_flags: default(), } @@ -89,13 +80,14 @@ impl Default for OxrInitPlugin { impl Plugin for OxrInitPlugin { fn build(&self, app: &mut App) { app.add_event::(); + app.init_resource::(); match self.init_xr() { Ok(( instance, system_id, WgpuGraphics(device, queue, adapter_info, adapter, wgpu_instance), - session_create_info, enabled_exts, + graphics_info, )) => { app.insert_resource(enabled_exts) .add_plugins(( @@ -150,7 +142,7 @@ impl Plugin for OxrInitPlugin { unfocused_mode: UpdateMode::Continuous, }) .insert_resource(OxrSessionStarted(false)) - .insert_non_send_resource(session_create_info) + .insert_non_send_resource(graphics_info) .init_non_send_resource::(); app.world_mut() @@ -215,8 +207,8 @@ impl OxrInitPlugin { OxrInstance, OxrSystemId, WgpuGraphics, - SessionConfigInfo, OxrEnabledExtensions, + SessionGraphicsCreateInfo, )> { #[cfg(windows)] let entry = OxrEntry(openxr::Entry::linked()); @@ -282,19 +274,12 @@ impl OxrInitPlugin { let (graphics, graphics_info) = instance.init_graphics(system_id)?; - let session_create_info = SessionConfigInfo { - blend_modes: self.blend_modes.clone(), - formats: self.formats.clone(), - resolutions: self.resolutions.clone(), - graphics_info, - }; - Ok(( instance, OxrSystemId(system_id), graphics, - session_create_info, OxrEnabledExtensions(exts), + graphics_info, )) } } @@ -349,12 +334,12 @@ fn init_xr_session( instance: &OxrInstance, system_id: openxr::SystemId, chain: &mut OxrSessionCreateNextChain, - SessionConfigInfo { + OxrSessionConfig { blend_modes, formats, resolutions, - graphics_info, - }: SessionConfigInfo, + }: OxrSessionConfig, + graphics_info: SessionGraphicsCreateInfo, ) -> OxrResult<( OxrSession, OxrFrameWaiter, @@ -485,14 +470,16 @@ pub fn create_xr_session(world: &mut World) { .unwrap(); let device = world.resource::(); let instance = world.resource::(); - let create_info = world.non_send_resource::(); + let session_config = world.resource::(); + let session_create_info = world.non_send_resource::(); let system_id = world.resource::(); match init_xr_session( device.wgpu_device(), instance, **system_id, &mut chain, - create_info.clone(), + session_config.clone(), + session_create_info.clone(), ) { Ok((session, frame_waiter, frame_stream, swapchain, images, graphics_info)) => { world.insert_resource(session.clone()); diff --git a/crates/bevy_openxr/src/openxr/resources.rs b/crates/bevy_openxr/src/openxr/resources.rs index aa78f14..3637ab5 100644 --- a/crates/bevy_openxr/src/openxr/resources.rs +++ b/crates/bevy_openxr/src/openxr/resources.rs @@ -106,13 +106,13 @@ impl OxrInstance { pub fn init_graphics( &self, system_id: openxr::SystemId, - ) -> OxrResult<(WgpuGraphics, SessionCreateInfo)> { + ) -> OxrResult<(WgpuGraphics, SessionGraphicsCreateInfo)> { graphics_match!( self.1; _ => { let (graphics, session_info) = Api::init_graphics(&self.2, self, system_id)?; - Ok((graphics, SessionCreateInfo(Api::wrap(session_info)))) + Ok((graphics, SessionGraphicsCreateInfo(Api::wrap(session_info)))) } ) } @@ -127,12 +127,12 @@ impl OxrInstance { pub unsafe fn create_session( &self, system_id: openxr::SystemId, - info: SessionCreateInfo, + info: SessionGraphicsCreateInfo, chain: &mut OxrSessionCreateNextChain, ) -> OxrResult<(OxrSession, OxrFrameWaiter, OxrFrameStream)> { if !info.0.using_graphics_of_val(&self.1) { return OxrResult::Err(OxrError::GraphicsBackendMismatch { - item: std::any::type_name::(), + item: std::any::type_name::(), backend: info.0.graphics_name(), expected_backend: self.1.graphics_name(), }); @@ -336,17 +336,33 @@ pub struct OxrGraphicsInfo { pub format: wgpu::TextureFormat, } -#[derive(Clone)] +#[derive(Clone, Resource, Debug)] /// This is used to store information from startup that is needed to create the session after the instance has been created. -pub struct SessionConfigInfo { +pub struct OxrSessionConfig { /// List of blend modes the openxr session can use. If [None], pick the first available blend mode. pub blend_modes: Option>, /// List of formats the openxr session can use. If [None], pick the first available format pub formats: Option>, /// List of resolutions that the openxr swapchain can use. If [None] pick the first available resolution. pub resolutions: Option>, - /// Graphics info used to create a session. - pub graphics_info: SessionCreateInfo, +} +impl Default for OxrSessionConfig { + fn default() -> Self { + Self { + blend_modes: Some(vec![openxr::EnvironmentBlendMode::OPAQUE]), + formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]), + resolutions: default(), + } + } +} + +/// Info needed to create a session. Mostly contains graphics info. +/// This is an API agnostic version of [openxr::Graphics::SessionCreateInfo] used for some of this library's functions +#[derive(Clone)] +pub struct SessionGraphicsCreateInfo(pub GraphicsWrap); + +impl GraphicsType for SessionGraphicsCreateInfo { + type Inner = G::SessionCreateInfo; } #[derive(ExtractResource, Resource, Clone, Default)] diff --git a/crates/bevy_openxr/src/openxr/types.rs b/crates/bevy_openxr/src/openxr/types.rs index b70e4bd..7ad5b32 100644 --- a/crates/bevy_openxr/src/openxr/types.rs +++ b/crates/bevy_openxr/src/openxr/types.rs @@ -87,12 +87,3 @@ impl TryFrom for openxr::SwapchainCreateInf }) } } - -/// Info needed to create a session. Mostly contains graphics info. -/// This is an API agnostic version of [openxr::Graphics::SessionCreateInfo] used for some of this library's functions -#[derive(Clone)] -pub struct SessionCreateInfo(pub GraphicsWrap); - -impl GraphicsType for SessionCreateInfo { - type Inner = G::SessionCreateInfo; -}