184 lines
6.0 KiB
Rust
184 lines
6.0 KiB
Rust
use anyhow::{bail, ensure};
|
|
use glam::{Affine3A, Quat, Vec3, Vec3A};
|
|
use openxr::{self as xr, SessionCreateFlags, Version};
|
|
use xr::OverlaySessionCreateFlagsEXTX;
|
|
|
|
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
|
|
let entry = xr::Entry::linked();
|
|
|
|
let Ok(available_extensions) = entry.enumerate_extensions() else {
|
|
bail!("Failed to enumerate OpenXR extensions.");
|
|
};
|
|
ensure!(
|
|
available_extensions.khr_vulkan_enable2,
|
|
"Missing KHR_vulkan_enable2 extension."
|
|
);
|
|
ensure!(
|
|
available_extensions.extx_overlay,
|
|
"Missing EXTX_overlay extension."
|
|
);
|
|
|
|
let mut enabled_extensions = xr::ExtensionSet::default();
|
|
enabled_extensions.khr_vulkan_enable2 = true;
|
|
enabled_extensions.extx_overlay = true;
|
|
if available_extensions.khr_binding_modification && available_extensions.ext_dpad_binding {
|
|
enabled_extensions.khr_binding_modification = true;
|
|
enabled_extensions.ext_dpad_binding = true;
|
|
} else {
|
|
log::warn!("Missing EXT_dpad_binding extension.");
|
|
}
|
|
if available_extensions.ext_hp_mixed_reality_controller {
|
|
enabled_extensions.ext_hp_mixed_reality_controller = true;
|
|
} else {
|
|
log::warn!("Missing EXT_hp_mixed_reality_controller extension.");
|
|
}
|
|
if available_extensions.khr_composition_layer_cylinder {
|
|
enabled_extensions.khr_composition_layer_cylinder = true;
|
|
} else {
|
|
log::warn!("Missing EXT_composition_layer_cylinder extension.");
|
|
}
|
|
|
|
if available_extensions.khr_composition_layer_equirect2 {
|
|
enabled_extensions.khr_composition_layer_equirect2 = true;
|
|
} else {
|
|
log::warn!("Missing EXT_composition_layer_equirect2 extension.");
|
|
}
|
|
|
|
//#[cfg(not(debug_assertions))]
|
|
let layers = [];
|
|
//#[cfg(debug_assertions)]
|
|
//let layers = [
|
|
// "XR_APILAYER_LUNARG_api_dump",
|
|
// "XR_APILAYER_LUNARG_standard_validation",
|
|
//];
|
|
|
|
let Ok(xr_instance) = entry.create_instance(
|
|
&xr::ApplicationInfo {
|
|
api_version: Version::new(1, 1, 37),
|
|
application_name: "wlx-overlay-s",
|
|
application_version: 0,
|
|
engine_name: "wlx-overlay-s",
|
|
engine_version: 0,
|
|
},
|
|
&enabled_extensions,
|
|
&layers,
|
|
) else {
|
|
bail!("Failed to create OpenXR instance.");
|
|
};
|
|
|
|
let Ok(instance_props) = xr_instance.properties() else {
|
|
bail!("Failed to query OpenXR instance properties.");
|
|
};
|
|
log::info!(
|
|
"Using OpenXR runtime: {} {}",
|
|
instance_props.runtime_name,
|
|
instance_props.runtime_version
|
|
);
|
|
|
|
let Ok(system) = xr_instance.system(xr::FormFactor::HEAD_MOUNTED_DISPLAY) else {
|
|
bail!("Failed to access OpenXR HMD system.");
|
|
};
|
|
|
|
let vk_target_version_xr = xr::Version::new(1, 1, 0);
|
|
|
|
let Ok(reqs) = xr_instance.graphics_requirements::<xr::Vulkan>(system) else {
|
|
bail!("Failed to query OpenXR Vulkan requirements.");
|
|
};
|
|
|
|
if vk_target_version_xr < reqs.min_api_version_supported
|
|
|| vk_target_version_xr.major() > reqs.max_api_version_supported.major()
|
|
{
|
|
bail!(
|
|
"OpenXR runtime requires Vulkan version > {}, < {}.0.0",
|
|
reqs.min_api_version_supported,
|
|
reqs.max_api_version_supported.major() + 1
|
|
);
|
|
}
|
|
|
|
Ok((xr_instance, system))
|
|
}
|
|
|
|
pub(super) unsafe fn create_overlay_session(
|
|
instance: &xr::Instance,
|
|
system: xr::SystemId,
|
|
info: &xr::vulkan::SessionCreateInfo,
|
|
) -> Result<xr::sys::Session, xr::sys::Result> {
|
|
let overlay = xr::sys::SessionCreateInfoOverlayEXTX {
|
|
ty: xr::sys::SessionCreateInfoOverlayEXTX::TYPE,
|
|
next: std::ptr::null(),
|
|
create_flags: OverlaySessionCreateFlagsEXTX::EMPTY,
|
|
session_layers_placement: 5,
|
|
};
|
|
let binding = xr::sys::GraphicsBindingVulkanKHR {
|
|
ty: xr::sys::GraphicsBindingVulkanKHR::TYPE,
|
|
next: (&raw const overlay).cast(),
|
|
instance: info.instance,
|
|
physical_device: info.physical_device,
|
|
device: info.device,
|
|
queue_family_index: info.queue_family_index,
|
|
queue_index: info.queue_index,
|
|
};
|
|
let info = xr::sys::SessionCreateInfo {
|
|
ty: xr::sys::SessionCreateInfo::TYPE,
|
|
next: (&raw const binding).cast(),
|
|
create_flags: SessionCreateFlags::default(),
|
|
system_id: system,
|
|
};
|
|
let mut out = xr::sys::Session::NULL;
|
|
let x = (instance.fp().create_session)(instance.as_raw(), &info, &mut out);
|
|
if x.into_raw() >= 0 {
|
|
Ok(out)
|
|
} else {
|
|
Err(x)
|
|
}
|
|
}
|
|
|
|
type Vec3M = mint::Vector3<f32>;
|
|
type QuatM = mint::Quaternion<f32>;
|
|
|
|
pub(super) fn ipd_from_views(views: &[xr::View]) -> f32 {
|
|
let p0: Vec3 = Vec3M::from(views[0].pose.position).into();
|
|
let p1: Vec3 = Vec3M::from(views[1].pose.position).into();
|
|
|
|
(p0.distance(p1) * 10000.0).round() * 0.1
|
|
}
|
|
|
|
pub(super) fn transform_to_norm_quat(transform: &Affine3A) -> Quat {
|
|
let norm_mat3 = transform
|
|
.matrix3
|
|
.mul_scalar(1.0 / transform.matrix3.x_axis.length());
|
|
Quat::from_mat3a(&norm_mat3).normalize()
|
|
}
|
|
|
|
pub(super) fn translation_rotation_to_posef(translation: Vec3A, mut rotation: Quat) -> xr::Posef {
|
|
if !rotation.is_finite() {
|
|
rotation = Quat::IDENTITY;
|
|
}
|
|
|
|
xr::Posef {
|
|
orientation: xr::Quaternionf {
|
|
x: rotation.x,
|
|
y: rotation.y,
|
|
z: rotation.z,
|
|
w: rotation.w,
|
|
},
|
|
position: xr::Vector3f {
|
|
x: translation.x,
|
|
y: translation.y,
|
|
z: translation.z,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(super) fn transform_to_posef(transform: &Affine3A) -> xr::Posef {
|
|
let translation = transform.translation;
|
|
let rotation = transform_to_norm_quat(transform);
|
|
translation_rotation_to_posef(translation, rotation)
|
|
}
|
|
|
|
pub(super) fn posef_to_transform(pose: &xr::Posef) -> Affine3A {
|
|
let rotation = QuatM::from(pose.orientation).into();
|
|
let translation = Vec3M::from(pose.position).into();
|
|
Affine3A::from_rotation_translation(rotation, translation)
|
|
}
|