updated documentation and resources

This commit is contained in:
awtterpip
2024-04-25 21:05:37 -05:00
parent 0b93358aa6
commit b2b40ba95a
6 changed files with 256 additions and 21 deletions

View File

@@ -4,8 +4,9 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[features] [features]
default = ["vulkan"] default = ["vulkan", "passthrough"]
vulkan = ["dep:ash"] vulkan = ["dep:ash"]
passthrough = []
# bevy can't be placed behind target or proc macros won't work properly # bevy can't be placed behind target or proc macros won't work properly
[dependencies] [dependencies]

View File

@@ -0,0 +1,2 @@
#[cfg(feature = "passthrough")]
pub mod passthrough;

View File

@@ -0,0 +1,59 @@
use bevy::prelude::*;
use openxr::sys::SystemPassthroughProperties2FB;
use openxr::PassthroughCapabilityFlagsFB;
use crate::resources::*;
use crate::types::*;
pub struct OxrPassthroughPlugin;
impl Plugin for OxrPassthroughPlugin {
fn build(&self, _app: &mut App) {
todo!()
}
}
pub fn create_passthrough(
session: &OxrSession,
flags: openxr::PassthroughFlagsFB,
purpose: openxr::PassthroughLayerPurposeFB,
) -> Result<(OxrPassthrough, OxrPassthroughLayer)> {
let passthrough = session.create_passthrough(flags)?;
let passthrough_layer = session.create_passthrough_layer(&passthrough, purpose)?;
Ok((passthrough, passthrough_layer))
}
#[inline]
pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> Result<bool> {
unsafe {
let mut hand = 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 _);
cvt((instance.fp().get_system_properties)(
instance.as_raw(),
system.0,
p.as_mut_ptr(),
))?;
bevy::log::info!(
"From supports_passthrough: Passthrough capabilities: {:?}",
hand.capabilities
);
Ok(
(hand.capabilities & PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY)
== PassthroughCapabilityFlagsFB::PASSTHROUGH_CAPABILITY,
)
}
}
fn cvt(x: openxr::sys::Result) -> openxr::Result<openxr::sys::Result> {
if x.into_raw() >= 0 {
Ok(x)
} else {
Err(x)
}
}

View File

@@ -3,7 +3,7 @@ use std::mem;
use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di, Space}; use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di, Space};
use crate::graphics::graphics_match; use crate::graphics::graphics_match;
use crate::resources::OxrSwapchain; use crate::resources::{OxrPassthroughLayer, OxrSwapchain};
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct SwapchainSubImage<'a> { pub struct SwapchainSubImage<'a> {
@@ -105,7 +105,7 @@ impl<'a> Default for CompositionLayerProjectionView<'a> {
} }
pub unsafe trait CompositionLayer<'a> { pub unsafe trait CompositionLayer<'a> {
fn swapchain(&self) -> Option<&'a OxrSwapchain>; fn swapchain(&self) -> Option<&'a OxrSwapchain>;
fn header(&self) -> &'a sys::CompositionLayerBaseHeader; fn header(&self) -> &sys::CompositionLayerBaseHeader;
} }
#[derive(Clone)] #[derive(Clone)]
pub struct CompositionLayerProjection<'a> { pub struct CompositionLayerProjection<'a> {
@@ -158,8 +158,8 @@ unsafe impl<'a> CompositionLayer<'a> for CompositionLayerProjection<'a> {
self.swapchain self.swapchain
} }
fn header(&self) -> &'a sys::CompositionLayerBaseHeader { fn header(&self) -> &sys::CompositionLayerBaseHeader {
unsafe { std::mem::transmute(&self.inner) } unsafe { mem::transmute(&self.inner) }
} }
} }
impl<'a> Default for CompositionLayerProjection<'a> { impl<'a> Default for CompositionLayerProjection<'a> {
@@ -167,3 +167,36 @@ impl<'a> Default for CompositionLayerProjection<'a> {
Self::new() Self::new()
} }
} }
pub struct CompositionLayerPassthrough {
inner: sys::CompositionLayerPassthroughFB,
}
impl CompositionLayerPassthrough {
#[inline]
pub fn new() -> Self {
Self {
inner: openxr::sys::CompositionLayerPassthroughFB {
ty: openxr::sys::CompositionLayerPassthroughFB::TYPE,
..unsafe { mem::zeroed() }
},
}
}
#[inline]
pub fn layer_handle(mut self, layer_handle: &OxrPassthroughLayer) -> Self {
self.inner.layer_handle = *layer_handle.inner();
self
}
#[inline]
pub fn layer_flags(mut self, value: CompositionLayerFlags) -> Self {
self.inner.flags = value;
self
}
}
unsafe impl<'a> CompositionLayer<'a> for CompositionLayerPassthrough {
fn swapchain(&self) -> Option<&'a OxrSwapchain> {
None
}
fn header(&self) -> &sys::CompositionLayerBaseHeader {
unsafe { mem::transmute(&self.inner) }
}
}

