From 56819a996c315f1813f840c185b889ea424ca1c9 Mon Sep 17 00:00:00 2001 From: awtterpip Date: Tue, 29 Aug 2023 13:02:15 -0500 Subject: [PATCH] XR is kinda working now --- src/graphics/vulkan.rs | 5 +- src/lib.rs | 33 +++++++- src/resources.rs | 30 +++++-- srcold/input.rs | 141 -------------------------------- srcold/lib.rs | 52 ------------ srcold/xr/mod.rs | 178 ----------------------------------------- 6 files changed, 58 insertions(+), 381 deletions(-) delete mode 100644 srcold/input.rs delete mode 100644 srcold/lib.rs delete mode 100644 srcold/xr/mod.rs diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index 8c7d48d..99fcb90 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -9,7 +9,7 @@ use bevy::prelude::*; use bevy::render::renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; use bevy::window::RawHandleWrapper; use openxr as xr; -use wgpu::Instance; +use wgpu::{Instance, Texture}; use crate::input::XrInput; use crate::resources::{ @@ -351,7 +351,6 @@ pub fn initialize_xr_graphics(window: Option) -> anyhow::Resul texture }) .collect(); - Ok(( wgpu_device.into(), @@ -368,7 +367,9 @@ pub fn initialize_xr_graphics(window: Option) -> anyhow::Resul stream: frame_stream, handle, resolution, + format: swapchain_format, buffers, + image_index: 0, })).into(), XrInput::new(xr_instance, session.into_any_graphics())?, Mutex::default().into(), diff --git a/src/lib.rs b/src/lib.rs index 458848c..f8fc4d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,6 +100,24 @@ impl Plugin for OpenXrPlugin { .insert_resource(views.clone()) .insert_resource(frame_state.clone()); + let swapchain_mut = swapchain.lock().unwrap(); + let (left, right) = swapchain_mut.get_render_views(); + let format = swapchain_mut.format(); + let left = ManualTextureView { + texture_view: left.into(), + size: swapchain_mut.resolution(), + format, + }; + let right = ManualTextureView { + texture_view: right.into(), + size: swapchain_mut.resolution(), + format, + }; + let mut manual_texture_views = app.world.resource_mut::(); + manual_texture_views.insert(LEFT_XR_TEXTURE_HANDLE, left); + manual_texture_views.insert(RIGHT_XR_TEXTURE_HANDLE, right); + drop(manual_texture_views); + drop(swapchain_mut); let render_app = app.sub_app_mut(RenderApp); render_app.insert_resource(instance) @@ -111,6 +129,7 @@ impl Plugin for OpenXrPlugin { .insert_resource(input) .insert_resource(views) .insert_resource(frame_state); + render_app.add_systems(Render, (pre_frame.in_set(RenderSet::Prepare).before(post_frame), post_frame.in_set(RenderSet::Prepare), post_queue_submit.in_set(RenderSet::Cleanup))); } @@ -178,9 +197,19 @@ pub fn pre_frame( let mut swapchain = swapchain.lock().unwrap(); swapchain.begin().unwrap(); + swapchain.update_render_views(); let (left, right) = swapchain.get_render_views(); - let left = ManualTextureView::with_default_format(left.into(), swapchain.resolution()); - let right = ManualTextureView::with_default_format(right.into(), swapchain.resolution()); + let format = swapchain.format(); + let left = ManualTextureView { + texture_view: left.into(), + size: swapchain.resolution(), + format, + }; + let right = ManualTextureView { + texture_view: right.into(), + size: swapchain.resolution(), + format, + }; manual_texture_views.insert(LEFT_XR_TEXTURE_HANDLE, left); manual_texture_views.insert(RIGHT_XR_TEXTURE_HANDLE, right); } diff --git a/src/resources.rs b/src/resources.rs index d3a4c41..cc8185e 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -26,12 +26,24 @@ impl Swapchain { } } - pub(crate) fn get_render_views(&mut self) -> (wgpu::TextureView, wgpu::TextureView) { + pub(crate) fn update_render_views(&mut self) { + match self { + Swapchain::Vulkan(swap) => swap.update_render_views(), + } + } + + pub(crate) fn get_render_views(&self) -> (wgpu::TextureView, wgpu::TextureView) { match self { Swapchain::Vulkan(swap) => swap.get_render_views(), } } + pub(crate) fn format(&self) -> wgpu::TextureFormat { + match self { + Swapchain::Vulkan(swap) => swap.format + } + } + pub(crate) fn resolution(&self) -> UVec2 { match self { Swapchain::Vulkan(swap) => swap.resolution, @@ -55,7 +67,9 @@ pub struct SwapchainInner { pub(crate) stream: xr::FrameStream, pub(crate) handle: xr::Swapchain, pub(crate) resolution: UVec2, + pub(crate) format: wgpu::TextureFormat, pub(crate) buffers: Vec, + pub(crate) image_index: usize, } impl SwapchainInner { @@ -63,11 +77,8 @@ impl SwapchainInner { self.stream.begin() } - fn get_render_views(&mut self) -> (wgpu::TextureView, wgpu::TextureView) { - let image_index = self.handle.acquire_image().unwrap(); - self.handle.wait_image(xr::Duration::INFINITE).unwrap(); - - let texture = &self.buffers[image_index as usize]; + fn get_render_views(&self) -> (wgpu::TextureView, wgpu::TextureView) { + let texture = &self.buffers[self.image_index]; ( texture.create_view(&wgpu::TextureViewDescriptor { @@ -84,6 +95,13 @@ impl SwapchainInner { ) } + fn update_render_views(&mut self) { + let image_index = self.handle.acquire_image().unwrap(); + self.handle.wait_image(xr::Duration::INFINITE).unwrap(); + + self.image_index = image_index as _; + } + fn post_queue_submit( &mut self, xr_frame_state: xr::FrameState, diff --git a/srcold/input.rs b/srcold/input.rs deleted file mode 100644 index d7022aa..0000000 --- a/srcold/input.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::sync::Mutex; - -use glam::{Quat, Vec3}; -use openxr as xr; - -use crate::xr::{VIEW_TYPE, XrPose}; - -#[derive(Clone)] -pub struct PostFrameData { - pub views: Vec, - pub left_hand: Option, - pub right_hand: Option, -} - -pub(crate) struct XrInput { - session: xr::Session, - action_set: xr::ActionSet, - right_action: xr::Action, - left_action: xr::Action, - right_space: xr::Space, - left_space: xr::Space, - stage: xr::Space, - left_hand: Mutex, - right_hand: Mutex, - views: Mutex>, -} - -impl XrInput { - pub(crate) fn new( - instance: xr::Instance, - session: xr::Session, - ) -> anyhow::Result { - let action_set = instance.create_action_set("input", "input pose information", 0)?; - let right_action = - action_set.create_action::("right_hand", "Right Hand Controller", &[])?; - let left_action = - action_set.create_action::("left_hand", "Left Hand Controller", &[])?; - instance.suggest_interaction_profile_bindings( - instance.string_to_path("/interaction_profiles/khr/simple_controller")?, - &[ - xr::Binding::new( - &right_action, - instance.string_to_path("/user/hand/right/input/grip/pose")?, - ), - xr::Binding::new( - &left_action, - instance.string_to_path("/user/hand/left/input/grip/pose")?, - ), - ], - )?; - session.attach_action_sets(&[&action_set])?; - let right_space = - right_action.create_space(session.clone(), xr::Path::NULL, xr::Posef::IDENTITY)?; - let left_space = - left_action.create_space(session.clone(), xr::Path::NULL, xr::Posef::IDENTITY)?; - let stage = - session.create_reference_space(xr::ReferenceSpaceType::STAGE, xr::Posef::IDENTITY)?; - Ok(Self { - left_action, - left_space, - right_action, - right_space, - action_set, - stage, - session, - left_hand: Default::default(), - right_hand: Default::default(), - views: Default::default(), - }) - } - - pub(crate) fn post_frame( - &self, - xr_frame_state: xr::FrameState, - ) -> xr::Result { - self.session.sync_actions(&[(&self.action_set).into()])?; - let locate_hand_pose = |action: &xr::Action, - space: &xr::Space| - -> xr::Result> { - if action.is_active(&self.session, xr::Path::NULL)? { - Ok(Some(openxr_pose_to_glam( - &space - .locate(&self.stage, xr_frame_state.predicted_display_time)? - .pose, - ))) - } else { - Ok(None) - } - }; - - let left_hand = locate_hand_pose(&self.left_action, &self.left_space)?; - let right_hand = locate_hand_pose(&self.right_action, &self.right_space)?; - let (_, views) = self.session.locate_views( - VIEW_TYPE, - xr_frame_state.predicted_display_time, - &self.stage, - )?; - - if let Some(left_hand) = &left_hand { - *self.left_hand.lock().unwrap() = left_hand.clone(); - } - - if let Some(right_hand) = &left_hand { - *self.right_hand.lock().unwrap() = right_hand.clone(); - } - - *self.views.lock().unwrap() = views.iter().map(|f| openxr_pose_to_glam(&f.pose)).collect(); - - Ok(PostFrameData { - views, - left_hand, - right_hand, - }) - } - - pub fn stage(&self) -> &xr::Space { - &self.stage - } - - pub fn left_hand(&self) -> XrPose { - *self.left_hand.lock().unwrap() - } - - pub fn right_hand(&self) -> XrPose { - *self.right_hand.lock().unwrap() - } - - pub fn views(&self) -> Vec { - self.views.lock().unwrap().clone() - } -} - -pub fn openxr_pose_to_glam(pose: &openxr::Posef) -> (Vec3, Quat) { - // with enough sign errors anything is possible - let rotation = { - let o = pose.orientation; - Quat::from_rotation_x(180.0f32.to_radians()) * glam::quat(o.w, o.z, o.y, o.x) - }; - let translation = glam::vec3(-pose.position.x, pose.position.y, -pose.position.z); - (translation, rotation) -} diff --git a/srcold/lib.rs b/srcold/lib.rs deleted file mode 100644 index b4b9b9f..0000000 --- a/srcold/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use bevy::ecs::system::SystemState; -use bevy::prelude::*; -use bevy::render::settings::WgpuSettings; -use bevy::render::FutureRendererResources; -use bevy::window::{PrimaryWindow, RawHandleWrapper}; - -mod xr; -mod input; - -pub struct OpenXrPlugin { - pub wgpu_settings: WgpuSettings, -} - -#[derive(Resource)] -struct FutureXrResources ( - Arc< - Mutex< - Option< - () - > - > - > -); - -impl Plugin for OpenXrPlugin { - fn build(&self, app: &mut App) { - if let Some(backends) = self.wgpu_settings.backends { - let future_renderer_resources_wrapper = Arc::new(Mutex::new(None)); - let future_xr_resources_wrapper = Arc::new(Mutex::new(None)); - app.insert_resource(FutureRendererResources( - future_renderer_resources_wrapper.clone(), - )); - - app.insert_resource(FutureXrResources( - future_xr_resources_wrapper.clone(), - )); - - let mut system_state: SystemState>> = - SystemState::new(&mut app.world); - let primary_window = system_state.get(&app.world).get_single().ok().cloned(); - - let settings = self.wgpu_settings.clone(); - bevy::tasks::IoTaskPool::get() - .spawn_local(async move { - - }) - .detach(); - } - } -} diff --git a/srcold/xr/mod.rs b/srcold/xr/mod.rs deleted file mode 100644 index 94f05c7..0000000 --- a/srcold/xr/mod.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::cell::UnsafeCell; -use std::sync::atomic::AtomicBool; -use std::sync::Mutex; - -use glam::{Quat, Vec3}; -use openxr as xr; - -use crate::input::{PostFrameData, XrInput}; - -pub type XrPose = (Vec3, Quat); -pub const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO; - -pub enum XrState { - Vulkan(XrStateInner), -} - -pub struct XrStateInner { - instance: xr::Instance, - session: xr::Session, - session_running: AtomicBool, - frame: Mutex>, - frame_state: Mutex>, - post_frame_data: Mutex>, - event_buffer: UnsafeCell, - input: XrInput, -} - -unsafe impl Sync for XrStateInner {} -unsafe impl Send for XrStateInner {} - -impl XrStateInner { - pub fn preframe(&self) -> xr::Result<()> { - let event_buffer = unsafe { &mut *self.event_buffer.get() }; - while let Some(event) = self.instance.poll_event(event_buffer)? { - use xr::Event::*; - match event { - SessionStateChanged(e) => { - // Session state change is where we can begin and end sessions, as well as - // find quit messages! - match e.state() { - xr::SessionState::READY => { - self.session - .begin(VIEW_TYPE)?; // TODO! support other view types - self.session_running - .store(true, std::sync::atomic::Ordering::Relaxed); - } - xr::SessionState::STOPPING => { - self.session.end()?; - self.session_running - .store(false, std::sync::atomic::Ordering::Relaxed); - } - xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => { - *self.frame_state.lock().unwrap() = None; - return Ok(()); - } - _ => {} - } - } - InstanceLossPending(_) => { - *self.frame_state.lock().unwrap() = None; - return Ok(()); - } - EventsLost(e) => {} - _ => {} - } - } - if !self - .session_running - .load(std::sync::atomic::Ordering::Relaxed) - { - // Don't grind up the CPU - std::thread::sleep(std::time::Duration::from_millis(10)); - *self.frame_state.lock().unwrap() = None; - return Ok(()); - } - - *self.frame_state.lock().unwrap() = Some(self.frame.lock().unwrap().begin()?); - - Ok(()) - } - - pub fn post_frame(&self) -> xr::Result<(wgpu::TextureView, wgpu::TextureView)> { - *self.post_frame_data.lock().unwrap() = Some(self.input.post_frame(self.frame_state.lock().unwrap().unwrap().clone())?); - Ok(self.frame.lock().unwrap().get_render_views()) - } - - pub fn post_queue_submit(&self) -> xr::Result<()> { - let pfd = self.post_frame_data.lock().unwrap(); - self.frame.lock().unwrap().post_queue_submit(self.frame_state.lock().unwrap().unwrap().clone(), &(*pfd).clone().unwrap().views, self.input.stage()) - } -} - -pub struct FrameInner { - waiter: xr::FrameWaiter, - stream: xr::FrameStream, - blend_mode: xr::EnvironmentBlendMode, - views: Vec, - swapchain: xr::Swapchain, - resolution: Extent2D, - buffers: Vec, -} - -impl FrameInner { - fn begin(&mut self) -> xr::Result { - let frame_state = self.waiter.wait()?; - self.stream.begin()?; - Ok(frame_state) - } - - fn get_render_views(&mut self) -> (wgpu::TextureView, wgpu::TextureView) { - let image_index = self.swapchain.acquire_image().unwrap(); - self.swapchain.wait_image(xr::Duration::INFINITE).unwrap(); - - let texture = &self.buffers[image_index as usize]; - - ( - texture.create_view(&wgpu::TextureViewDescriptor { - dimension: Some(wgpu::TextureViewDimension::D2), - array_layer_count: Some(1), - base_array_layer: 0, - ..Default::default() - }), - texture.create_view(&wgpu::TextureViewDescriptor { - dimension: Some(wgpu::TextureViewDimension::D2), - array_layer_count: Some(1), - base_array_layer: 1, - ..Default::default() - }), - ) - } - - fn post_queue_submit( - &mut self, - xr_frame_state: xr::FrameState, - views: &[openxr::View], - stage: &xr::Space, - ) -> xr::Result<()> { - self.swapchain.release_image()?; - let rect = xr::Rect2Di { - offset: xr::Offset2Di { x: 0, y: 0 }, - extent: xr::Extent2Di { - width: self.resolution.width as _, - height: self.resolution.height as _, - }, - }; - self.stream.end( - xr_frame_state.predicted_display_time, - self.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(&self.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(&self.swapchain) - .image_array_index(1) - .image_rect(rect), - ), - ])], - )?; - - Ok(()) - } -} - -pub struct Extent2D { - pub width: u32, - pub height: u32, -}