refactor(openxr): make environment blend modes a completely runtime feature, like it should and remove the fb_passthrough plugin from the default oxr plugins as quests now support blendmode based passthrough

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-07-21 02:30:34 +02:00
committed by Schmarni
parent 9569f591ac
commit 62cf605f4a
13 changed files with 84 additions and 60 deletions

View File

@@ -13,10 +13,11 @@ fn main() -> AppExit {
DefaultPlugins.build().disable::<PipelinedRenderingPlugin>(),
))
.insert_resource(OxrSessionConfig {
blend_modes: Some(vec![
blend_mode_preference: vec![
EnvironmentBlendMode::ALPHA_BLEND,
EnvironmentBlendMode::ADDITIVE,
EnvironmentBlendMode::OPAQUE,
]),
],
..default()
})
.add_plugins(bevy_mod_xr::hand_debug_gizmos::HandGizmosPlugin)

View File

@@ -92,6 +92,6 @@ categories = [
# https://developer.android.com/studio/publish/app-signing
#
# !! IMPORTANT !!
[package.metadata.android.signing.release]
path = "./hotham_examples.keystore"
keystore_password = "chomsky-vigilant-spa"
# [package.metadata.android.signing.release]
# path = "./hotham_examples.keystore"
# keystore_password = "chomsky-vigilant-spa"

View File

@@ -16,6 +16,7 @@ fn main() {
..default()
}))
.add_plugins(bevy_mod_xr::hand_debug_gizmos::HandGizmosPlugin)
.add_plugins(bevy_mod_openxr::features::fb_passthrough::OxrFbPassthroughPlugin)
.add_systems(Startup, setup)
.add_systems(Update, modify_msaa)
.insert_resource(AmbientLight {

View File

@@ -19,12 +19,13 @@ fn main() {
..OxrInitPlugin::default()
}))
.insert_resource(OxrSessionConfig {
blend_modes: Some({
blend_mode_preference: {
vec![
EnvironmentBlendMode::ALPHA_BLEND,
EnvironmentBlendMode::ADDITIVE,
EnvironmentBlendMode::OPAQUE,
]
}),
},
..OxrSessionConfig::default()
})
.insert_resource(ClearColor(Color::NONE))

View File

@@ -0,0 +1,39 @@
use bevy::{ecs::resource::Resource, render::extract_resource::ExtractResource};
use openxr::EnvironmentBlendMode;
#[derive(Resource, ExtractResource, Clone)]
pub struct OxrEnvironmentBlendModes {
available_blend_modes: Vec<EnvironmentBlendMode>,
current_blend_mode: EnvironmentBlendMode,
}
impl OxrEnvironmentBlendModes {
pub(crate) fn new(
available_modes: Vec<EnvironmentBlendMode>,
preferences: &[EnvironmentBlendMode],
) -> Option<OxrEnvironmentBlendModes> {
let blend_mode = preferences.iter().find(|m| available_modes.contains(m))?;
Some(Self {
available_blend_modes: available_modes,
current_blend_mode: *blend_mode,
})
}
/// returns whether the blend_mode was changed
pub fn set_blend_mode(&mut self, blend_mode: EnvironmentBlendMode) -> bool {
if self.available_blend_modes.contains(&blend_mode) {
self.current_blend_mode = blend_mode;
return true;
}
false
}
pub fn blend_mode(&self) -> EnvironmentBlendMode {
self.current_blend_mode
}
pub fn available_blend_modes(&self) -> &[EnvironmentBlendMode] {
&self.available_blend_modes
}
}

View File