View File

@@ -12,6 +12,7 @@ use render::OxrRenderPlugin;
pub mod error; pub mod error;
mod exts; mod exts;
pub mod features;
pub mod graphics; pub mod graphics;
pub mod init; pub mod init;
pub mod layer_builder; pub mod layer_builder;

View File

@@ -10,7 +10,9 @@ use crate::graphics::*;
use crate::layer_builder::CompositionLayer; use crate::layer_builder::CompositionLayer;
use crate::types::*; use crate::types::*;
/// Wrapper around the entry point to the OpenXR API /// Wrapper around an [`Entry`](openxr::Entry) with some methods overridden to use bevy types.
///
/// See [`openxr::Entry`] for other available methods.
#[derive(Deref, Clone)] #[derive(Deref, Clone)]
pub struct OxrEntry(pub openxr::Entry); pub struct OxrEntry(pub openxr::Entry);
@@ -20,6 +22,9 @@ impl OxrEntry {
Ok(self.0.enumerate_extensions().map(Into::into)?) Ok(self.0.enumerate_extensions().map(Into::into)?)
} }
/// Creates an [`OxrInstance`].
///
/// Calls [`create_instance`](openxr::Entry::create_instance) internally.
pub fn create_instance( pub fn create_instance(
&self, &self,
app_info: AppInfo, app_info: AppInfo,
@@ -49,6 +54,7 @@ impl OxrEntry {
Ok(OxrInstance(instance, backend, app_info)) Ok(OxrInstance(instance, backend, app_info))
} }
/// Returns a list of all of the backends the OpenXR runtime supports.
pub fn available_backends(&self) -> Result<Vec<GraphicsBackend>> { pub fn available_backends(&self) -> Result<Vec<GraphicsBackend>> {
Ok(GraphicsBackend::available_backends( Ok(GraphicsBackend::available_backends(
&self.enumerate_extensions()?, &self.enumerate_extensions()?,
@@ -56,20 +62,48 @@ impl OxrEntry {
} }
} }
/// Wrapper around [openxr::Instance] with additional data for safety. /// Wrapper around [`openxr::Instance`] with additional data for safety and some methods overriden to use bevy types.
///
/// See [`openxr::Instance`] for other available methods.
#[derive(Resource, Deref, Clone)] #[derive(Resource, Deref, Clone)]
pub struct OxrInstance( pub struct OxrInstance(
#[deref] pub openxr::Instance, #[deref] pub(crate) openxr::Instance,
/// [`GraphicsBackend`] is stored here to let us know what graphics API the current instance wants to target.
pub(crate) GraphicsBackend, pub(crate) GraphicsBackend,
pub(crate) AppInfo, pub(crate) AppInfo,
); );
impl OxrInstance { impl OxrInstance {
/// Creates an [`OxrInstance`] from an [`openxr::Instance`] if needed.
/// In the majority of cases, you should use [`create_instance`](OxrEntry::create_instance) instead.
///
/// # Safety
///
/// The OpenXR instance passed in *must* have support for the backend specified.
pub unsafe fn from_inner(
instance: openxr::Instance,
backend: GraphicsBackend,
info: AppInfo,
) -> Self {
Self(instance, backend, info)
}
/// Consumes self and returns the inner [`openxr::Instance`]
pub fn into_inner(self) -> openxr::Instance { pub fn into_inner(self) -> openxr::Instance {
self.0 self.0
} }
/// Initialize graphics. This is used to create [WgpuGraphics] for the bevy app and to get the [SessionCreateInfo] to make an XR session. /// Returns the current backend being used by this instance.
pub fn backend(&self) -> GraphicsBackend {
self.1
}
/// Returns the [`AppInfo`] being used by this instance.
pub fn app_info(&self) -> &AppInfo {
&self.2
}
/// Initialize graphics. This is used to create [WgpuGraphics] for the bevy app and to get the [SessionCreateInfo] needed to make an XR session.
pub fn init_graphics( pub fn init_graphics(
&self, &self,
system_id: openxr::SystemId, system_id: openxr::SystemId,
@@ -86,6 +120,8 @@ impl OxrInstance {
/// Creates an [OxrSession] /// Creates an [OxrSession]
/// ///
/// Calls [`create_session`](openxr::Instance::create_session) internally.
///
/// # Safety /// # Safety
/// ///
/// `info` must contain valid handles for the graphics api /// `info` must contain valid handles for the graphics api
@@ -111,11 +147,18 @@ impl OxrInstance {
} }
} }
/// Graphics agnostic wrapper around [openxr::Session] /// Graphics agnostic wrapper around [openxr::Session].
///
/// See [`openxr::Session`] for other available methods.
#[derive(Resource, Deref, Clone)] #[derive(Resource, Deref, Clone)]
pub struct OxrSession( pub struct OxrSession(
#[deref] pub openxr::Session<AnyGraphics>, /// A session handle with [`AnyGraphics`].
pub GraphicsWrap<Self>, /// Having this here allows the majority of [`Session`](openxr::Session)'s methods to work without having to rewrite them.
#[deref]
pub(crate) openxr::Session<AnyGraphics>,
/// A [`GraphicsWrap`] with [`openxr::Session<G>`] 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<Self>,
); );
impl GraphicsType for OxrSession { impl GraphicsType for OxrSession {
@@ -124,16 +167,27 @@ impl GraphicsType for OxrSession {
impl<G: GraphicsExt> From<openxr::Session<G>> for OxrSession { impl<G: GraphicsExt> From<openxr::Session<G>> for OxrSession {
fn from(session: openxr::Session<G>) -> Self { fn from(session: openxr::Session<G>) -> Self {
Self::new(session) Self::from_inner(session)
} }
} }
impl OxrSession { impl OxrSession {
pub fn new<G: GraphicsExt>(session: openxr::Session<G>) -> Self { /// 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<G: GraphicsExt>(session: openxr::Session<G>) -> Self {
Self(session.clone().into_any_graphics(), G::wrap(session)) Self(session.clone().into_any_graphics(), G::wrap(session))
} }
/// Enumerate all available swapchain formats. /// Returns [`GraphicsWrap`] with [`openxr::Session<G>`] 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> {
&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<Vec<wgpu::TextureFormat>> { pub fn enumerate_swapchain_formats(&self) -> Result<Vec<wgpu::TextureFormat>> {
graphics_match!( graphics_match!(
&self.1; &self.1;
@@ -142,14 +196,75 @@ impl OxrSession {
} }
/// Creates an [OxrSwapchain]. /// Creates an [OxrSwapchain].
///
/// Calls [`create_swapchain`](openxr::Session::create_swapchain) internally.
pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result<OxrSwapchain> { pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result<OxrSwapchain> {
Ok(OxrSwapchain(graphics_match!( Ok(OxrSwapchain(graphics_match!(
&self.1; &self.1;
session => session.create_swapchain(&info.try_into()?)? => OxrSwapchain 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<OxrPassthrough> {
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<OxrPassthroughLayer> {
Ok(OxrPassthroughLayer(graphics_match! {
&self.1;
session => session.create_passthrough_layer(&passthrough.0, passthrough.1, purpose)?
}))
}
}
/// Wrapper around [`openxr::Passthrough`].
///
/// Used to [`start`](openxr::Passthrough::start) or [`pause`](openxr::Passthrough::pause) passthrough on the physical device.
///
/// See [`openxr::Passthrough`] for available methods.
#[derive(Resource, Deref, DerefMut)]
pub struct OxrPassthrough(
#[deref] pub openxr::Passthrough,
/// The flags are stored here so that they don't need to be passed in again when creating an [`OxrPassthroughLayer`].
openxr::PassthroughFlagsFB,
);
impl OxrPassthrough {
/// This function can create an [`OxrPassthrough`] from raw openxr types if needed.
/// In the majority of cases, you should use [`create_passthrough`](OxrSession::create_passthrough) instead.
pub fn from_inner(passthrough: openxr::Passthrough, flags: openxr::PassthroughFlagsFB) -> Self {
Self(passthrough, flags)
}
}
/// Wrapper around [`openxr::Passthrough`].
///
/// Used to create a [`CompositionLayerPassthrough`](crate::layer_builder::CompositionLayerPassthrough), and to [`pause`](openxr::PassthroughLayer::pause) or [`resume`](openxr::PassthroughLayer::resume) rendering of the passthrough layer.
///
/// See [`openxr::PassthroughLayer`] for available methods.
#[derive(Resource, Deref, DerefMut)]
pub struct OxrPassthroughLayer(pub openxr::PassthroughLayer);
/// Graphics agnostic wrapper around [openxr::FrameStream] /// Graphics agnostic wrapper around [openxr::FrameStream]
#[derive(Resource)] #[derive(Resource)]
pub struct OxrFrameStream(pub GraphicsWrap<Self>); pub struct OxrFrameStream(pub GraphicsWrap<Self>);
@@ -159,7 +274,15 @@ impl GraphicsType for OxrFrameStream {
} }
impl OxrFrameStream { impl OxrFrameStream {
/// Creates a new [`OxrFrameStream`] from an [`openxr::FrameStream`].
/// In the majority of cases, you should use [`create_session`](OxrInstance::create_session) instead.
pub fn from_inner<G: GraphicsExt>(frame_stream: openxr::FrameStream<G>) -> Self {
Self(G::wrap(frame_stream))
}
/// Indicate that graphics device work is beginning. /// Indicate that graphics device work is beginning.
///
/// Calls [`begin`](openxr::FrameStream::begin) internally.
pub fn begin(&mut self) -> openxr::Result<()> { pub fn begin(&mut self) -> openxr::Result<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
@@ -169,8 +292,8 @@ impl OxrFrameStream {
/// Indicate that all graphics work for the frame has been submitted /// Indicate that all graphics work for the frame has been submitted
/// ///
/// `layers` is an array of references to any type of composition layer, /// `layers` is an array of references to any type of composition layer that implements [`CompositionLayer`],
/// e.g. [`CompositionLayerProjection`](crate::oxr::layer_builder::CompositionLayerProjection) /// e.g. [`CompositionLayerProjection`](crate::layer_builder::CompositionLayerProjection)
pub fn end( pub fn end(
&mut self, &mut self,
display_time: openxr::Time, display_time: openxr::Time,
@@ -202,7 +325,9 @@ impl OxrFrameStream {
} }
} }
/// Handle for waiting to render a frame. Check [`FrameWaiter`](openxr::FrameWaiter) for available methods. /// Handle for waiting to render a frame.
///
/// See [`FrameWaiter`](openxr::FrameWaiter) for available methods.
#[derive(Resource, Deref, DerefMut)] #[derive(Resource, Deref, DerefMut)]
pub struct OxrFrameWaiter(pub openxr::FrameWaiter); pub struct OxrFrameWaiter(pub openxr::FrameWaiter);
@@ -215,7 +340,15 @@ impl GraphicsType for OxrSwapchain {
} }
impl OxrSwapchain { impl OxrSwapchain {
/// Determine the index of the next image to render to in the swapchain image array /// Creates a new [`OxrSwapchain`] from an [`openxr::Swapchain`].
/// In the majority of cases, you should use [`create_swapchain`](OxrSession::create_swapchain) instead.
pub fn from_inner<G: GraphicsExt>(swapchain: openxr::Swapchain<G>) -> Self {
Self(G::wrap(swapchain))
}
/// Determine the index of the next image to render to in the swapchain image array.
///
/// Calls [`acquire_image`](openxr::Swapchain::acquire_image) internally.
pub fn acquire_image(&mut self) -> Result<u32> { pub fn acquire_image(&mut self) -> Result<u32> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
@@ -223,7 +356,9 @@ impl OxrSwapchain {
) )
} }
/// Wait for the compositor to finish reading from the oldest unwaited acquired image /// Wait for the compositor to finish reading from the oldest unwaited acquired image.
///
/// Calls [`wait_image`](openxr::Swapchain::wait_image) internally.
pub fn wait_image(&mut self, timeout: openxr::Duration) -> Result<()> { pub fn wait_image(&mut self, timeout: openxr::Duration) -> Result<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
@@ -231,7 +366,9 @@ impl OxrSwapchain {
) )
} }
/// Release the oldest acquired image /// Release the oldest acquired image.
///
/// Calls [`release_image`](openxr::Swapchain::release_image) internally.
pub fn release_image(&mut self) -> Result<()> { pub fn release_image(&mut self) -> Result<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
@@ -240,6 +377,8 @@ impl OxrSwapchain {
} }
/// Enumerates swapchain images and converts them to wgpu [`Texture`](wgpu::Texture)s. /// Enumerates swapchain images and converts them to wgpu [`Texture`](wgpu::Texture)s.
///
/// Calls [`enumerate_images`](openxr::Swapchain::enumerate_images) internally.
pub fn enumerate_images( pub fn enumerate_images(
&self, &self,
device: &wgpu::Device, device: &wgpu::Device,