use std::ffi::c_void; use crate::next_chain::{OxrNextChain, OxrNextChainStructBase, OxrNextChainStructProvider}; use crate::resources::{OxrPassthrough, OxrPassthroughLayer, OxrSwapchain}; use crate::types::{Result, SwapchainCreateInfo}; use bevy::prelude::*; use openxr::AnyGraphics; use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap}; /// Graphics agnostic wrapper around [openxr::Session]. /// /// See [`openxr::Session`] for other available methods. #[derive(Resource, Deref, Clone)] pub struct OxrSession( /// A session handle with [`AnyGraphics`]. /// Having this here allows the majority of [`Session`](openxr::Session)'s methods to work without having to rewrite them. #[deref] pub(crate) openxr::Session, /// A [`GraphicsWrap`] with [`openxr::Session`] as the inner type. /// This is so that we can still operate on functions that don't take [`AnyGraphics`] as the generic. pub(crate) GraphicsWrap, ); impl GraphicsType for OxrSession { type Inner = openxr::Session; } impl From> for OxrSession { fn from(session: openxr::Session) -> Self { Self::from_inner(session) } } impl OxrSession { /// Creates a new [`OxrSession`] from an [`openxr::Session`]. /// In the majority of cases, you should use [`create_session`](OxrInstance::create_session) instead. pub fn from_inner(session: openxr::Session) -> Self { Self(session.clone().into_any_graphics(), G::wrap(session)) } /// Returns [`GraphicsWrap`] with [`openxr::Session`] as the inner type. /// /// This can be useful if you need access to the original [`openxr::Session`] with the graphics API still specified. pub fn typed_session(&self) -> &GraphicsWrap { &self.1 } /// Enumerates all available swapchain formats and converts them to wgpu's [`TextureFormat`](wgpu::TextureFormat). /// /// Calls [`enumerate_swapchain_formats`](openxr::Session::enumerate_swapchain_formats) internally. pub fn enumerate_swapchain_formats(&self) -> Result> { graphics_match!( &self.1; session => Ok(session.enumerate_swapchain_formats()?.into_iter().filter_map(Api::into_wgpu_format).collect()) ) } /// Creates an [OxrSwapchain]. /// /// Calls [`create_swapchain`](openxr::Session::create_swapchain) internally. pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result { Ok(OxrSwapchain(graphics_match!( &self.1; session => session.create_swapchain(&info.try_into()?)? => OxrSwapchain ))) } /// Creates a passthrough. /// /// Requires [`XR_FB_passthrough`](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_FB_passthrough). /// /// Calls [`create_passthrough`](openxr::Session::create_passthrough) internally. pub fn create_passthrough(&self, flags: openxr::PassthroughFlagsFB) -> Result { Ok(OxrPassthrough( graphics_match! { &self.1; session => session.create_passthrough(flags)? }, flags, )) } /// Creates a passthrough layer that can be used to make a [`CompositionLayerPassthrough`](crate::layer_builder::CompositionLayerPassthrough) for frame submission. /// /// Requires [`XR_FB_passthrough`](https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#XR_FB_passthrough). /// /// Calls [`create_passthrough_layer`](openxr::Session::create_passthrough_layer) internally. pub fn create_passthrough_layer( &self, passthrough: &OxrPassthrough, purpose: openxr::PassthroughLayerPurposeFB, ) -> Result { Ok(OxrPassthroughLayer(graphics_match! { &self.1; session => session.create_passthrough_layer(&passthrough.0, passthrough.1, purpose)? })) } } pub trait OxrSessionCreateNextProvider: OxrNextChainStructProvider {} /// NonSend Resource #[derive(Default)] pub struct OxrSessionCreateNextChain(OxrNextChain); impl OxrSessionCreateNextChain { pub fn push(&mut self, info_struct: T) { self.0.push(info_struct) } pub fn chain(&self) -> Option<&OxrNextChainStructBase> { self.0.chain() } pub fn chain_pointer(&self) -> *const c_void { self.0.chain_pointer() } }