refactor: create OxrSessionConfig and make that the only way to configure things like BlendModes

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-05-02 16:43:39 +02:00
parent 4074d4be7c
commit be6a053b55
7 changed files with 88 additions and 93 deletions

View File

@@ -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::<PipelinedRenderingPlugin>()).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::<PipelinedRenderingPlugin>(),
))
.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

View File

@@ -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)

View File

@@ -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(

View File

@@ -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::<OxrInstance>()
.and_then(|instance| {
app.world()
.get_resource::<OxrSystemId>()
.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::<OxrSession>),
);
} else {
error!("Passthrough is not supported with this runtime")
.get_resource::<OxrEnabledExtensions>()
.is_some_and(|e| e.fb_passthrough)
{
let resources = app
.world()
.get_resource::<OxrInstance>()
.and_then(|instance| {
app.world()
.get_resource::<OxrSystemId>()
.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::<OxrSession>),
);
} 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<bool> {
pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> OxrResult<bool> {
if instance.exts().fb_passthrough.is_none() {
return Ok(false);
}

View File

@@ -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<Vec<EnvironmentBlendMode>>,
/// List of backends the openxr session can use. If [None], pick the first available backend.
pub backends: Option<Vec<GraphicsBackend>>,
/// List of formats the openxr session can use. If [None], pick the first available format
pub formats: Option<Vec<wgpu::TextureFormat>>,
/// List of resolutions that the openxr swapchain can use. If [None] pick the first available resolution.
pub resolutions: Option<Vec<UVec2>>,
/// 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::<OxrInteractionProfileChanged>();
app.init_resource::<OxrSessionConfig>();
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::<OxrSessionCreateNextChain>();
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::<RenderDevice>();
let instance = world.resource::<OxrInstance>();
let create_info = world.non_send_resource::<SessionConfigInfo>();
let session_config = world.resource::<OxrSessionConfig>();
let session_create_info = world.non_send_resource::<SessionGraphicsCreateInfo>();
let system_id = world.resource::<OxrSystemId>();
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());

View File

@@ -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::<SessionCreateInfo>(),
item: std::any::type_name::<SessionGraphicsCreateInfo>(),
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<Vec<EnvironmentBlendMode>>,
/// List of formats the openxr session can use. If [None], pick the first available format
pub formats: Option<Vec<wgpu::TextureFormat>>,
/// List of resolutions that the openxr swapchain can use. If [None] pick the first available resolution.
pub resolutions: Option<Vec<UVec2>>,
/// 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<Self>);
impl GraphicsType for SessionGraphicsCreateInfo {
type Inner<G: GraphicsExt> = G::SessionCreateInfo;
}
#[derive(ExtractResource, Resource, Clone, Default)]

View File

@@ -87,12 +87,3 @@ impl<G: GraphicsExt> TryFrom<SwapchainCreateInfo> 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<Self>);
impl GraphicsType for SessionCreateInfo {
type Inner<G: GraphicsExt> = G::SessionCreateInfo;
}