@@ -11,9 +11,9 @@ use crate::resources::*;
use crate::session::OxrSession;
use crate::types::Result as OxrResult;
pub struct OxrPassthroughPlugin;
pub struct OxrFbPassthroughPlugin;
impl Plugin for OxrPassthroughPlugin {
impl Plugin for OxrFbPassthroughPlugin {
fn build(&self, app: &mut App) {
if app
.world()
@@ -94,12 +94,12 @@ pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> OxrR
return Ok(false);
}
unsafe {
let mut hand = openxr::sys::SystemPassthroughProperties2FB {
let mut properties = openxr::sys::SystemPassthroughProperties2FB {
ty: SystemPassthroughProperties2FB::TYPE,
next: std::ptr::null(),
capabilities: PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
};
let mut p = openxr::sys::SystemProperties::out(&mut hand as *mut _ as _);
let mut p = openxr::sys::SystemProperties::out(&mut properties as *mut _ as _);
cvt((instance.fp().get_system_properties)(
instance.as_raw(),
system.0,
@@ -107,10 +107,10 @@ pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> OxrR
))?;
bevy::log::info!(
"From supports_passthrough: Passthrough capabilities: {:?}",
hand.capabilities
properties.capabilities
);
Ok(
(hand.capabilities & PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY)
(properties.capabilities & PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY)
== PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
)
}

View File

@@ -1,4 +1,4 @@
pub mod handtracking;
#[cfg(feature = "passthrough")]
pub mod passthrough;
pub mod fb_passthrough;
pub mod overlay;

View File

@@ -28,6 +28,7 @@ use crate::session::OxrSessionCreateNextChain;
use crate::types::Result as OxrResult;
use crate::types::*;
use super::environment_blend_mode::OxrEnvironmentBlendModes;
use super::exts::OxrEnabledExtensions;
use super::poll_events::OxrEventHandlerExt;
use super::poll_events::OxrEventIn;
@@ -66,7 +67,6 @@ impl Default for OxrInitPlugin {
app_info: default(),
exts: {
let mut exts = OxrExtensions::default();
exts.enable_fb_passthrough();
exts.enable_hand_tracking();
exts
},
@@ -104,6 +104,7 @@ impl Plugin for OxrInitPlugin {
debug_flags: self.render_debug_flags,
},
ExtractResourcePlugin::<OxrSessionStarted>::default(),
ExtractResourcePlugin::<OxrEnvironmentBlendModes>::default(),
))
.add_oxr_event_handler(handle_events)
.add_systems(
@@ -249,7 +250,7 @@ impl OxrInitPlugin {
// check available extensions and send a warning for any wanted extensions that aren't available.
for ext in available_exts.unavailable_exts(&self.exts) {
error!(
warn!(
"Extension \"{ext}\" not available in the current OpenXR runtime. Disabling extension."
);
}
@@ -273,13 +274,7 @@ impl OxrInitPlugin {
let exts = self.exts.clone() & available_exts;
let instance = entry.create_instance(
self.app_info.clone(),
exts.clone(),
// &["XR_APILAYER_LUNARG_api_dump"],
&[],
backend,
)?;
let instance = entry.create_instance(self.app_info.clone(), exts.clone(), &[], backend)?;
let instance_props = instance.properties()?;
info!(
@@ -362,7 +357,7 @@ fn init_xr_session(
system_id: openxr::SystemId,
chain: &mut OxrSessionCreateNextChain,
OxrSessionConfig {
blend_modes,
blend_mode_preference,
formats,
resolutions,
}: OxrSessionConfig,
@@ -374,6 +369,7 @@ fn init_xr_session(
OxrSwapchain,
OxrSwapchainImages,
OxrCurrentSessionConfig,
OxrEnvironmentBlendModes,
)> {
let (session, frame_waiter, frame_stream) =
unsafe { instance.create_session(system_id, graphics_info, chain)? };
@@ -461,25 +457,10 @@ fn init_xr_session(
instance.enumerate_environment_blend_modes(system_id, view_configuration_type)?;
// blend mode selection
let blend_mode = if let Some(wanted_blend_modes) = &blend_modes {
let mut blend_mode = None;
for wanted_blend_mode in wanted_blend_modes {
if available_blend_modes.contains(wanted_blend_mode) {
blend_mode = Some(*wanted_blend_mode);
break;
}
}
blend_mode
} else {
available_blend_modes.first().copied()
}
.ok_or(OxrError::NoAvailableBlendMode)?;
let blend_modes = OxrEnvironmentBlendModes::new(available_blend_modes, &blend_mode_preference)
.ok_or(OxrError::NoAvailableBlendMode)?;
let graphics_info = OxrCurrentSessionConfig {
blend_mode,
resolution,
format,
};
let graphics_info = OxrCurrentSessionConfig { resolution, format };
Ok((
session,
@@ -488,6 +469,7 @@ fn init_xr_session(
swapchain,
images,
graphics_info,
blend_modes,
))
}
@@ -508,7 +490,15 @@ pub fn create_xr_session(world: &mut World) {
session_config.clone(),
session_create_info.clone(),
) {
Ok((session, frame_waiter, frame_stream, swapchain, images, graphics_info)) => {
Ok((
session,
frame_waiter,
frame_stream,
swapchain,
images,
graphics_info,
blend_modes,
)) => {
world.insert_resource(session.clone());
world.insert_resource(frame_waiter);
world.insert_resource(images);
@@ -524,6 +514,7 @@ pub fn create_xr_session(world: &mut World) {
.expect("added by xr session plugin")
.clone(),
});
world.insert_resource(blend_modes);
}
Err(e) => error!("Failed to initialize XrSession: {e}"),
}

View File

@@ -14,14 +14,12 @@ use render::OxrRenderPlugin;
use resources::OxrInstance;
use session::OxrSession;
use self::{
features::{handtracking::HandTrackingPlugin, passthrough::OxrPassthroughPlugin},
reference_space::OxrReferenceSpacePlugin,
};
use self::{features::handtracking::HandTrackingPlugin, reference_space::OxrReferenceSpacePlugin};
pub mod action_binding;
pub mod action_set_attaching;
pub mod action_set_syncing;
pub mod environment_blend_mode;
pub mod error;
pub mod exts;
pub mod features;
@@ -59,13 +57,11 @@ pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
plugins
.build()
.disable::<RenderPlugin>()
// .disable::<PipelinedRenderingPlugin>()
.add_before::<RenderPlugin>(XrSessionPlugin { auto_handle: true })
.add_before::<RenderPlugin>(OxrInitPlugin::default())
.add(OxrEventsPlugin)
.add(OxrReferenceSpacePlugin::default())
.add(OxrRenderPlugin::default())
.add(OxrPassthroughPlugin)
.add(HandTrackingPlugin::default())
.add(XrCameraPlugin)
.add(action_set_attaching::OxrActionAttachingPlugin)
@@ -74,20 +70,14 @@ pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
.add(features::overlay::OxrOverlayPlugin)
.add(spaces::OxrSpatialPlugin)
.add(spaces::OxrSpacePatchingPlugin)
// .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,
present_mode: PresentMode::AutoNoVsync,
// title: self.app_info.name.clone(),
..default()
}),
// #[cfg(target_os = "android")]
// exit_condition: bevy::window::ExitCondition::DontExit,
#[cfg(target_os = "android")]
close_when_requested: true,
..default()
})
}

View File

@@ -22,6 +22,8 @@ use openxr::ViewStateFlags;
use crate::{init::should_run_frame_loop, resources::*};
use crate::{layer_builder::ProjectionLayer, session::OxrSession};
use super::environment_blend_mode::OxrEnvironmentBlendModes;
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
pub struct OxrRenderBegin;
@@ -393,7 +395,7 @@ pub fn end_frame(world: &mut World) {
let _span = debug_span!("xr_end_frame").entered();
if let Err(e) = frame_stream.end(
frame_state.predicted_display_time,
world.resource::<OxrCurrentSessionConfig>().blend_mode,
world.resource::<OxrEnvironmentBlendModes>().blend_mode(),
&layers,
) {
error!("Failed to end frame stream: {e}");

View File

@@ -332,7 +332,6 @@ pub struct OxrRenderLayers(pub Vec<Box<dyn LayerProvider + Send + Sync>>);
/// Resource storing graphics info for the currently running session.
#[derive(Clone, Copy, Resource, ExtractResource)]
pub struct OxrCurrentSessionConfig {
pub blend_mode: EnvironmentBlendMode,
pub resolution: UVec2,
pub format: wgpu::TextureFormat,
}
@@ -341,7 +340,7 @@ pub struct OxrCurrentSessionConfig {
/// This is used to store information from startup that is needed to create the session after the instance has been created.
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>>,
pub blend_mode_preference: 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.
@@ -350,7 +349,7 @@ pub struct OxrSessionConfig {
impl Default for OxrSessionConfig {
fn default() -> Self {
Self {
blend_modes: Some(vec![openxr::EnvironmentBlendMode::OPAQUE]),
blend_mode_preference: vec![openxr::EnvironmentBlendMode::OPAQUE],
formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]),
resolutions: default(),
}