mirror of
https://github.com/mii443/rust-openvr.git
synced 2025-08-22 16:25:36 +00:00
174 lines
8.2 KiB
Rust
174 lines
8.2 KiB
Rust
//! The `Compositor` implements distortion, prediction, synchronization and other subtle issues that can be a challenge to
|
|
//! get operating properly for a solid VR experience.
|
|
//!
|
|
//! Applications call WaitGetPoses to get the set of poses used to render the camera and other tracked objects, render
|
|
//! the left and right eyes as normal (using the info provided by `System`) and finally `submit` those undistorted
|
|
//! textures for the `Compositor` to display on the output device.
|
|
//!
|
|
//! It is recommended that you continue presenting your application's own window, reusing either the left or right eye
|
|
//! camera render target to draw a single quad (perhaps cropped to a lower fov to hide the hidden area mask).
|
|
|
|
use std::{mem, ptr, error, fmt};
|
|
use std::ffi::CString;
|
|
|
|
use openvr_sys as sys;
|
|
|
|
pub mod texture;
|
|
|
|
pub use self::texture::Texture;
|
|
|
|
use super::*;
|
|
|
|
impl<'a> Compositor<'a> {
|
|
pub fn vulkan_instance_extensions_required(&self) -> Vec<CString> {
|
|
let temp = unsafe {
|
|
let n = (self.0.GetVulkanInstanceExtensionsRequired.unwrap())(ptr::null_mut(), 0);
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
buffer.resize(n as usize, mem::uninitialized());
|
|
(self.0.GetVulkanInstanceExtensionsRequired.unwrap())(buffer.as_mut_ptr() as *mut i8, n);
|
|
buffer
|
|
};
|
|
temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
|
|
}
|
|
|
|
pub fn vulkan_device_extensions_required(&self, physical_device: *mut VkPhysicalDevice_T) -> Vec<CString> {
|
|
let temp = unsafe {
|
|
let n = (self.0.GetVulkanDeviceExtensionsRequired.unwrap())(physical_device, ptr::null_mut(), 0);
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
buffer.resize(n as usize, mem::uninitialized());
|
|
(self.0.GetVulkanDeviceExtensionsRequired.unwrap())(physical_device as *mut _, buffer.as_mut_ptr() as *mut i8, n);
|
|
buffer
|
|
};
|
|
temp.split(|&x| x == b' ').map(|x| CString::new(x.to_vec()).expect("extension name contained null byte")).collect()
|
|
}
|
|
|
|
/// Sets tracking space returned by WaitGetPoses
|
|
pub fn set_tracking_space(&self, origin: TrackingUniverseOrigin) {
|
|
unsafe { (self.0.SetTrackingSpace.unwrap())(origin as sys::ETrackingUniverseOrigin) }
|
|
}
|
|
|
|
/// Block until a few milliseconds before the next vsync, then return poses for the next step of rendering and game
|
|
/// logic.
|
|
///
|
|
/// Poses are relative to the origin set by `set_tracking_space`.
|
|
pub fn wait_get_poses(&self) -> Result<WaitPoses, CompositorError> {
|
|
unsafe {
|
|
let mut result: WaitPoses = mem::uninitialized();
|
|
let e = (self.0.WaitGetPoses.unwrap())(result.render.as_mut().as_mut_ptr() as *mut _, result.render.len() as u32,
|
|
result.game.as_mut().as_mut_ptr() as *mut _, result.game.len() as u32);
|
|
if e == sys::EVRCompositorError_EVRCompositorError_VRCompositorError_None {
|
|
Ok(result)
|
|
} else {
|
|
Err(CompositorError(e))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Display the supplied texture for the next frame.
|
|
///
|
|
/// If `bounds` is None, the entire texture will be used. Lens distortion is handled by the OpenVR implementation.
|
|
pub fn submit(&self, eye: Eye, texture: &Texture, bounds: Option<&texture::Bounds>) -> Result<(), CompositorError> {
|
|
use self::texture::Handle::*;
|
|
let flags = match texture.handle {
|
|
Vulkan(_) => sys::EVRSubmitFlags_EVRSubmitFlags_Submit_Default,
|
|
OpenGLTexture(_) => sys::EVRSubmitFlags_EVRSubmitFlags_Submit_Default,
|
|
OpenGLRenderBuffer(_) => sys::EVRSubmitFlags_EVRSubmitFlags_Submit_GlRenderBuffer,
|
|
};
|
|
let texture = sys::Texture_t {
|
|
handle: match texture.handle {
|
|
Vulkan(ref x) => x as *const _ as *mut _,
|
|
OpenGLTexture(x) => x as *mut _,
|
|
OpenGLRenderBuffer(x) => x as *mut _,
|
|
},
|
|
eType: match texture.handle {
|
|
Vulkan(_) => sys::ETextureType_ETextureType_TextureType_Vulkan,
|
|
OpenGLTexture(_) => sys::ETextureType_ETextureType_TextureType_OpenGL,
|
|
OpenGLRenderBuffer(_) => sys::ETextureType_ETextureType_TextureType_OpenGL,
|
|
},
|
|
eColorSpace: texture.color_space as sys::EColorSpace,
|
|
};
|
|
let e = unsafe {
|
|
self.0.Submit.unwrap()(eye as sys::EVREye,
|
|
&texture as *const _ as *mut _,
|
|
bounds.map(|x| x as *const _ as *mut texture::Bounds as *mut _).unwrap_or(ptr::null_mut()),
|
|
flags)
|
|
};
|
|
if e == sys::EVRCompositorError_EVRCompositorError_VRCompositorError_None {
|
|
Ok(())
|
|
} else {
|
|
Err(CompositorError(e))
|
|
}
|
|
}
|
|
|
|
pub fn post_present_handoff(&self) {
|
|
unsafe { (self.0.PostPresentHandoff.unwrap())() };
|
|
}
|
|
|
|
/// Return whether the compositor is fullscreen.
|
|
pub fn is_fullscreen(&self) -> bool {
|
|
unsafe { (self.0.IsFullscreen.unwrap())() }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct WaitPoses {
|
|
/// Predicted to the point they will be at the upcoming frame.
|
|
pub render: TrackedDevicePoses,
|
|
/// Predicted to the point they will be at the frame after the upcoming frame, for use in game logic.
|
|
pub game: TrackedDevicePoses,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
|
pub struct CompositorError(sys::EVRCompositorError);
|
|
|
|
pub mod compositor_error {
|
|
use super::*;
|
|
|
|
pub const REQUEST_FAILED: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_RequestFailed);
|
|
pub const INCOMPATIBLE_VERSION: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_IncompatibleVersion);
|
|
pub const DO_NOT_HAVE_FOCUS: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_DoNotHaveFocus);
|
|
pub const INVALID_TEXTURE: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_InvalidTexture);
|
|
pub const IS_NOT_SCENE_APPLICATION: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_IsNotSceneApplication);
|
|
pub const TEXTURE_IS_ON_WRONG_DEVICE: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_TextureIsOnWrongDevice);
|
|
pub const TEXTURE_USES_UNSUPPORTED_FORMAT: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_TextureUsesUnsupportedFormat);
|
|
pub const SHARED_TEXTURES_NOT_SUPPORTED: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_SharedTexturesNotSupported);
|
|
pub const INDEX_OUT_OF_RANGE: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_IndexOutOfRange);
|
|
pub const ALREADY_SUBMITTED: CompositorError = CompositorError(sys::EVRCompositorError_EVRCompositorError_VRCompositorError_AlreadySubmitted);
|
|
}
|
|
|
|
impl fmt::Debug for CompositorError {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.pad(error::Error::description(self))
|
|
}
|
|
}
|
|
|
|
impl error::Error for CompositorError {
|
|
fn description(&self) -> &str {
|
|
use self::compositor_error::*;
|
|
match *self {
|
|
REQUEST_FAILED => "REQUEST_FAILED",
|
|
INCOMPATIBLE_VERSION => "INCOMPATIBLE_VERSION",
|
|
DO_NOT_HAVE_FOCUS => "DO_NOT_HAVE_FOCUS",
|
|
INVALID_TEXTURE => "INVALID_TEXTURE",
|
|
IS_NOT_SCENE_APPLICATION => "IS_NOT_SCENE_APPLICATION",
|
|
TEXTURE_IS_ON_WRONG_DEVICE => "TEXTURE_IS_ON_WRONG_DEVICE",
|
|
TEXTURE_USES_UNSUPPORTED_FORMAT => "TEXTURE_USES_UNSUPPORTED_FORMAT",
|
|
SHARED_TEXTURES_NOT_SUPPORTED => "SHARED_TEXTURES_NOT_SUPPORTED",
|
|
INDEX_OUT_OF_RANGE => "INDEX_OUT_OF_RANGE",
|
|
ALREADY_SUBMITTED => "ALREADY_SUBMITTED",
|
|
_ => "UNKNOWN",
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for CompositorError {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.pad(error::Error::description(self))
|
|
}
|
|
}
|
|
|
|
pub use sys::VkPhysicalDevice_T;
|
|
pub use sys::VkDevice_T;
|
|
pub use sys::VkInstance_T;
|
|
pub use sys::VkQueue_T;
|