diff --git a/examples/android/manifest.yaml b/examples/android/manifest.yaml
index 9a6118c..7622de3 100644
--- a/examples/android/manifest.yaml
+++ b/examples/android/manifest.yaml
@@ -3,6 +3,15 @@ android:
- "runtime_libs"
manifest:
package: "org.bevyengine.example_openxr_android"
+ uses_feature:
+ - name: "android.hardware.vr.headtracking"
+ required: true
+ - name: "oculus.software.handtracking"
+ required: true
+ - name: "com.oculus.feature.PASSTHROUGH"
+ required: true
+ - name: "com.oculus.experimental.enabled"
+ required: true
application:
label: "Bevy Openxr Android"
theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
@@ -14,7 +23,7 @@ android:
- name: "com.oculus.supportedDevices"
value: "quest|quest2|quest3|questpro"
activities:
- - config_changes: "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode"
+ - config_changes: "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode|screenLayout"
launch_mode: "singleTask"
orientation: "landscape"
intent_filters:
@@ -23,5 +32,6 @@ android:
categories:
- "com.oculus.intent.category.VR"
- "android.intent.category.LAUNCHER"
+ - "org.khronos.openxr.intent.category.IMMERSIVE_HMD"
sdk:
target_sdk_version: 32
diff --git a/examples/android/src/lib.rs b/examples/android/src/lib.rs
index 4fabb2b..efb835a 100644
--- a/examples/android/src/lib.rs
+++ b/examples/android/src/lib.rs
@@ -1,7 +1,11 @@
use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin};
use bevy::prelude::*;
use bevy::transform::components::Transform;
+use bevy_oxr::graphics::extensions::XrExtensions;
use bevy_oxr::graphics::XrAppInfo;
+use bevy_oxr::graphics::XrPreferdBlendMode::AlphaBlend;
+use bevy_oxr::passthrough::{passthrough_layer_pause, passthrough_layer_resume};
+use bevy_oxr::xr_init::XrRenderData;
use bevy_oxr::xr_input::debug_gizmos::OpenXrDebugRenderer;
use bevy_oxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig};
use bevy_oxr::xr_input::trackers::{
@@ -11,18 +15,21 @@ use bevy_oxr::DefaultXrPlugins;
#[bevy_main]
fn main() {
+ let mut xr_extensions = XrExtensions::default();
+ xr_extensions.enable_fb_passthrough();
App::new()
.add_plugins(DefaultXrPlugins {
+ reqeusted_extensions: xr_extensions,
app_info: XrAppInfo {
name: "Bevy OXR Android Example".into(),
},
- ..default()
+ prefered_blend_mode: bevy_oxr::graphics::XrPreferdBlendMode::Opaque,
})
.add_plugins(OpenXrDebugRenderer)
.add_plugins(LogDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin)
.add_systems(Startup, setup)
- .add_systems(Update, proto_locomotion)
+ .add_systems(Update, (proto_locomotion, toggle_passthrough))
.add_systems(Startup, spawn_controllers_example)
.insert_resource(PrototypeLocomotionConfig::default())
.run();
@@ -64,11 +71,6 @@ fn setup(
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
- // camera
- // commands.spawn((Camera3dBundle {
- // transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
- // ..default()
- // },));
}
fn spawn_controllers_example(mut commands: Commands) {
@@ -87,3 +89,16 @@ fn spawn_controllers_example(mut commands: Commands) {
SpatialBundle::default(),
));
}
+
+// Does this work? Not getting logs
+fn toggle_passthrough(keys: Res>, mut xr_data: ResMut) {
+ if keys.just_pressed(KeyCode::Space) {
+ if xr_data.xr_passthrough_active {
+ passthrough_layer_pause(xr_data);
+ bevy::log::info!("Passthrough paused");
+ } else {
+ passthrough_layer_resume(xr_data);
+ bevy::log::info!("Passthrough resumed");
+ }
+ }
+}
diff --git a/examples/demo/manifest.yaml b/examples/demo/manifest.yaml
index 6cba5b8..f514707 100644
--- a/examples/demo/manifest.yaml
+++ b/examples/demo/manifest.yaml
@@ -3,27 +3,27 @@ android:
- "runtime_libs"
manifest:
package: "org.bevyengine.demo_openxr_android"
- # Are features and permissions fliped?
uses_feature:
- name: "android.hardware.vr.headtracking"
required: true
- name: "oculus.software.handtracking"
- required: false
- # - name: "com.oculus.feature.PASSTHROUGH"
- # required: true
- uses_permission:
- - name: "com.oculus.permission.HAND_TRACKING"
- - name: "android.permission.INTERNET"
+ required: true
+ - name: "com.oculus.feature.PASSTHROUGH"
+ required: true
+ - name: "com.oculus.experimental.enabled"
+ required: true
application:
label: "Bevy Openxr Android"
theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
meta_data:
+ - name: "com.oculus.intent.category.VR"
+ value: "vr_only"
- name: "com.samsung.android.vr.application.mode"
value: "vr_only"
- name: "com.oculus.supportedDevices"
- value: "quest|quest2|quest3"
+ value: "quest|quest2|quest3|questpro"
activities:
- - config_changes: "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode"
+ - config_changes: "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode|screenLayout"
launch_mode: "singleTask"
orientation: "landscape"
intent_filters:
@@ -32,5 +32,6 @@ android:
categories:
- "com.oculus.intent.category.VR"
- "android.intent.category.LAUNCHER"
+ - "org.khronos.openxr.intent.category.IMMERSIVE_HMD"
sdk:
target_sdk_version: 32
diff --git a/examples/demo/src/lib.rs b/examples/demo/src/lib.rs
index e7feb94..d55db1a 100644
--- a/examples/demo/src/lib.rs
+++ b/examples/demo/src/lib.rs
@@ -65,6 +65,7 @@ pub fn main() {
info!("Running bevy_openxr demo");
let mut app = App::new();
let mut xr_extensions = XrExtensions::default();
+ xr_extensions.enable_fb_passthrough();
app
//lets get the usual diagnostic stuff added
diff --git a/src/graphics/extensions.rs b/src/graphics/extensions.rs
index 2276b79..81d8ca7 100644
--- a/src/graphics/extensions.rs
+++ b/src/graphics/extensions.rs
@@ -10,14 +10,14 @@ impl XrExtensions {
pub fn raw(&self) -> &ExtensionSet {
&self.0
}
- // pub fn enable_fb_passthrough(&mut self) -> &mut Self {
- // self.0.fb_passthrough = true;
- // self
- // }
- // pub fn disable_fb_passthrough(&mut self) -> &mut Self {
- // self.0.fb_passthrough = false;
- // self
- // }
+ pub fn enable_fb_passthrough(&mut self) -> &mut Self {
+ self.0.fb_passthrough = true;
+ self
+ }
+ pub fn disable_fb_passthrough(&mut self) -> &mut Self {
+ self.0.fb_passthrough = false;
+ self
+ }
pub fn enable_hand_tracking(&mut self) -> &mut Self {
self.0.ext_hand_tracking = true;
self
diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs
index 33dc317..147fa1c 100644
--- a/src/graphics/mod.rs
+++ b/src/graphics/mod.rs
@@ -12,9 +12,10 @@ use wgpu::Instance;
use crate::input::XrInput;
use crate::resources::{
- OXrSessionSetupInfo, XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, XrInstance,
- XrResolution, XrSession, XrSessionRunning, XrSwapchain, XrViews,
+ XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, XrInstance, XrResolution,
+ XrSession, XrSessionRunning, XrSwapchain, XrViews,
};
+use crate::OXrSessionSetupInfo;
use openxr as xr;
diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs
index f4ca0f0..2a4bb44 100644
--- a/src/graphics/vulkan.rs
+++ b/src/graphics/vulkan.rs
@@ -16,6 +16,7 @@ use xr::EnvironmentBlendMode;
use crate::graphics::extensions::XrExtensions;
use crate::input::XrInput;
+
use crate::resources::{
OXrSessionSetupInfo, Swapchain, SwapchainInner, VulkanOXrSessionSetupInfo,
XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, XrInstance, XrResolution,
@@ -47,7 +48,7 @@ pub fn initialize_xr_instance(
let available_extensions: XrExtensions = xr_entry.enumerate_extensions()?.into();
assert!(available_extensions.raw().khr_vulkan_enable2);
- info!("available xr exts: {:#?}", available_extensions);
+ //info!("available xr exts: {:#?}", available_extensions);
let mut enabled_extensions: xr::ExtensionSet =
(available_extensions & reqeusted_extensions).into();
@@ -58,7 +59,7 @@ pub fn initialize_xr_instance(
}
let available_layers = xr_entry.enumerate_layers()?;
- info!("available xr layers: {:#?}", available_layers);
+ //info!("available xr layers: {:#?}", available_layers);
let xr_instance = xr_entry.create_instance(
&xr::ApplicationInfo {
@@ -88,17 +89,23 @@ pub fn initialize_xr_instance(
let blend_modes = xr_instance.enumerate_environment_blend_modes(xr_system_id, VIEW_TYPE)?;
let blend_mode: EnvironmentBlendMode = match prefered_blend_mode {
XrPreferdBlendMode::Opaque if blend_modes.contains(&EnvironmentBlendMode::OPAQUE) => {
+ bevy::log::info!("Using Opaque");
EnvironmentBlendMode::OPAQUE
}
XrPreferdBlendMode::Additive if blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) => {
+ bevy::log::info!("Using Additive");
EnvironmentBlendMode::ADDITIVE
}
XrPreferdBlendMode::AlphaBlend
if blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) =>
{
+ bevy::log::info!("Using AlphaBlend");
EnvironmentBlendMode::ALPHA_BLEND
}
- _ => EnvironmentBlendMode::OPAQUE,
+ _ => {
+ bevy::log::info!("Using Opaque");
+ EnvironmentBlendMode::OPAQUE
+ }
};
#[cfg(not(target_os = "android"))]
@@ -359,6 +366,8 @@ pub fn start_xr_session(
.map(|surface| surface.get_capabilities(wgpu_adapter).formats[0])
.unwrap_or(wgpu::TextureFormat::Rgba8UnormSrgb);
+ // TODO: Log swapchain format
+
let resolution = uvec2(
views[0].recommended_image_rect_width,
views[0].recommended_image_rect_height,
@@ -436,7 +445,7 @@ pub fn start_xr_session(
.collect();
Ok((
- session.clone().into_any_graphics().into(),
+ XrSession::Vulkan(session.clone()),
resolution.into(),
swapchain_format.into(),
AtomicBool::new(false).into(),
diff --git a/src/lib.rs b/src/lib.rs
index 647b666..ae0a5a4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,6 @@
pub mod graphics;
pub mod input;
-// pub mod passthrough;
+pub mod passthrough;
pub mod resource_macros;
pub mod resources;
pub mod xr_init;
@@ -11,41 +11,31 @@ use std::io::{BufWriter, Write};
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
+use crate::passthrough::ResumePassthrough;
use crate::xr_init::{StartXrSession, XrInitPlugin};
-use crate::xr_input::hands::hand_tracking::DisableHandTracking;
use crate::xr_input::oculus_touch::ActionSets;
use bevy::app::{AppExit, PluginGroupBuilder};
use bevy::core::TaskPoolThreadAssignmentPolicy;
use bevy::ecs::system::SystemState;
use bevy::prelude::*;
-use bevy::render::camera::{
- camera_system, ManualTextureView, ManualTextureViewHandle, ManualTextureViews,
-};
-use bevy::render::extract_resource::ExtractResourcePlugin;
+use bevy::render::camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews};
use bevy::render::pipelined_rendering::PipelinedRenderingPlugin;
use bevy::render::renderer::{render_system, RenderInstance};
use bevy::render::settings::RenderCreation;
-use bevy::render::view::ExtractedView;
use bevy::render::{Render, RenderApp, RenderPlugin, RenderSet};
-use bevy::tasks::available_parallelism;
-use bevy::transform::systems::{propagate_transforms, sync_simple_transforms};
use bevy::window::{PresentMode, PrimaryWindow, RawHandleWrapper};
use graphics::extensions::XrExtensions;
use graphics::{XrAppInfo, XrPreferdBlendMode};
use input::XrInput;
use openxr as xr;
-// use passthrough::{start_passthrough, supports_passthrough, XrPassthroughLayer};
+use passthrough::{PassthroughPlugin, XrPassthroughLayer, XrPassthroughState};
use resources::*;
-use xr::{FormFactor, FrameState};
use xr_init::{
xr_after_wait_only, xr_only, xr_render_only, CleanupXrData, XrEarlyInitPlugin, XrHasWaited,
XrShouldRender, XrStatus,
};
use xr_input::controllers::XrControllerType;
-use xr_input::hands::emulated::HandEmulationPlugin;
-use xr_input::hands::hand_tracking::{HandTrackingData, HandTrackingPlugin};
use xr_input::hands::XrHandPlugins;
-use xr_input::xr_camera::{XRProjection, XrCameraType};
use xr_input::OpenXrInput;
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
@@ -61,6 +51,11 @@ pub struct OpenXrPlugin {
app_info: XrAppInfo,
}
+fn mr_test(mut commands: Commands, mut resume: EventWriter) {
+ commands.insert_resource(ClearColor(Color::rgba(0.0, 0.0, 0.0, 0.0)));
+ resume.send_default();
+}
+
impl Plugin for OpenXrPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(XrSessionRunning::new(AtomicBool::new(false)));
@@ -88,6 +83,8 @@ impl Plugin for OpenXrPlugin {
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
debug!("Configured wgpu adapter Features: {:#?}", device.features());
warn!("Starting with OpenXR Instance");
+ app.insert_resource(xr_instance.clone());
+ app.insert_resource(blend_mode.clone());
app.insert_resource(ActionSets(vec![]));
app.insert_resource(xr_instance);
app.insert_resource(blend_mode);
@@ -117,6 +114,7 @@ impl Plugin for OpenXrPlugin {
app.add_plugins(RenderPlugin::default());
app.insert_resource(XrStatus::Disabled);
}
+ app.add_systems(Update, mr_test.run_if(xr_only()));
app.add_systems(
PreUpdate,
xr_poll_events.run_if(|status: Res| *status != XrStatus::NoInstance),
@@ -227,6 +225,7 @@ impl PluginGroup for DefaultXrPlugins {
.add_after::(XrInitPlugin)
.add_before::(XrEarlyInitPlugin)
.add(XrHandPlugins)
+ .add(PassthroughPlugin)
.add(XrResourcePlugin)
.set(WindowPlugin {
#[cfg(not(target_os = "android"))]
@@ -237,7 +236,7 @@ impl PluginGroup for DefaultXrPlugins {
..default()
}),
#[cfg(target_os = "android")]
- primary_window: None,
+ primary_window: None, // ?
#[cfg(target_os = "android")]
exit_condition: bevy::window::ExitCondition::DontExit,
#[cfg(target_os = "android")]
@@ -315,7 +314,6 @@ pub fn xr_wait_frame(
) {
{
let _span = info_span!("xr_wait_frame").entered();
- info!("Pre Frame Wait");
*frame_state = match frame_waiter.wait() {
Ok(a) => a.into(),
Err(e) => {
@@ -323,15 +321,6 @@ pub fn xr_wait_frame(
return;
}
};
- info!(
- "Post Wait Time: {}",
- frame_state.predicted_display_time.as_nanos()
- );
- // frame_state.predicted_display_time = xr::Time::from_nanos(
- // frame_state.predicted_display_time.as_nanos()
- // + frame_state.predicted_display_period.as_nanos(),
- // );
- info!("Post Frame Wait");
**should_render = frame_state.should_render;
**waited = true;
}
@@ -369,6 +358,7 @@ pub fn xr_pre_frame(
}
}
+#[allow(clippy::too_many_arguments)]
pub fn xr_end_frame(
xr_frame_state: Res,
views: Res,
@@ -376,6 +366,8 @@ pub fn xr_end_frame(
swapchain: Res,
resolution: Res,
environment_blend_mode: Res,
+ passthrough_layer: Option>,
+ passthrough_state: Option>,
) {
#[cfg(target_os = "android")]
{
@@ -383,23 +375,24 @@ pub fn xr_end_frame(
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();
let env = vm.attach_current_thread_as_daemon();
}
+
{
let _span = info_span!("xr_release_image").entered();
swapchain.release_image().unwrap();
}
{
let _span = info_span!("xr_end_frame").entered();
- info!(
- "End Frame Time: {}",
- xr_frame_state.predicted_display_time.as_nanos()
- );
+ let pass_layer = match passthrough_state.as_deref() {
+ Some(XrPassthroughState::Running) => passthrough_layer.as_deref(),
+ _ => None,
+ };
let result = swapchain.end(
xr_frame_state.predicted_display_time,
&views,
&input.stage,
**resolution,
**environment_blend_mode,
- // passthrough_layer.map(|p| p.into_inner()),
+ pass_layer,
);
match result {
Ok(_) => {}
diff --git a/src/passthrough.rs b/src/passthrough.rs
new file mode 100644
index 0000000..51256e7
--- /dev/null
+++ b/src/passthrough.rs
@@ -0,0 +1,226 @@
+use bevy::render::extract_resource::ExtractResource;
+use bevy::{prelude::*, render::extract_resource::ExtractResourcePlugin};
+use std::{marker::PhantomData, mem, ptr};
+
+use crate::resources::XrSession;
+use crate::{
+ resources::XrInstance,
+ xr_arc_resource_wrapper,
+ xr_init::{XrCleanup, XrSetup},
+};
+use openxr as xr;
+use xr::{
+ sys::{Space, SystemPassthroughProperties2FB},
+ CompositionLayerBase, CompositionLayerFlags, FormFactor, Graphics,
+ PassthroughCapabilityFlagsFB,
+};
+
+#[derive(
+ Clone, Copy, Default, Debug, Resource, PartialEq, PartialOrd, Ord, Eq, Reflect, ExtractResource,
+)]
+pub enum XrPassthroughState {
+ #[default]
+ Unsupported,
+ Running,
+ Paused,
+}
+
+pub struct PassthroughPlugin;
+xr_arc_resource_wrapper!(XrPassthrough, xr::Passthrough);
+xr_arc_resource_wrapper!(XrPassthroughLayer, xr::PassthroughLayer);
+
+impl Plugin for PassthroughPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_event::();
+ app.add_event::();
+ app.add_plugins(ExtractResourcePlugin::::default());
+ app.add_plugins(ExtractResourcePlugin::::default());
+ app.register_type::();
+ app.add_systems(Startup, check_passthrough_support);
+ app.add_systems(
+ XrSetup,
+ setup_passthrough
+ .run_if(|state: Res| *state != XrPassthroughState::Unsupported),
+ );
+ app.add_systems(XrCleanup, cleanup_passthrough);
+ app.add_systems(
+ Update,
+ resume_passthrough.run_if(
+ resource_exists_and_equals(XrPassthroughState::Paused)
+ .and_then(on_event::()),
+ ),
+ );
+ app.add_systems(
+ Update,
+ pause_passthrough.run_if(
+ resource_exists_and_equals(XrPassthroughState::Running)
+ .and_then(on_event::()),
+ ),
+ );
+ }
+}
+
+fn check_passthrough_support(mut cmds: Commands, instance: Option>) {
+ match instance {
+ None => cmds.insert_resource(XrPassthroughState::Unsupported),
+ Some(instance) => {
+ let supported = instance.exts().fb_passthrough.is_some()
+ && supports_passthrough(
+ &instance,
+ instance.system(FormFactor::HEAD_MOUNTED_DISPLAY).unwrap(),
+ )
+ .is_ok_and(|v| v);
+ match supported {
+ false => cmds.insert_resource(XrPassthroughState::Unsupported),
+ true => cmds.insert_resource(XrPassthroughState::Paused),
+ }
+ }
+ }
+}
+
+fn resume_passthrough(layer: Res, mut state: ResMut) {
+ if let Err(e) = layer.resume() {
+ warn!("Unable to resume Passthrough: {}", e);
+ return;
+ }
+ info!("<=> Resume Passthrough");
+ *state = XrPassthroughState::Running;
+}
+fn pause_passthrough(layer: Res, mut state: ResMut) {
+ if let Err(e) = layer.pause() {
+ warn!("Unable to resume Passthrough: {}", e);
+ return;
+ }
+ info!("<=> Pausing Passthrough");
+ *state = XrPassthroughState::Paused;
+}
+
+fn cleanup_passthrough(mut cmds: Commands) {
+ cmds.remove_resource::();
+ cmds.remove_resource::();
+}
+
+fn setup_passthrough(mut cmds: Commands, instance: Res, session: Res) {
+ match create_passthrough(&instance, &session) {
+ Ok((passthrough, layer)) => {
+ cmds.insert_resource(XrPassthrough::from(passthrough));
+ cmds.insert_resource(XrPassthroughLayer::from(layer));
+ }
+ Err(e) => {
+ warn!("Unable to create passthrough: {}", e);
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Default, Reflect, Event)]
+pub struct ResumePassthrough;
+
+#[derive(Clone, Copy, Debug, Default, Reflect, Event)]
+pub struct PausePassthrough;
+
+fn cvt(x: xr::sys::Result) -> xr::Result {
+ if x.into_raw() >= 0 {
+ Ok(x)
+ } else {
+ Err(x)
+ }
+}
+
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub(crate) struct CompositionLayerPassthrough<'a, G: xr::Graphics> {
+ inner: xr::sys::CompositionLayerPassthroughFB,
+ _marker: PhantomData<&'a G>,
+}
+impl<'a, G: Graphics> std::ops::Deref for CompositionLayerPassthrough<'a, G> {
+ type Target = CompositionLayerBase<'a, G>;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ unsafe { mem::transmute(&self.inner) }
+ }
+}
+
+impl<'a, G: xr::Graphics> CompositionLayerPassthrough<'a, G> {
+ pub(crate) fn from_xr_passthrough_layer(layer: &XrPassthroughLayer) -> Self {
+ Self {
+ inner: xr::sys::CompositionLayerPassthroughFB {
+ ty: xr::sys::CompositionLayerPassthroughFB::TYPE,
+ next: ptr::null(),
+ flags: CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA,
+ space: Space::NULL,
+ layer_handle: *layer.inner(),
+ },
+ _marker: PhantomData,
+ }
+ }
+}
+#[inline]
+pub fn supports_passthrough(instance: &XrInstance, system: xr::SystemId) -> xr::Result {
+ unsafe {
+ let mut hand = xr::sys::SystemPassthroughProperties2FB {
+ ty: SystemPassthroughProperties2FB::TYPE,
+ next: ptr::null(),
+ capabilities: PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
+ };
+ let mut p = xr::sys::SystemProperties::out(&mut hand as *mut _ as _);
+ cvt((instance.fp().get_system_properties)(
+ instance.as_raw(),
+ system,
+ p.as_mut_ptr(),
+ ))?;
+ bevy::log::info!(
+ "From supports_passthrough: Passthrough capabilities: {:?}",
+ hand.capabilities
+ );
+ Ok(
+ (hand.capabilities & PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY)
+ == PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
+ )
+ }
+}
+
+#[inline]
+pub fn create_passthrough(
+ instance: &XrInstance,
+ xr_session: &XrSession,
+) -> xr::Result<(xr::Passthrough, xr::PassthroughLayer)> {
+ let passthrough = match xr_session {
+ XrSession::Vulkan(session) => {
+ session.create_passthrough(xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION)
+ }
+ }?;
+ let passthrough_layer = match xr_session {
+ XrSession::Vulkan(session) => session.create_passthrough_layer(
+ &passthrough,
+ xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION,
+ xr::PassthroughLayerPurposeFB::RECONSTRUCTION,
+ ),
+ }?;
+ Ok((passthrough, passthrough_layer))
+}
+
+// #[inline]
+// pub fn passthrough_layer_resume(mut layer: ResMut, mut passthrough: ResMut) -> xr::Result<()> {
+// layer.resume()
+// }
+
+// #[inline]
+// pub fn passthrough_layer_pause(mut xr_data_resource: ResMut) -> xr::Result<()> {
+// unsafe {
+// let passthrough_layer = &xr_data_resource.xr_passthrough_layer;
+// {
+// let passthrough_layer_locked = passthrough_layer.lock().unwrap();
+// cvt((xr_data_resource
+// .xr_instance
+// .exts()
+// .fb_passthrough
+// .unwrap()
+// .passthrough_layer_pause)(
+// *passthrough_layer_locked
+// ))?;
+// }
+// xr_data_resource.xr_passthrough_active = false;
+// bevy::log::info!("Paused passthrough layer");
+// Ok(())
+// }
+// }
diff --git a/src/resources.rs b/src/resources.rs
index 41678bb..3b6ee26 100644
--- a/src/resources.rs
+++ b/src/resources.rs
@@ -3,14 +3,20 @@ use std::sync::atomic::AtomicBool;
use std::sync::Mutex;
use crate::input::XrInput;
-// use crate::passthrough::XrPassthroughLayer;
+use crate::passthrough::{CompositionLayerPassthrough, XrPassthroughLayer};
+use crate::resource_macros::*;
+use crate::xr::sys::CompositionLayerPassthroughFB;
+use crate::xr::{CompositionLayerBase, CompositionLayerFlags};
use crate::{resource_macros::*, xr_resource_wrapper_copy};
use bevy::prelude::*;
-use bevy::render::extract_resource::ExtractResourcePlugin;
+use bevy::prelude::*;
+use bevy::render::extract_component::ExtractComponent;
+use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin};
+use core::ptr;
use openxr as xr;
xr_resource_wrapper!(XrInstance, xr::Instance);
-xr_resource_wrapper!(XrSession, xr::Session);
+// xr_resource_wrapper!(XrSession, xr::Session);
xr_resource_wrapper_copy!(XrEnvironmentBlendMode, xr::EnvironmentBlendMode);
xr_resource_wrapper_copy!(XrResolution, UVec2);
xr_resource_wrapper_copy!(XrFormat, wgpu::TextureFormat);
@@ -20,6 +26,23 @@ xr_arc_resource_wrapper!(XrSessionRunning, AtomicBool);
xr_arc_resource_wrapper!(XrSwapchain, Swapchain);
xr_no_clone_resource_wrapper!(XrFrameWaiter, xr::FrameWaiter);
+#[derive(Clone, Resource, ExtractResource)]
+pub enum XrSession {
+ Vulkan(xr::Session),
+}
+
+impl std::ops::Deref for XrSession {
+ type Target = xr::Session;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFTEY: should be fine i think -Schmarni
+ unsafe {
+ match self {
+ XrSession::Vulkan(sess) => std::mem::transmute(sess),
+ }
+ }
+ }
+}
pub struct VulkanOXrSessionSetupInfo {
pub(crate) device_ptr: *const c_void,
@@ -91,7 +114,7 @@ impl Swapchain {
stage: &xr::Space,
resolution: UVec2,
environment_blend_mode: xr::EnvironmentBlendMode,
- // passthrough_layer: Option<&XrPassthroughLayer>,
+ passthrough_layer: Option<&XrPassthroughLayer>,
) -> xr::Result<()> {
match self {
Swapchain::Vulkan(swapchain) => swapchain.end(
@@ -100,7 +123,7 @@ impl Swapchain {
stage,
resolution,
environment_blend_mode,
- // passthrough_layer,
+ passthrough_layer,
),
}
}
@@ -160,7 +183,7 @@ impl SwapchainInner {
stage: &xr::Space,
resolution: UVec2,
environment_blend_mode: xr::EnvironmentBlendMode,
- // passthrough_layer: Option<&XrPassthroughLayer>,
+ passthrough_layer: Option<&XrPassthroughLayer>,
) -> xr::Result<()> {
let rect = xr::Rect2Di {
offset: xr::Offset2Di { x: 0, y: 0 },
@@ -174,76 +197,71 @@ impl SwapchainInner {
warn!("views are len of 0");
return Ok(());
}
- // match passthrough_layer {
- // Some(pass) => {
- // // info!("Rendering with pass through");
- // let passthrough_layer = xr::sys::CompositionLayerPassthroughFB {
- // ty: CompositionLayerPassthroughFB::TYPE,
- // next: ptr::null(),
- // flags: CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA,
- // space: xr::sys::Space::NULL,
- // layer_handle: pass.0,
- // };
- // self.stream.lock().unwrap().end(
- // predicted_display_time,
- // environment_blend_mode,
- // &[
- // &xr::CompositionLayerProjection::new()
- // .layer_flags(CompositionLayerFlags::UNPREMULTIPLIED_ALPHA)
- // .space(stage)
- // .views(&[
- // xr::CompositionLayerProjectionView::new()
- // .pose(views[0].pose)
- // .fov(views[0].fov)
- // .sub_image(
- // xr::SwapchainSubImage::new()
- // .swapchain(&swapchain)
- // .image_array_index(0)
- // .image_rect(rect),
- // ),
- // xr::CompositionLayerProjectionView::new()
- // .pose(views[1].pose)
- // .fov(views[1].fov)
- // .sub_image(
- // xr::SwapchainSubImage::new()
- // .swapchain(&swapchain)
- // .image_array_index(1)
- // .image_rect(rect),
- // ),
- // ]),
- // unsafe {
- // &*(&passthrough_layer as *const _ as *const CompositionLayerBase)
- // },
- // ],
- // )
- // }
+ match passthrough_layer {
+ Some(pass) => {
+ //bevy::log::info!("Rendering with pass through");
- // None =>
- let r = self.stream.lock().unwrap().end(
- predicted_display_time,
- environment_blend_mode,
- &[&xr::CompositionLayerProjection::new().space(stage).views(&[
- xr::CompositionLayerProjectionView::new()
- .pose(views[0].pose)
- .fov(views[0].fov)
- .sub_image(
- xr::SwapchainSubImage::new()
- .swapchain(&swapchain)
- .image_array_index(0)
- .image_rect(rect),
- ),
- xr::CompositionLayerProjectionView::new()
- .pose(views[1].pose)
- .fov(views[1].fov)
- .sub_image(
- xr::SwapchainSubImage::new()
- .swapchain(&swapchain)
- .image_array_index(1)
- .image_rect(rect),
- ),
- ])],
- );
- r
- // }
+ self.stream.lock().unwrap().end(
+ predicted_display_time,
+ environment_blend_mode,
+ &[
+ &CompositionLayerPassthrough::from_xr_passthrough_layer(
+ pass,
+ ),
+ &xr::CompositionLayerProjection::new()
+ .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA)
+ .space(stage)
+ .views(&[
+ xr::CompositionLayerProjectionView::new()
+ .pose(views[0].pose)
+ .fov(views[0].fov)
+ .sub_image(
+ xr::SwapchainSubImage::new()
+ .swapchain(&swapchain)
+ .image_array_index(0)
+ .image_rect(rect),
+ ),
+ xr::CompositionLayerProjectionView::new()
+ .pose(views[1].pose)
+ .fov(views[1].fov)
+ .sub_image(
+ xr::SwapchainSubImage::new()
+ .swapchain(&swapchain)
+ .image_array_index(1)
+ .image_rect(rect),
+ ),
+ ]),
+ ],
+ )
+ }
+
+ None => {
+ bevy::log::info!("Rendering without pass through");
+ self.stream.lock().unwrap().end(
+ predicted_display_time,
+ environment_blend_mode,
+ &[&xr::CompositionLayerProjection::new().space(stage).views(&[
+ xr::CompositionLayerProjectionView::new()
+ .pose(views[0].pose)
+ .fov(views[0].fov)
+ .sub_image(
+ xr::SwapchainSubImage::new()
+ .swapchain(&swapchain)
+ .image_array_index(0)
+ .image_rect(rect),
+ ),
+ xr::CompositionLayerProjectionView::new()
+ .pose(views[1].pose)
+ .fov(views[1].fov)
+ .sub_image(
+ xr::SwapchainSubImage::new()
+ .swapchain(&swapchain)
+ .image_array_index(1)
+ .image_rect(rect),
+ ),
+ ])],
+ )
+ }
+ }
}
}