pull main, refactor passthrough
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<Input<KeyCode>>, mut xr_data: ResMut<XrRenderData>) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
53
src/lib.rs
53
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<ResumePassthrough>) {
|
||||
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<XrStatus>| *status != XrStatus::NoInstance),
|
||||
@@ -227,6 +225,7 @@ impl PluginGroup for DefaultXrPlugins {
|
||||
.add_after::<OpenXrPlugin, _>(XrInitPlugin)
|
||||
.add_before::<OpenXrPlugin, _>(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<XrFrameState>,
|
||||
views: Res<XrViews>,
|
||||
@@ -376,6 +366,8 @@ pub fn xr_end_frame(
|
||||
swapchain: Res<XrSwapchain>,
|
||||
resolution: Res<XrResolution>,
|
||||
environment_blend_mode: Res<XrEnvironmentBlendMode>,
|
||||
passthrough_layer: Option<Res<XrPassthroughLayer>>,
|
||||
passthrough_state: Option<Res<XrPassthroughState>>,
|
||||
) {
|
||||
#[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(_) => {}
|
||||
|
||||
226
src/passthrough.rs
Normal file
226
src/passthrough.rs
Normal file
@@ -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::<ResumePassthrough>();
|
||||
app.add_event::<PausePassthrough>();
|
||||
app.add_plugins(ExtractResourcePlugin::<XrPassthroughLayer>::default());
|
||||
app.add_plugins(ExtractResourcePlugin::<XrPassthroughState>::default());
|
||||
app.register_type::<XrPassthroughState>();
|
||||
app.add_systems(Startup, check_passthrough_support);
|
||||
app.add_systems(
|
||||
XrSetup,
|
||||
setup_passthrough
|
||||
.run_if(|state: Res<XrPassthroughState>| *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::<ResumePassthrough>()),
|
||||
),
|
||||
);
|
||||
app.add_systems(
|
||||
Update,
|
||||
pause_passthrough.run_if(
|
||||
resource_exists_and_equals(XrPassthroughState::Running)
|
||||
.and_then(on_event::<PausePassthrough>()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_passthrough_support(mut cmds: Commands, instance: Option<Res<XrInstance>>) {
|
||||
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<XrPassthroughLayer>, mut state: ResMut<XrPassthroughState>) {
|
||||
if let Err(e) = layer.resume() {
|
||||
warn!("Unable to resume Passthrough: {}", e);
|
||||
return;
|
||||
}
|
||||
info!("<=> Resume Passthrough");
|
||||
*state = XrPassthroughState::Running;
|
||||
}
|
||||
fn pause_passthrough(layer: Res<XrPassthroughLayer>, mut state: ResMut<XrPassthroughState>) {
|
||||
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::<XrPassthrough>();
|
||||
cmds.remove_resource::<XrPassthroughLayer>();
|
||||
}
|
||||
|
||||
fn setup_passthrough(mut cmds: Commands, instance: Res<XrInstance>, session: Res<XrSession>) {
|
||||
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<xr::sys::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<bool> {
|
||||
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<XrPassthroughLayer>, mut passthrough: ResMut<XrPassthrough>) -> xr::Result<()> {
|
||||
// layer.resume()
|
||||
// }
|
||||
|
||||
// #[inline]
|
||||
// pub fn passthrough_layer_pause(mut xr_data_resource: ResMut<XrRenderData>) -> 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(())
|
||||
// }
|
||||
// }
|
||||
126
src/resources.rs
126
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::AnyGraphics>);
|
||||
// xr_resource_wrapper!(XrSession, xr::Session<xr::AnyGraphics>);
|
||||
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<xr::Vulkan>),
|
||||
}
|
||||
|
||||
impl std::ops::Deref for XrSession {
|
||||
type Target = xr::Session<xr::AnyGraphics>;
|
||||
|
||||
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<G: xr::Graphics> SwapchainInner<G> {
|
||||
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,52 +197,47 @@ impl<G: xr::Graphics> SwapchainInner<G> {
|
||||
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<G>)
|
||||
// },
|
||||
// ],
|
||||
// )
|
||||
// }
|
||||
match passthrough_layer {
|
||||
Some(pass) => {
|
||||
//bevy::log::info!("Rendering with pass through");
|
||||
|
||||
// None =>
|
||||
let r = self.stream.lock().unwrap().end(
|
||||
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(&[
|
||||
@@ -242,8 +260,8 @@ impl<G: xr::Graphics> SwapchainInner<G> {
|
||||
.image_rect(rect),
|
||||
),
|
||||
])],
|
||||
);
|
||||
r
|
||||
// }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user