From 713b2439cc9791d879fa7cfeb9ec7fb72e22a676 Mon Sep 17 00:00:00 2001 From: Jeffrey Winkler Date: Sat, 21 Sep 2024 17:25:01 +0200 Subject: [PATCH] implement XR_META_environment_depth --- openxr/src/environment_depth.rs | 353 ++++++++++++++++++++++++++++++++ openxr/src/graphics/d3d.rs | 42 ++++ openxr/src/graphics/headless.rs | 6 + openxr/src/graphics/mod.rs | 5 + openxr/src/graphics/opengl.rs | 21 ++ openxr/src/graphics/opengles.rs | 21 ++ openxr/src/graphics/vulkan.rs | 21 ++ openxr/src/lib.rs | 2 + 8 files changed, 471 insertions(+) create mode 100644 openxr/src/environment_depth.rs diff --git a/openxr/src/environment_depth.rs b/openxr/src/environment_depth.rs new file mode 100644 index 00000000..5ea7814c --- /dev/null +++ b/openxr/src/environment_depth.rs @@ -0,0 +1,353 @@ +//! The [Environment Depth feature](https://developer.oculus.com/documentation/native/android/mobile-depth/) +//! allows you to access depth maps based on the user environment. +//! This is primarily used to occlude virtual objects by real-world objects and surfaces. +//! +//! This feature is exclusive to the Oculus Quest 3 as of September 2024. +//! +//! More details about the environment depth feature can be found in the [OpenXR specification](https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth). +use crate::{ + cvt, raw, sys, Graphics, Instance, Result, Session, SessionInner, Space, SystemId, Time, View, +}; +use std::marker::PhantomData; +use std::ptr; +use std::sync::Arc; + +#[derive(Debug, Copy, Clone)] +pub struct SystemEnvironmentDepthProperties { + pub supports_environment_depth: bool, + pub supports_hand_removal: bool, +} + +impl Instance { + #[inline] + pub fn environment_depth_properties( + &self, + system: SystemId, + ) -> Result { + unsafe { + if self.exts().meta_environment_depth.is_none() { + return Err(sys::Result::ERROR_EXTENSION_NOT_PRESENT); + } + let mut env_depth = sys::SystemEnvironmentDepthPropertiesMETA::out(ptr::null_mut()); + let mut p = sys::SystemProperties::out(&mut env_depth as *mut _ as _); + cvt((self.fp().get_system_properties)( + self.as_raw(), + system, + p.as_mut_ptr(), + ))?; + Ok(env_depth.assume_init().into()) + } + } +} + +impl From for SystemEnvironmentDepthProperties { + fn from(value: sys::SystemEnvironmentDepthPropertiesMETA) -> Self { + SystemEnvironmentDepthProperties { + supports_environment_depth: value.supports_environment_depth.into(), + supports_hand_removal: value.supports_hand_removal.into(), + } + } +} + +impl Session { + #[inline] + /// Create an [`EnvironmentDepthProvider`]. + /// + /// Requires [`XR_META_environment_depth`]. + /// + /// [`XR_META_environment_depth`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth + /// [`EnvironmentDepthProvider`]: environment_depth/struct.EnvironmentDepthProvider.html + pub fn create_depth_environment_provider(&self) -> Result { + EnvironmentDepthProvider::create(self) + } + + #[inline] + /// Create an [`EnvironmentDepthSwapchain`]. + /// + /// Requires [`XR_META_environment_depth`]. + /// + /// [`XR_META_environment_depth`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth + /// [`EnvironmentDepthSwapchain`]: environment_depth/struct.EnvironmentDepthSwapchain.html + pub fn create_depth_environment_swapchain( + &self, + provider: &EnvironmentDepthProvider, + ) -> Result> { + EnvironmentDepthSwapchain::create(self, provider) + } +} + +/// An [Environment Depth Provider]. +/// +/// Requires [`XR_META_environment_depth`] to be enabled. +/// +/// See the [`EnvironmentDepthProviderMETA struct`]. +/// +/// [`XR_META_environment_depth`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth +/// [`EnvironmentDepthProviderMETA struct`]: https://docs.rs/openxr-sys/latest/openxr_sys/struct.EnvironmentDepthProviderMETA.html +/// [Environment Depth Provider]: https://developer.oculus.com/documentation/native/android/mobile-depth/#creating-a-depth-provider +pub struct EnvironmentDepthProvider { + pub(crate) session: Arc, + handle: sys::EnvironmentDepthProviderMETA, +} + +impl EnvironmentDepthProvider { + /// [Create] an environment depth provider. + /// + /// [Create]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrCreateEnvironmentDepthProviderMETA + pub(crate) fn create(session: &Session) -> Result { + let info = sys::EnvironmentDepthProviderCreateInfoMETA { + ty: sys::EnvironmentDepthProviderCreateInfoMETA::TYPE, + next: ptr::null(), + create_flags: sys::EnvironmentDepthProviderCreateFlagsMETA::EMPTY, + }; + let fp = fp(&session.inner); + let mut handle = sys::EnvironmentDepthProviderMETA::NULL; + unsafe { + cvt((fp.create_environment_depth_provider)( + session.as_raw(), + &info, + &mut handle, + ))?; + } + Ok(EnvironmentDepthProvider { + session: session.inner.clone(), + handle, + }) + } + + /// [Start] an environment depth provider. + /// + /// [Start]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrStartEnvironmentDepthProviderMETA + pub fn start(&self) -> Result<()> { + let fp = fp(&self.session); + unsafe { + cvt((fp.start_environment_depth_provider)(self.handle))?; + } + Ok(()) + } + + /// [Stop] an environment depth provider. + /// + /// [Stop]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrStopEnvironmentDepthProviderMETA + pub fn stop(&self) -> Result<()> { + let fp = fp(&self.session); + unsafe { + cvt((fp.stop_environment_depth_provider)(self.handle))?; + } + Ok(()) + } + + /// Set the [hand removal option]. + /// + /// [hand removal option]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrSetEnvironmentDepthHandRemovalMETA + pub fn set_hand_removal(&self, enabled: bool) -> Result<()> { + let info = sys::EnvironmentDepthHandRemovalSetInfoMETA { + ty: sys::EnvironmentDepthHandRemovalSetInfoMETA::TYPE, + next: ptr::null(), + enabled: enabled.into(), + }; + let fp = fp(&self.session); + unsafe { + cvt((fp.set_environment_depth_hand_removal)(self.handle, &info))?; + } + Ok(()) + } + + /// [Acquire] the latest available swapchain image that has been generated. + /// + /// [Acquire]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrAcquireEnvironmentDepthImageMETA + pub fn acquire_image( + &self, + space: &Space, + display_time: Time, + ) -> Result { + let info = sys::EnvironmentDepthImageAcquireInfoMETA { + ty: sys::EnvironmentDepthImageAcquireInfoMETA::TYPE, + next: ptr::null(), + space: space.as_raw(), + display_time, + }; + let fp = fp(&self.session); + let default_img_view = sys::EnvironmentDepthImageViewMETA { + ty: sys::EnvironmentDepthImageViewMETA::TYPE, + next: ptr::null(), + pose: sys::Posef::default(), + fov: sys::Fovf::default(), + }; + let mut img = sys::EnvironmentDepthImageMETA { + ty: sys::EnvironmentDepthImageMETA::TYPE, + next: ptr::null(), + near_z: 0.0, + far_z: 0.0, + swapchain_index: 0, + views: [default_img_view, default_img_view], + }; + unsafe { + cvt((fp.acquire_environment_depth_image)( + self.handle, + &info, + &mut img, + ))?; + Ok(img.into()) + } + } +} + +impl Drop for EnvironmentDepthProvider { + fn drop(&mut self) { + unsafe { + ((fp(&self.session).destroy_environment_depth_provider)(self.handle)); + } + } +} + +/// An [Environment Depth Swapchain]. +/// +/// Requires [`XR_META_environment_depth`] to be enabled. +/// +/// See the [`EnvironmentDepthSwapchainMETA struct`]. +/// +/// [`XR_META_environment_depth`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth +/// [`EnvironmentDepthSwapchainMETA struct`]: https://docs.rs/openxr-sys/latest/openxr_sys/struct.EnvironmentDepthSwapchainMETA.html +/// [Environment Depth Swapchain]: https://developer.oculus.com/documentation/native/android/mobile-depth/#creating-and-enumerating-a-depth-swapchain +pub struct EnvironmentDepthSwapchain { + pub(crate) session: Arc, + pub(crate) handle: sys::EnvironmentDepthSwapchainMETA, + _marker: PhantomData, +} + +impl EnvironmentDepthSwapchain { + /// [Create] an environment depth swapchain. + /// + /// [Create]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrCreateEnvironmentDepthSwapchainMETA + pub(crate) fn create( + session: &Session, + provider: &EnvironmentDepthProvider, + ) -> Result { + let info = sys::EnvironmentDepthSwapchainCreateInfoMETA { + ty: sys::EnvironmentDepthSwapchainCreateInfoMETA::TYPE, + next: ptr::null(), + create_flags: sys::EnvironmentDepthSwapchainCreateFlagsMETA::EMPTY, + }; + let fp = fp(&session.inner); + let mut handle = sys::EnvironmentDepthSwapchainMETA::NULL; + unsafe { + cvt((fp.create_environment_depth_swapchain)( + provider.handle, + &info, + &mut handle, + ))?; + } + Ok(EnvironmentDepthSwapchain { + session: session.inner.clone(), + handle, + _marker: PhantomData, + }) + } + + /// Retrieve the [environment depth swapchain state]. + /// + /// [environment depth swapchain state]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrGetEnvironmentDepthSwapchainStateMETA + pub fn get_state(&self) -> Result { + let fp = fp(&self.session); + let mut state = sys::EnvironmentDepthSwapchainStateMETA { + ty: sys::EnvironmentDepthSwapchainStateMETA::TYPE, + next: ptr::null_mut(), + width: 0, + height: 0, + }; + unsafe { + cvt((fp.get_environment_depth_swapchain_state)( + self.handle, + &mut state, + ))?; + Ok(state.into()) + } + } + + #[inline] + /// [Enumerate] the environment depth swapchain images. + /// + /// [`Enumerate`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#xrEnumerateEnvironmentDepthSwapchainImagesMETA + pub fn enumerate_images(&self) -> Result> { + G::enumerate_depth_environment_swapchain_images(self) + } + + #[inline] + pub(crate) fn fp(&self) -> &raw::EnvironmentDepthMETA { + fp(&self.session) + } +} + +impl Drop for EnvironmentDepthSwapchain { + fn drop(&mut self) { + unsafe { + ((fp(&self.session).destroy_environment_depth_swapchain)(self.handle)); + } + } +} + +/// An [Environment Depth Swapchain State]. +/// +/// Requires [`XR_META_environment_depth`] to be enabled. +/// +/// See the [`EnvironmentDepthSwapchainStateMETA struct`]. +/// +/// [`XR_META_environment_depth`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth +/// [`EnvironmentDepthSwapchainStateMETA struct`]: https://docs.rs/openxr-sys/latest/openxr_sys/struct.EnvironmentDepthSwapchainStateMETA.html +/// [Environment Depth Swapchain State]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XrEnvironmentDepthSwapchainStateMETA +#[derive(Debug, Copy, Clone)] +pub struct EnvironmentDepthSwapchainState { + pub width: u32, + pub height: u32, +} + +impl From for EnvironmentDepthSwapchainState { + fn from(value: sys::EnvironmentDepthSwapchainStateMETA) -> Self { + EnvironmentDepthSwapchainState { + width: value.width, + height: value.height, + } + } +} + +/// An [Environment Depth Image]. +/// +/// Requires [`XR_META_environment_depth`] to be enabled. +/// +/// See the [`EnvironmentDepthImageMETA struct`]. +/// +/// [`XR_META_environment_depth`]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_META_environment_depth +/// [`EnvironmentDepthImageMETA struct`]: https://docs.rs/openxr-sys/latest/openxr_sys/struct.EnvironmentDepthImageMETA.html +/// [Environment Depth Image]: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XrEnvironmentDepthImageMETA +#[derive(Copy, Clone)] +pub struct EnvironmentDepthImage { + pub swapchain_index: u32, + pub near_z: f32, + pub far_z: f32, + pub views: [View; 2], +} + +impl From for EnvironmentDepthImage { + fn from(value: sys::EnvironmentDepthImageMETA) -> Self { + EnvironmentDepthImage { + swapchain_index: value.swapchain_index, + near_z: value.near_z, + far_z: value.far_z, + views: value.views.map(|v| View { + pose: v.pose, + fov: v.fov, + }), + } + } +} + +#[inline] +fn fp(session: &SessionInner) -> &raw::EnvironmentDepthMETA { + session + .instance + .exts() + .meta_environment_depth + .as_ref() + .expect("`XR_META_environment_depth` not loaded") +} diff --git a/openxr/src/graphics/d3d.rs b/openxr/src/graphics/d3d.rs index 03bdbcf2..b698d411 100644 --- a/openxr/src/graphics/d3d.rs +++ b/openxr/src/graphics/d3d.rs @@ -85,6 +85,27 @@ impl Graphics for D3D11 { )?; Ok(images.into_iter().map(|x| x.texture).collect()) } + + fn enumerate_depth_environment_swapchain_images( + swapchain: &EnvironmentDepthSwapchain, + ) -> Result> { + let images = get_arr_init( + sys::SwapchainImageD3D11KHR { + ty: sys::SwapchainImageD3D11KHR::TYPE, + next: ptr::null_mut(), + texture: ptr::null_mut(), + }, + |capacity, count, buf| unsafe { + (swapchain.fp().enumerate_environment_depth_swapchain_images)( + swapchain.handle, + capacity, + count, + buf as *mut _, + ) + }, + )?; + Ok(images.into_iter().map(|x| x.texture as _).collect()) + } } /// The D3D12 graphics API @@ -169,6 +190,27 @@ impl Graphics for D3D12 { )?; Ok(images.into_iter().map(|x| x.texture).collect()) } + + fn enumerate_depth_environment_swapchain_images( + swapchain: &EnvironmentDepthSwapchain, + ) -> Result> { + let images = get_arr_init( + sys::SwapchainImageD3D12KHR { + ty: sys::SwapchainImageD3D12KHR::TYPE, + next: ptr::null_mut(), + texture: ptr::null_mut(), + }, + |capacity, count, buf| unsafe { + (swapchain.fp().enumerate_environment_depth_swapchain_images)( + swapchain.handle, + capacity, + count, + buf as *mut _, + ) + }, + )?; + Ok(images.into_iter().map(|x| x.texture as _).collect()) + } } #[derive(Copy, Clone)] diff --git a/openxr/src/graphics/headless.rs b/openxr/src/graphics/headless.rs index 6d0b5203..a8ff3732 100644 --- a/openxr/src/graphics/headless.rs +++ b/openxr/src/graphics/headless.rs @@ -53,6 +53,12 @@ impl Graphics for Headless { // enumerate 0 formats, and so it's not possible to create a swapchain unreachable!(); } + + fn enumerate_depth_environment_swapchain_images( + _swapchain: &EnvironmentDepthSwapchain, + ) -> Result> { + unreachable!(); + } } #[derive(Clone, Copy)] diff --git a/openxr/src/graphics/mod.rs b/openxr/src/graphics/mod.rs index 1820a51d..f7f54c7e 100644 --- a/openxr/src/graphics/mod.rs +++ b/openxr/src/graphics/mod.rs @@ -32,6 +32,11 @@ pub trait Graphics: Sized { #[doc(hidden)] fn enumerate_swapchain_images(swapchain: &Swapchain) -> Result>; + + #[doc(hidden)] + fn enumerate_depth_environment_swapchain_images( + swapchain: &EnvironmentDepthSwapchain, + ) -> Result>; } #[cfg(windows)] diff --git a/openxr/src/graphics/opengl.rs b/openxr/src/graphics/opengl.rs index 7972ff89..99147587 100644 --- a/openxr/src/graphics/opengl.rs +++ b/openxr/src/graphics/opengl.rs @@ -141,6 +141,27 @@ impl Graphics for OpenGL { )?; Ok(images.into_iter().map(|x| x.image).collect()) } + + fn enumerate_depth_environment_swapchain_images( + swapchain: &EnvironmentDepthSwapchain, + ) -> Result> { + let images = get_arr_init( + sys::SwapchainImageOpenGLKHR { + ty: sys::SwapchainImageOpenGLKHR::TYPE, + next: ptr::null_mut(), + image: 0, + }, + |capacity, count, buf| unsafe { + (swapchain.fp().enumerate_environment_depth_swapchain_images)( + swapchain.handle, + capacity, + count, + buf as *mut _, + ) + }, + )?; + Ok(images.into_iter().map(|x| x.image as _).collect()) + } } #[derive(Copy, Clone)] diff --git a/openxr/src/graphics/opengles.rs b/openxr/src/graphics/opengles.rs index 765df642..2f9675da 100644 --- a/openxr/src/graphics/opengles.rs +++ b/openxr/src/graphics/opengles.rs @@ -98,6 +98,27 @@ impl Graphics for OpenGlEs { )?; Ok(images.into_iter().map(|x| x.image).collect()) } + + fn enumerate_depth_environment_swapchain_images( + swapchain: &EnvironmentDepthSwapchain, + ) -> Result> { + let images = get_arr_init( + sys::SwapchainImageOpenGLESKHR { + ty: sys::SwapchainImageOpenGLESKHR::TYPE, + next: ptr::null_mut(), + image: 0, + }, + |capacity, count, buf| unsafe { + (swapchain.fp().enumerate_environment_depth_swapchain_images)( + swapchain.handle, + capacity, + count, + buf as *mut _, + ) + }, + )?; + Ok(images.into_iter().map(|x| x.image as _).collect()) + } } #[derive(Copy, Clone)] diff --git a/openxr/src/graphics/vulkan.rs b/openxr/src/graphics/vulkan.rs index 8e0d970b..c87c01ac 100644 --- a/openxr/src/graphics/vulkan.rs +++ b/openxr/src/graphics/vulkan.rs @@ -90,6 +90,27 @@ impl Graphics for Vulkan { )?; Ok(images.into_iter().map(|x| x.image as _).collect()) } + + fn enumerate_depth_environment_swapchain_images( + swapchain: &EnvironmentDepthSwapchain, + ) -> Result> { + let images = get_arr_init( + sys::SwapchainImageVulkanKHR { + ty: sys::SwapchainImageVulkanKHR::TYPE, + next: ptr::null_mut(), + image: 0, + }, + |capacity, count, buf| unsafe { + (swapchain.fp().enumerate_environment_depth_swapchain_images)( + swapchain.handle, + capacity, + count, + buf as *mut _, + ) + }, + )?; + Ok(images.into_iter().map(|x| x.image as _).collect()) + } } #[derive(Debug, Copy, Clone)] diff --git a/openxr/src/lib.rs b/openxr/src/lib.rs index c32ca523..cf13f8c8 100644 --- a/openxr/src/lib.rs +++ b/openxr/src/lib.rs @@ -42,6 +42,8 @@ mod passthrough; pub use passthrough::*; mod localization_map_ml; pub use localization_map_ml::*; +mod environment_depth; +pub use environment_depth::*; pub use builder::{ CompositionLayerBase, CompositionLayerCubeKHR, CompositionLayerCylinderKHR,