move graphics initialization to instance

This commit is contained in:
awtterpip
2024-02-27 22:45:12 -06:00
parent bda328f434
commit ca007e8937
21 changed files with 244 additions and 2358 deletions

View File

@@ -7,33 +7,66 @@ pub use resources::*;
pub use types::*;
use bevy::app::{App, Plugin};
use bevy::log::error;
pub fn xr_entry() -> Result<XrEntry> {
#[cfg(windows)]
let entry = openxr::Entry::linked();
#[cfg(not(windows))]
let entry = unsafe { openxr::Entry::load()? };
Ok(entry.into())
Ok(XrEntry(entry))
}
fn init_xr() -> Result<()> {
let entry = xr_entry()?;
let instance = entry.create_instance(
AppInfo::default(),
XrExtensions::default(),
GraphicsBackend::Vulkan(()),
)?;
let system_id = instance.system(openxr::FormFactor::HEAD_MOUNTED_DISPLAY)?;
instance.create_session(system_id)?;
Ok(())
pub struct XrInitPlugin {
/// Information about the app this is being used to build.
pub app_info: AppInfo,
/// Extensions wanted for this session.
// This should preferably be changed into a simpler list of features wanted that this crate supports. i.e. hand tracking
pub exts: XrExtensions,
/// List of backends the openxr session can use. If [None], pick the first available backend.
pub backends: Option<Vec<GraphicsBackend>>,
}
pub struct XrInitPlugin;
impl Plugin for XrInitPlugin {
fn build(&self, app: &mut App) {
let entry = xr_entry();
init_xr(self, app).unwrap();
todo!()
}
}
fn init_xr(config: &XrInitPlugin, _app: &mut App) -> Result<()> {
let entry = xr_entry()?;
let available_exts = entry.enumerate_extensions()?;
for ext in available_exts.unavailable_exts(&config.exts) {
error!(
"Extension \"{ext}\" not available in the current openxr runtime. Disabling extension."
);
}
let available_backends = GraphicsBackend::available_backends(&available_exts);
// Backend selection
let backend = if let Some(wanted_backends) = &config.backends {
let mut backend = None;
for wanted_backend in wanted_backends {
if available_backends.contains(wanted_backend) {
backend = Some(*wanted_backend);
break;
}
}
backend
} else {
available_backends.first().copied()
}
.ok_or(XrError::NoAvailableBackend)?;
let exts = config.exts.clone() & available_exts;
let instance = entry.create_instance(config.app_info.clone(), exts, backend)?;
let _system_id = instance.system(openxr::FormFactor::HEAD_MOUNTED_DISPLAY)?;
//instance.create_session(system_id)?;
Ok(())
}

View File

@@ -49,6 +49,40 @@ impl Default for XrExtensions {
}
}
macro_rules! unavailable_exts {
(
$exts:ty;
$(
$(
#[$meta:meta]
)*
$ident:ident
),*
$(,)?
) => {
impl $exts {
/// Returns any extensions needed by `required_exts` that aren't available in `self`
pub(crate) fn unavailable_exts(&self, required_exts: &Self) -> Vec<std::borrow::Cow<'static, str>> {
let mut exts = vec![];
$(
$(
#[$meta]
)*
if required_exts.0.$ident && !self.0.$ident {
exts.push(std::borrow::Cow::Borrowed(stringify!($ident)))
}
)*
for ext in required_exts.0.other.iter() {
if !self.0.other.contains(ext) {
exts.push(std::borrow::Cow::Owned(ext.clone()))
}
}
exts
}
}
};
}
macro_rules! bitor {
(
$exts:ty;
@@ -254,4 +288,4 @@ macro_rules! impl_ext {
};
}
impl_ext!(bitor, bitand);
impl_ext!(bitor, bitand, unavailable_exts);

View File

@@ -1,15 +1,21 @@
pub mod vulkan;
use std::any::TypeId;
use bevy::math::UVec2;
use crate::openxr::resources::*;
use crate::openxr::types::{AppInfo, Result, XrError};
use crate::types::BlendMode;
pub trait GraphicsExt: openxr::Graphics {
pub unsafe trait GraphicsExt: openxr::Graphics {
/// Wrap the graphics specific type into the [GraphicsWrap] enum
fn wrap<T: GraphicsType>(item: T::Inner<Self>) -> GraphicsWrap<T>;
/// Convert from wgpu format to the graphics format
fn from_wgpu_format(format: wgpu::TextureFormat) -> Option<Self::Format>;
/// Convert from the graphics format to wgpu format
fn to_wgpu_format(format: Self::Format) -> Option<wgpu::TextureFormat>;
fn create_session(
/// Initialize graphics for this backend
fn init_graphics(
app_info: &AppInfo,
instance: &openxr::Instance,
system_id: openxr::SystemId,
@@ -18,10 +24,9 @@ pub trait GraphicsExt: openxr::Graphics {
wgpu::Queue,
wgpu::Adapter,
wgpu::Instance,
XrSession,
XrFrameWaiter,
XrFrameStream,
Self::SessionCreateInfo,
)>;
/// Convert a swapchain function
unsafe fn to_wgpu_img(
image: Self::SwapchainImage,
device: &wgpu::Device,
@@ -45,16 +50,32 @@ impl<T: GraphicsType> GraphicsWrap<T> {
)
}
fn graphics_type(&self) -> std::any::TypeId {
fn graphics_type(&self) -> TypeId {
graphics_match!(
self;
_ => std::any::TypeId::of::<Api>()
_ => TypeId::of::<Api>()
)
}
/// Checks if this struct is using the wanted graphics api.
pub fn using_graphics<G: GraphicsExt + 'static>(&self) -> bool {
self.graphics_type() == std::any::TypeId::of::<G>()
self.graphics_type() == TypeId::of::<G>()
}
/// Checks if the two values are both using the same graphics backend
pub fn using_graphics_of_val<V: GraphicsType>(&self, other: &GraphicsWrap<V>) -> bool {
self.graphics_type() == other.graphics_type()
}
pub fn as_type<G: GraphicsExt>(&self) -> Result<&T::Inner<G>> {
// graphics_match!(
// self;
// inner => if TypeId::of::<Api> == TypeId::of::<G> {
// return Ok(inner)
// }
// );
return Err(XrError::FailedGraphicsRequirements);
}
}

View File

@@ -8,7 +8,6 @@ use wgpu_hal::api::Vulkan;
use wgpu_hal::Api;
use crate::openxr::extensions::XrExtensions;
use crate::openxr::resources::*;
use crate::openxr::types::Result;
use super::{AppInfo, GraphicsExt, XrError};
@@ -25,7 +24,7 @@ const VK_TARGET_VERSION_ASH: u32 = ash::vk::make_api_version(
VK_TARGET_VERSION.patch() as u32,
);
impl GraphicsExt for openxr::Vulkan {
unsafe impl GraphicsExt for openxr::Vulkan {
fn from_wgpu_format(format: wgpu::TextureFormat) -> Option<Self::Format> {
wgpu_to_vulkan(format).map(|f| f.as_raw() as _)
}
@@ -34,7 +33,7 @@ impl GraphicsExt for openxr::Vulkan {
vulkan_to_wgpu(ash::vk::Format::from_raw(format as _))
}
fn create_session(
fn init_graphics(
app_info: &AppInfo,
instance: &openxr::Instance,
system_id: openxr::SystemId,
@@ -43,9 +42,7 @@ impl GraphicsExt for openxr::Vulkan {
wgpu::Queue,
wgpu::Adapter,
wgpu::Instance,
XrSession,
XrFrameWaiter,
XrFrameStream,
Self::SessionCreateInfo,
)> {
let reqs = instance.graphics_requirements::<openxr::Vulkan>(system_id)?;
if VK_TARGET_VERSION < reqs.min_api_version_supported
@@ -228,30 +225,18 @@ impl GraphicsExt for openxr::Vulkan {
)
}?;
let (session, frame_wait, frame_stream) = unsafe {
instance.create_session::<openxr::Vulkan>(
system_id,
&openxr::vulkan::SessionCreateInfo {
instance: vk_instance_ptr,
physical_device: vk_physical_device_ptr,
device: vk_device_ptr,
queue_family_index,
queue_index: 0,
},
)
}?;
Ok((
wgpu_device,
wgpu_queue,
wgpu_adapter,
wgpu_instance,
XrSession(
session.clone().into_any_graphics(),
super::GraphicsWrap::Vulkan(session),
),
XrFrameWaiter(frame_wait),
XrFrameStream(super::GraphicsWrap::Vulkan(frame_stream)),
openxr::vulkan::SessionCreateInfo {
instance: vk_instance_ptr,
physical_device: vk_physical_device_ptr,
device: vk_device_ptr,
queue_family_index,
queue_index: 0,
},
))
}
@@ -310,6 +295,10 @@ impl GraphicsExt for openxr::Vulkan {
extensions.khr_vulkan_enable2 = true;
extensions.into()
}
fn wrap<T: super::GraphicsType>(item: T::Inner<Self>) -> super::GraphicsWrap<T> {
super::GraphicsWrap::Vulkan(item)
}
}
fn vulkan_to_wgpu(format: ash::vk::Format) -> Option<wgpu::TextureFormat> {

View File

@@ -1,12 +1,14 @@
use bevy::prelude::*;
use bevy::render::renderer::{RenderAdapter, RenderAdapterInfo, RenderInstance, RenderQueue};
use bevy::render::settings::RenderCreation;
use openxr::AnyGraphics;
use super::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap};
use super::types::*;
#[derive(Deref, Clone)]
pub struct XrEntry(openxr::Entry);
pub struct XrEntry(pub openxr::Entry);
impl XrEntry {
pub fn enumerate_extensions(&self) -> Result<XrExtensions> {
@@ -48,37 +50,57 @@ impl XrEntry {
}
}
impl From<openxr::Entry> for XrEntry {
fn from(value: openxr::Entry) -> Self {
Self(value)
}
}
#[derive(Resource, Deref, Clone)]
pub struct XrInstance(
#[deref] pub(crate) openxr::Instance,
#[deref] pub openxr::Instance,
pub(crate) GraphicsBackend,
pub(crate) AppInfo,
);
impl XrInstance {
pub fn create_session(
pub fn init_graphics(
&self,
system_id: openxr::SystemId,
) -> Result<(
wgpu::Device,
wgpu::Queue,
wgpu::Adapter,
wgpu::Instance,
XrSession,
XrFrameWaiter,
XrFrameStream,
)> {
) -> Result<(RenderCreation, SessionCreateInfo)> {
graphics_match!(
self.1;
_ => Api::create_session(&self.2, &self.0, system_id)
_ => {
let (device, queue, adapter, instance, session_info) = Api::init_graphics(&self.2, &self, system_id)?;
Ok((RenderCreation::manual(device.into(), RenderQueue(queue.into()), RenderAdapterInfo(adapter.get_info()), RenderAdapter(adapter.into()), RenderInstance(instance.into())), SessionCreateInfo(Api::wrap(session_info))))
}
)
}
/// # Safety
///
/// `info` must contain valid handles for the graphics api
pub unsafe fn create_session(
&self,
system_id: openxr::SystemId,
info: SessionCreateInfo,
) -> Result<(XrSession, XrFrameWaiter, XrFrameStream)> {
if !info.0.using_graphics_of_val(&self.1) {
return Err(XrError::GraphicsBackendMismatch {
item: std::any::type_name::<SessionCreateInfo>(),
backend: info.0.graphics_name(),
expected_backend: self.1.graphics_name(),
});
}
graphics_match!(
info.0;
info => {
let (session, frame_waiter, frame_stream) = unsafe { self.0.create_session::<Api>(system_id, &info)? };
Ok((session.into(), XrFrameWaiter(frame_waiter), XrFrameStream(Api::wrap(frame_stream))))
}
)
}
}
pub struct SessionCreateInfo(pub(crate) GraphicsWrap<Self>);
impl GraphicsType for SessionCreateInfo {
type Inner<G: GraphicsExt> = G::SessionCreateInfo;
}
impl GraphicsType for XrSession {
@@ -91,6 +113,12 @@ pub struct XrSession(
pub(crate) GraphicsWrap<Self>,
);
impl<G: GraphicsExt> From<openxr::Session<G>> for XrSession {
fn from(value: openxr::Session<G>) -> Self {
Self(value.clone().into_any_graphics(), G::wrap(value))
}
}
impl XrSession {
pub fn enumerate_swapchain_formats(&self) -> Result<Vec<wgpu::TextureFormat>> {
graphics_match!(
@@ -107,6 +135,7 @@ impl XrSession {
}
}
#[derive(Resource)]
pub struct XrFrameStream(pub(crate) GraphicsWrap<Self>);
impl GraphicsType for XrFrameStream {
@@ -135,8 +164,8 @@ impl XrFrameStream {
for (i, layer) in layers.into_iter().enumerate() {
if let Some(swapchain) = layer.swapchain() {
if !swapchain.0.using_graphics::<Api>() {
warn!(
"composition layer {i} is using graphics api '{}', expected graphics api '{}'. Excluding layer from frame submission.",
error!(
"Composition layer {i} is using graphics api '{}', expected graphics api '{}'. Excluding layer from frame submission.",
swapchain.0.graphics_name(),
std::any::type_name::<Api>(),
);
@@ -152,9 +181,10 @@ impl XrFrameStream {
}
}
#[derive(Deref, DerefMut)]
#[derive(Resource, Deref, DerefMut)]
pub struct XrFrameWaiter(pub openxr::FrameWaiter);
#[derive(Resource)]
pub struct XrSwapchain(pub(crate) GraphicsWrap<Self>);
impl GraphicsType for XrSwapchain {

View File

@@ -1,11 +1,10 @@
use std::borrow::Cow;
use thiserror::Error;
use super::graphics::{graphics_match, GraphicsExt, GraphicsWrap};
pub use super::extensions::XrExtensions;
pub use openxr::{
Extent2Di, Offset2Di, Rect2Di, SwapchainCreateFlags, SwapchainUsageFlags, SystemId,
Extent2Di, Graphics, Offset2Di, Rect2Di, SwapchainCreateFlags, SwapchainUsageFlags, SystemId,
};
pub type Result<T> = std::result::Result<T, XrError>;
@@ -53,32 +52,71 @@ impl GraphicsBackend {
}
}
#[derive(Error, Debug)]
pub enum XrError {
#[error("OpenXR error: {0}")]
OpenXrError(#[from] openxr::sys::Result),
#[error("OpenXR loading error: {0}")]
OpenXrLoadingError(#[from] openxr::LoadError),
#[error("WGPU instance error: {0}")]
WgpuInstanceError(#[from] wgpu_hal::InstanceError),
#[error("WGPU device error: {0}")]
WgpuDeviceError(#[from] wgpu_hal::DeviceError),
#[error("WGPU request device error: {0}")]
WgpuRequestDeviceError(#[from] wgpu::RequestDeviceError),
#[error("Unsupported texture format: {0:?}")]
UnsupportedTextureFormat(wgpu::TextureFormat),
#[error("Vulkan error: {0}")]
VulkanError(#[from] ash::vk::Result),
#[error("Vulkan loading error: {0}")]
VulkanLoadingError(#[from] ash::LoadingError),
#[error("Graphics backend '{0:?}' is not available")]
UnavailableBackend(GraphicsBackend),
#[error("Could not meet graphics requirements for platform. See console for details")]
FailedGraphicsRequirements,
#[error("Failed to create CString: {0}")]
NulError(#[from] std::ffi::NulError),
mod error {
use super::GraphicsBackend;
use std::borrow::Cow;
use std::fmt;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum XrError {
#[error("OpenXR error: {0}")]
OpenXrError(#[from] openxr::sys::Result),
#[error("OpenXR loading error: {0}")]
OpenXrLoadingError(#[from] openxr::LoadError),
#[error("WGPU instance error: {0}")]
WgpuInstanceError(#[from] wgpu_hal::InstanceError),
#[error("WGPU device error: {0}")]
WgpuDeviceError(#[from] wgpu_hal::DeviceError),
#[error("WGPU request device error: {0}")]
WgpuRequestDeviceError(#[from] wgpu::RequestDeviceError),
#[error("Unsupported texture format: {0:?}")]
UnsupportedTextureFormat(wgpu::TextureFormat),
#[error("Vulkan error: {0}")]
VulkanError(#[from] ash::vk::Result),
#[error("Vulkan loading error: {0}")]
VulkanLoadingError(#[from] ash::LoadingError),
#[error("Graphics backend '{0:?}' is not available")]
UnavailableBackend(GraphicsBackend),
#[error("No available backend")]
NoAvailableBackend,
#[error("OpenXR runtime does not support these extensions: {0}")]
UnavailableExtensions(UnavailableExts),
#[error("Could not meet graphics requirements for platform. See console for details")]
FailedGraphicsRequirements,
#[error(
"Tried to use item {item} with backend {backend}. Expected backend {expected_backend}"
)]
GraphicsBackendMismatch {
item: &'static str,
backend: &'static str,
expected_backend: &'static str,
},
#[error("Failed to create CString: {0}")]
NulError(#[from] std::ffi::NulError),
}
impl From<Vec<Cow<'static, str>>> for XrError {
fn from(value: Vec<Cow<'static, str>>) -> Self {
Self::UnavailableExtensions(UnavailableExts(value))
}
}
#[derive(Debug)]
pub struct UnavailableExts(Vec<Cow<'static, str>>);
impl fmt::Display for UnavailableExts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for s in &self.0 {
write!(f, "\t{s}")?;
}
Ok(())
}
}
}
pub use error::XrError;
#[derive(Debug, Copy, Clone)]
pub struct SwapchainCreateInfo {
pub create_flags: SwapchainCreateFlags,

View File

@@ -5,7 +5,7 @@ use bevy::render::camera::{RenderTarget, Viewport};
use crate::types::Pose;
pub(crate) const XR_TEXTURE_VIEW_INDEX: u32 = 1208214591;
pub const XR_TEXTURE_VIEW_INDEX: u32 = 1208214591;
#[derive(Debug, Clone)]
pub struct XrView {