feat: allow manually defining additional vulkan extensions
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
57
crates/bevy_openxr/examples/custom_vulkan_extensions.rs
Normal file
57
crates/bevy_openxr/examples/custom_vulkan_extensions.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//! A simple 3D scene with light shining over a cube sitting on a plane.
|
||||||
|
|
||||||
|
use bevy::{prelude::*, render::pipelined_rendering::PipelinedRenderingPlugin};
|
||||||
|
use bevy_mod_openxr::{
|
||||||
|
add_xr_plugins,
|
||||||
|
graphics::{GraphicsBackend, OxrManualGraphicsConfig},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> AppExit {
|
||||||
|
App::new()
|
||||||
|
.insert_resource(OxrManualGraphicsConfig {
|
||||||
|
fallback_backend: GraphicsBackend::Vulkan(()),
|
||||||
|
vk_instance_exts: vec![],
|
||||||
|
vk_device_exts: vec![ash::khr::external_memory::NAME],
|
||||||
|
})
|
||||||
|
.add_plugins(add_xr_plugins(
|
||||||
|
// Disabling Pipelined Rendering should reduce latency a little bit for button inputs
|
||||||
|
// and increase accuracy for hand tracking, controller positions and similar,
|
||||||
|
// the views are updated right before rendering so they are as accurate as possible
|
||||||
|
DefaultPlugins.build().disable::<PipelinedRenderingPlugin>(),
|
||||||
|
))
|
||||||
|
.add_plugins(bevy_mod_xr::hand_debug_gizmos::HandGizmosPlugin)
|
||||||
|
.add_systems(Startup, setup)
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set up a simple 3D scene
|
||||||
|
fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
// circular base
|
||||||
|
commands.spawn((
|
||||||
|
Mesh3d(meshes.add(Circle::new(4.0))),
|
||||||
|
MeshMaterial3d(materials.add(Color::WHITE)),
|
||||||
|
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
|
||||||
|
));
|
||||||
|
// cube
|
||||||
|
commands.spawn((
|
||||||
|
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
|
||||||
|
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),
|
||||||
|
Transform::from_xyz(0.0, 0.5, 0.0),
|
||||||
|
));
|
||||||
|
// light
|
||||||
|
commands.spawn((
|
||||||
|
PointLight {
|
||||||
|
shadows_enabled: true,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Transform::from_xyz(4.0, 8.0, 4.0),
|
||||||
|
));
|
||||||
|
commands.spawn((
|
||||||
|
Camera3d::default(),
|
||||||
|
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
));
|
||||||
|
}
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
#[cfg(feature = "vulkan")]
|
#[cfg(feature = "vulkan")]
|
||||||
pub mod vulkan;
|
pub mod vulkan;
|
||||||
|
|
||||||
use std::any::TypeId;
|
use std::{any::TypeId, ffi::CStr};
|
||||||
|
|
||||||
use bevy::math::UVec2;
|
use bevy::{ecs::resource::Resource, math::UVec2};
|
||||||
use openxr::{FrameStream, FrameWaiter, Session};
|
use openxr::{FrameStream, FrameWaiter, Session};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -39,6 +39,7 @@ pub unsafe trait GraphicsExt: openxr::Graphics {
|
|||||||
app_info: &AppInfo,
|
app_info: &AppInfo,
|
||||||
instance: &openxr::Instance,
|
instance: &openxr::Instance,
|
||||||
system_id: openxr::SystemId,
|
system_id: openxr::SystemId,
|
||||||
|
cfg: Option<&OxrManualGraphicsConfig>,
|
||||||
) -> Result<(WgpuGraphics, Self::SessionCreateInfo)>;
|
) -> Result<(WgpuGraphics, Self::SessionCreateInfo)>;
|
||||||
unsafe fn create_session(
|
unsafe fn create_session(
|
||||||
instance: &openxr::Instance,
|
instance: &openxr::Instance,
|
||||||
@@ -46,6 +47,17 @@ pub unsafe trait GraphicsExt: openxr::Graphics {
|
|||||||
info: &Self::SessionCreateInfo,
|
info: &Self::SessionCreateInfo,
|
||||||
session_create_info_chain: &mut OxrSessionCreateNextChain,
|
session_create_info_chain: &mut OxrSessionCreateNextChain,
|
||||||
) -> openxr::Result<(Session<Self>, FrameWaiter, FrameStream<Self>)>;
|
) -> openxr::Result<(Session<Self>, FrameWaiter, FrameStream<Self>)>;
|
||||||
|
fn init_fallback_graphics(
|
||||||
|
app_info: &AppInfo,
|
||||||
|
cfg: &OxrManualGraphicsConfig,
|
||||||
|
) -> Result<WgpuGraphics>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct OxrManualGraphicsConfig {
|
||||||
|
pub fallback_backend: GraphicsBackend,
|
||||||
|
pub vk_instance_exts: Vec<&'static CStr>,
|
||||||
|
pub vk_device_exts: Vec<&'static CStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type that can be used in [`GraphicsWrap`].
|
/// A type that can be used in [`GraphicsWrap`].
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
use std::ffi::{c_void, CString};
|
use std::ffi::{c_void, CStr, CString};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use ash::vk::Handle;
|
use ash::vk::{self, Handle};
|
||||||
use bevy::log::{debug, error};
|
use bevy::log::{debug, error};
|
||||||
use bevy::math::UVec2;
|
use bevy::math::UVec2;
|
||||||
use openxr::{sys, Version};
|
use openxr::{sys, Version};
|
||||||
|
use wgpu::InstanceFlags;
|
||||||
use wgpu_hal::api::Vulkan;
|
use wgpu_hal::api::Vulkan;
|
||||||
use wgpu_hal::Api;
|
use wgpu_hal::Api;
|
||||||
|
|
||||||
use super::{GraphicsExt, GraphicsType, GraphicsWrap};
|
use super::{GraphicsExt, GraphicsType, GraphicsWrap, OxrManualGraphicsConfig};
|
||||||
use crate::error::OxrError;
|
use crate::error::OxrError;
|
||||||
use crate::session::OxrSessionCreateNextChain;
|
use crate::session::OxrSessionCreateNextChain;
|
||||||
use crate::types::{AppInfo, OxrExtensions, Result, WgpuGraphics};
|
use crate::types::{AppInfo, OxrExtensions, Result, WgpuGraphics};
|
||||||
@@ -17,7 +19,7 @@ const VK_TARGET_VERSION: Version = Version::new(1, 2, 0);
|
|||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
const VK_TARGET_VERSION: Version = Version::new(1, 1, 0);
|
const VK_TARGET_VERSION: Version = Version::new(1, 1, 0);
|
||||||
|
|
||||||
const VK_TARGET_VERSION_ASH: u32 = ash::vk::make_api_version(
|
const VK_TARGET_VERSION_ASH: u32 = vk::make_api_version(
|
||||||
0,
|
0,
|
||||||
VK_TARGET_VERSION.major() as u32,
|
VK_TARGET_VERSION.major() as u32,
|
||||||
VK_TARGET_VERSION.minor() as u32,
|
VK_TARGET_VERSION.minor() as u32,
|
||||||
@@ -40,7 +42,7 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn into_wgpu_format(format: Self::Format) -> Option<wgpu::TextureFormat> {
|
fn into_wgpu_format(format: Self::Format) -> Option<wgpu::TextureFormat> {
|
||||||
vulkan_to_wgpu(ash::vk::Format::from_raw(format as _))
|
vulkan_to_wgpu(vk::Format::from_raw(format as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn to_wgpu_img(
|
unsafe fn to_wgpu_img(
|
||||||
@@ -49,7 +51,7 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
format: wgpu::TextureFormat,
|
format: wgpu::TextureFormat,
|
||||||
resolution: UVec2,
|
resolution: UVec2,
|
||||||
) -> Result<wgpu::Texture> {
|
) -> Result<wgpu::Texture> {
|
||||||
let color_image = ash::vk::Image::from_raw(color_image);
|
let color_image = vk::Image::from_raw(color_image);
|
||||||
let wgpu_hal_texture = unsafe {
|
let wgpu_hal_texture = unsafe {
|
||||||
<wgpu_hal::vulkan::Api as wgpu_hal::Api>::Device::texture_from_raw(
|
<wgpu_hal::vulkan::Api as wgpu_hal::Api>::Device::texture_from_raw(
|
||||||
color_image,
|
color_image,
|
||||||
@@ -97,6 +99,7 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
app_info: &AppInfo,
|
app_info: &AppInfo,
|
||||||
instance: &openxr::Instance,
|
instance: &openxr::Instance,
|
||||||
system_id: openxr::SystemId,
|
system_id: openxr::SystemId,
|
||||||
|
cfg: Option<&OxrManualGraphicsConfig>,
|
||||||
) -> Result<(WgpuGraphics, Self::SessionCreateInfo)> {
|
) -> Result<(WgpuGraphics, Self::SessionCreateInfo)> {
|
||||||
let reqs = instance.graphics_requirements::<openxr::Vulkan>(system_id)?;
|
let reqs = instance.graphics_requirements::<openxr::Vulkan>(system_id)?;
|
||||||
if VK_TARGET_VERSION < reqs.min_api_version_supported
|
if VK_TARGET_VERSION < reqs.min_api_version_supported
|
||||||
@@ -110,26 +113,12 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
return Err(OxrError::FailedGraphicsRequirements);
|
return Err(OxrError::FailedGraphicsRequirements);
|
||||||
};
|
};
|
||||||
let vk_entry = unsafe { ash::Entry::load() }?;
|
let vk_entry = unsafe { ash::Entry::load() }?;
|
||||||
let flags = wgpu::InstanceFlags::default().with_env();
|
let (flags, instance_exts, device_exts) = get_extensions(cfg, &vk_entry)?;
|
||||||
let extensions =
|
|
||||||
<Vulkan as Api>::Instance::desired_extensions(&vk_entry, VK_TARGET_VERSION_ASH, flags)?;
|
|
||||||
let device_extensions = [
|
|
||||||
ash::khr::swapchain::NAME,
|
|
||||||
ash::khr::draw_indirect_count::NAME,
|
|
||||||
ash::khr::timeline_semaphore::NAME,
|
|
||||||
ash::khr::imageless_framebuffer::NAME,
|
|
||||||
ash::khr::image_format_list::NAME,
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
ash::khr::portability_subset::NAME,
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
ash::ext::metal_objects::NAME,
|
|
||||||
];
|
|
||||||
|
|
||||||
let vk_instance = unsafe {
|
let vk_instance = unsafe {
|
||||||
let extensions_cchar: Vec<_> = extensions.iter().map(|s| s.as_ptr()).collect();
|
let extensions_cchar: Vec<_> = instance_exts.iter().map(|s| s.as_ptr()).collect();
|
||||||
|
|
||||||
let app_name = CString::new(app_info.name.clone().into_owned())?;
|
let app_name = CString::new(app_info.name.clone().into_owned())?;
|
||||||
let vk_app_info = ash::vk::ApplicationInfo::default()
|
let vk_app_info = vk::ApplicationInfo::default()
|
||||||
.application_name(&app_name)
|
.application_name(&app_name)
|
||||||
.application_version(1)
|
.application_version(1)
|
||||||
.engine_name(&app_name)
|
.engine_name(&app_name)
|
||||||
@@ -141,18 +130,182 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
system_id,
|
system_id,
|
||||||
#[allow(clippy::missing_transmute_annotations)]
|
#[allow(clippy::missing_transmute_annotations)]
|
||||||
std::mem::transmute(vk_entry.static_fn().get_instance_proc_addr),
|
std::mem::transmute(vk_entry.static_fn().get_instance_proc_addr),
|
||||||
&ash::vk::InstanceCreateInfo::default()
|
&vk::InstanceCreateInfo::default()
|
||||||
.application_info(&vk_app_info)
|
.application_info(&vk_app_info)
|
||||||
.enabled_extension_names(&extensions_cchar) as *const _
|
.enabled_extension_names(&extensions_cchar) as *const _
|
||||||
as *const _,
|
as *const _,
|
||||||
)?
|
)?
|
||||||
.map_err(ash::vk::Result::from_raw)?;
|
.map_err(vk::Result::from_raw)?;
|
||||||
|
|
||||||
ash::Instance::load(
|
ash::Instance::load(
|
||||||
vk_entry.static_fn(),
|
vk_entry.static_fn(),
|
||||||
ash::vk::Instance::from_raw(vk_instance as _),
|
vk::Instance::from_raw(vk_instance as _),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
let vk_physical_device = vk::PhysicalDevice::from_raw(unsafe {
|
||||||
|
instance.vulkan_graphics_device(system_id, vk_instance.handle().as_raw() as _)? as _
|
||||||
|
});
|
||||||
|
init_from_instance_and_dev(
|
||||||
|
vk_entry.clone(),
|
||||||
|
vk_instance.clone(),
|
||||||
|
vk_physical_device,
|
||||||
|
instance_exts,
|
||||||
|
flags,
|
||||||
|
device_exts.into(),
|
||||||
|
|info| unsafe {
|
||||||
|
let vk_device = instance
|
||||||
|
.create_vulkan_device(
|
||||||
|
system_id,
|
||||||
|
#[allow(clippy::missing_transmute_annotations)]
|
||||||
|
std::mem::transmute(vk_entry.static_fn().get_instance_proc_addr),
|
||||||
|
vk_physical_device.as_raw() as _,
|
||||||
|
info as *const _ as *const _,
|
||||||
|
)?
|
||||||
|
.map_err(vk::Result::from_raw)?;
|
||||||
|
|
||||||
|
Ok(ash::Device::load(
|
||||||
|
vk_instance.fp_v1_0(),
|
||||||
|
vk::Device::from_raw(vk_device as _),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn create_session(
|
||||||
|
instance: &openxr::Instance,
|
||||||
|
system_id: openxr::SystemId,
|
||||||
|
info: &Self::SessionCreateInfo,
|
||||||
|
session_create_info_chain: &mut OxrSessionCreateNextChain,
|
||||||
|
) -> openxr::Result<(
|
||||||
|
openxr::Session<Self>,
|
||||||
|
openxr::FrameWaiter,
|
||||||
|
openxr::FrameStream<Self>,
|
||||||
|
)> {
|
||||||
|
let next_ptr = session_create_info_chain.chain_pointer();
|
||||||
|
let binding = sys::GraphicsBindingVulkanKHR {
|
||||||
|
ty: sys::GraphicsBindingVulkanKHR::TYPE,
|
||||||
|
next: next_ptr,
|
||||||
|
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 = sys::SessionCreateInfo {
|
||||||
|
ty: sys::SessionCreateInfo::TYPE,
|
||||||
|
next: &binding as *const _ as *const _,
|
||||||
|
create_flags: Default::default(),
|
||||||
|
system_id,
|
||||||
|
};
|
||||||
|
let mut out = sys::Session::NULL;
|
||||||
|
cvt((instance.fp().create_session)(
|
||||||
|
instance.as_raw(),
|
||||||
|
&info,
|
||||||
|
&mut out,
|
||||||
|
))?;
|
||||||
|
Ok(openxr::Session::from_raw(
|
||||||
|
instance.clone(),
|
||||||
|
out,
|
||||||
|
Box::new(()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_fallback_graphics(
|
||||||
|
app_info: &AppInfo,
|
||||||
|
cfg: &OxrManualGraphicsConfig,
|
||||||
|
) -> Result<WgpuGraphics> {
|
||||||
|
let vk_entry = unsafe { ash::Entry::load() }?;
|
||||||
|
let (instance_flags, instance_exts, device_exts) = get_extensions(Some(cfg), &vk_entry)?;
|
||||||
|
|
||||||
|
let vk_instance = unsafe {
|
||||||
|
let extensions_cchar: Vec<_> = instance_exts.iter().map(|s| s.as_ptr()).collect();
|
||||||
|
|
||||||
|
let app_name = CString::from_str(&app_info.name)?;
|
||||||
|
let vk_app_info = ash::vk::ApplicationInfo::default()
|
||||||
|
.application_name(&app_name)
|
||||||
|
.application_version(1)
|
||||||
|
.engine_name(c"bevy")
|
||||||
|
.engine_version(16)
|
||||||
|
.api_version(VK_TARGET_VERSION_ASH);
|
||||||
|
|
||||||
|
vk_entry.create_instance(
|
||||||
|
&ash::vk::InstanceCreateInfo::default()
|
||||||
|
.application_info(&vk_app_info)
|
||||||
|
.enabled_extension_names(&extensions_cchar),
|
||||||
|
None,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
let vk_physical_device = {
|
||||||
|
let mut devices = unsafe { vk_instance.enumerate_physical_devices()? };
|
||||||
|
devices.sort_by_key(|physical_device| {
|
||||||
|
match unsafe {
|
||||||
|
vk_instance
|
||||||
|
.get_physical_device_properties(*physical_device)
|
||||||
|
.device_type
|
||||||
|
} {
|
||||||
|
vk::PhysicalDeviceType::DISCRETE_GPU => 1,
|
||||||
|
vk::PhysicalDeviceType::INTEGRATED_GPU => 2,
|
||||||
|
vk::PhysicalDeviceType::OTHER => 3,
|
||||||
|
vk::PhysicalDeviceType::VIRTUAL_GPU => 4,
|
||||||
|
vk::PhysicalDeviceType::CPU => 5,
|
||||||
|
_ => 6,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let Some(phys_dev) = devices.into_iter().next() else {
|
||||||
|
return Err(OxrError::NoAvailableBackend);
|
||||||
|
};
|
||||||
|
phys_dev
|
||||||
|
};
|
||||||
|
init_from_instance_and_dev(
|
||||||
|
vk_entry.clone(),
|
||||||
|
vk_instance.clone(),
|
||||||
|
vk_physical_device,
|
||||||
|
instance_exts,
|
||||||
|
instance_flags,
|
||||||
|
device_exts.into(),
|
||||||
|
|info| unsafe { Ok(vk_instance.create_device(vk_physical_device, &info, None)?) },
|
||||||
|
)
|
||||||
|
.map(|v| v.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_extensions(
|
||||||
|
cfg: Option<&OxrManualGraphicsConfig>,
|
||||||
|
vk_entry: &ash::Entry,
|
||||||
|
) -> Result<(wgpu::InstanceFlags, Vec<&'static CStr>, Vec<&'static CStr>)> {
|
||||||
|
let flags = wgpu::InstanceFlags::default().with_env();
|
||||||
|
let mut instance_exts =
|
||||||
|
<Vulkan as Api>::Instance::desired_extensions(&vk_entry, VK_TARGET_VERSION_ASH, flags)?;
|
||||||
|
let mut device_exts = vec![
|
||||||
|
ash::khr::swapchain::NAME,
|
||||||
|
ash::khr::draw_indirect_count::NAME,
|
||||||
|
ash::khr::timeline_semaphore::NAME,
|
||||||
|
ash::khr::imageless_framebuffer::NAME,
|
||||||
|
ash::khr::image_format_list::NAME,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
ash::khr::portability_subset::NAME,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
ash::ext::metal_objects::NAME,
|
||||||
|
];
|
||||||
|
if let Some(cfg) = cfg {
|
||||||
|
instance_exts.extend(&cfg.vk_instance_exts);
|
||||||
|
device_exts.extend(&cfg.vk_device_exts);
|
||||||
|
}
|
||||||
|
instance_exts.dedup();
|
||||||
|
device_exts.dedup();
|
||||||
|
|
||||||
|
Ok((flags, instance_exts, device_exts))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_from_instance_and_dev(
|
||||||
|
vk_entry: ash::Entry,
|
||||||
|
vk_instance: ash::Instance,
|
||||||
|
vk_physical_device: vk::PhysicalDevice,
|
||||||
|
instance_exts: Vec<&'static CStr>,
|
||||||
|
instance_flags: InstanceFlags,
|
||||||
|
device_exts: Vec<&'static CStr>,
|
||||||
|
create_dev: impl for<'a> FnOnce(&'a vk::DeviceCreateInfo) -> Result<ash::Device>,
|
||||||
|
) -> Result<(WgpuGraphics, openxr::vulkan::SessionCreateInfo)> {
|
||||||
let api_layers = unsafe { vk_entry.enumerate_instance_layer_properties()? };
|
let api_layers = unsafe { vk_entry.enumerate_instance_layer_properties()? };
|
||||||
let has_nv_optimus = api_layers.iter().any(|v| {
|
let has_nv_optimus = api_layers.iter().any(|v| {
|
||||||
v.layer_name_as_c_str()
|
v.layer_name_as_c_str()
|
||||||
@@ -161,11 +314,10 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
|
|
||||||
drop(api_layers);
|
drop(api_layers);
|
||||||
|
|
||||||
|
// these to my knowledge aren't pointers, idk why openxr_sys says that they are,
|
||||||
|
// they're just ids
|
||||||
let vk_instance_ptr = vk_instance.handle().as_raw() as *const c_void;
|
let vk_instance_ptr = vk_instance.handle().as_raw() as *const c_void;
|
||||||
|
|
||||||
let vk_physical_device = ash::vk::PhysicalDevice::from_raw(unsafe {
|
|
||||||
instance.vulkan_graphics_device(system_id, vk_instance.handle().as_raw() as _)? as _
|
|
||||||
});
|
|
||||||
let vk_physical_device_ptr = vk_physical_device.as_raw() as *const c_void;
|
let vk_physical_device_ptr = vk_physical_device.as_raw() as *const c_void;
|
||||||
|
|
||||||
let vk_device_properties =
|
let vk_device_properties =
|
||||||
@@ -216,8 +368,8 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
vk_device_properties.api_version,
|
vk_device_properties.api_version,
|
||||||
android_sdk_version,
|
android_sdk_version,
|
||||||
None,
|
None,
|
||||||
extensions,
|
instance_exts,
|
||||||
flags,
|
instance_flags,
|
||||||
has_nv_optimus,
|
has_nv_optimus,
|
||||||
None,
|
None,
|
||||||
)?
|
)?
|
||||||
@@ -235,42 +387,27 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
.required_device_extensions(wgpu_features);
|
.required_device_extensions(wgpu_features);
|
||||||
|
|
||||||
let (wgpu_open_device, vk_device_ptr, queue_family_index) = {
|
let (wgpu_open_device, vk_device_ptr, queue_family_index) = {
|
||||||
let extensions_cchar: Vec<_> = device_extensions.iter().map(|s| s.as_ptr()).collect();
|
let extensions_cchar: Vec<_> = device_exts.iter().map(|s| s.as_ptr()).collect();
|
||||||
let mut enabled_phd_features = wgpu_exposed_adapter
|
let mut enabled_phd_features = wgpu_exposed_adapter
|
||||||
.adapter
|
.adapter
|
||||||
.physical_device_features(&enabled_extensions, wgpu_features);
|
.physical_device_features(&enabled_extensions, wgpu_features);
|
||||||
let family_index = 0;
|
let family_index = 0;
|
||||||
let family_info = ash::vk::DeviceQueueCreateInfo::default()
|
let family_info = vk::DeviceQueueCreateInfo::default()
|
||||||
.queue_family_index(family_index)
|
.queue_family_index(family_index)
|
||||||
.queue_priorities(&[1.0]);
|
.queue_priorities(&[1.0]);
|
||||||
let family_infos = [family_info];
|
let family_infos = [family_info];
|
||||||
let mut physical_device_multiview_features = ash::vk::PhysicalDeviceMultiviewFeatures {
|
let mut physical_device_multiview_features = vk::PhysicalDeviceMultiviewFeatures {
|
||||||
multiview: ash::vk::TRUE,
|
multiview: vk::TRUE,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let info = enabled_phd_features
|
let info = enabled_phd_features
|
||||||
.add_to_device_create(
|
.add_to_device_create(
|
||||||
ash::vk::DeviceCreateInfo::default()
|
vk::DeviceCreateInfo::default()
|
||||||
.queue_create_infos(&family_infos)
|
.queue_create_infos(&family_infos)
|
||||||
.push_next(&mut physical_device_multiview_features),
|
.push_next(&mut physical_device_multiview_features),
|
||||||
)
|
)
|
||||||
.enabled_extension_names(&extensions_cchar);
|
.enabled_extension_names(&extensions_cchar);
|
||||||
let vk_device = unsafe {
|
let vk_device = create_dev(&info)?;
|
||||||
let vk_device = instance
|
|
||||||
.create_vulkan_device(
|
|
||||||
system_id,
|
|
||||||
#[allow(clippy::missing_transmute_annotations)]
|
|
||||||
std::mem::transmute(vk_entry.static_fn().get_instance_proc_addr),
|
|
||||||
vk_physical_device.as_raw() as _,
|
|
||||||
&info as *const _ as *const _,
|
|
||||||
)?
|
|
||||||
.map_err(ash::vk::Result::from_raw)?;
|
|
||||||
|
|
||||||
ash::Device::load(
|
|
||||||
vk_instance.fp_v1_0(),
|
|
||||||
ash::vk::Device::from_raw(vk_device as _),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let vk_device_ptr = vk_device.handle().as_raw() as *const c_void;
|
let vk_device_ptr = vk_device.handle().as_raw() as *const c_void;
|
||||||
|
|
||||||
let wgpu_open_device = unsafe {
|
let wgpu_open_device = unsafe {
|
||||||
@@ -309,7 +446,6 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
WgpuGraphics(
|
WgpuGraphics(
|
||||||
wgpu_device,
|
wgpu_device,
|
||||||
@@ -328,46 +464,6 @@ unsafe impl GraphicsExt for openxr::Vulkan {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_session(
|
|
||||||
instance: &openxr::Instance,
|
|
||||||
system_id: openxr::SystemId,
|
|
||||||
info: &Self::SessionCreateInfo,
|
|
||||||
session_create_info_chain: &mut OxrSessionCreateNextChain,
|
|
||||||
) -> openxr::Result<(
|
|
||||||
openxr::Session<Self>,
|
|
||||||
openxr::FrameWaiter,
|
|
||||||
openxr::FrameStream<Self>,
|
|
||||||
)> {
|
|
||||||
let next_ptr = session_create_info_chain.chain_pointer();
|
|
||||||
let binding = sys::GraphicsBindingVulkanKHR {
|
|
||||||
ty: sys::GraphicsBindingVulkanKHR::TYPE,
|
|
||||||
next: next_ptr,
|
|
||||||
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 = sys::SessionCreateInfo {
|
|
||||||
ty: sys::SessionCreateInfo::TYPE,
|
|
||||||
next: &binding as *const _ as *const _,
|
|
||||||
create_flags: Default::default(),
|
|
||||||
system_id,
|
|
||||||
};
|
|
||||||
let mut out = sys::Session::NULL;
|
|
||||||
cvt((instance.fp().create_session)(
|
|
||||||
instance.as_raw(),
|
|
||||||
&info,
|
|
||||||
&mut out,
|
|
||||||
))?;
|
|
||||||
Ok(openxr::Session::from_raw(
|
|
||||||
instance.clone(),
|
|
||||||
out,
|
|
||||||
Box::new(()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cvt(x: sys::Result) -> openxr::Result<sys::Result> {
|
fn cvt(x: sys::Result) -> openxr::Result<sys::Result> {
|
||||||
if x.into_raw() >= 0 {
|
if x.into_raw() >= 0 {
|
||||||
Ok(x)
|
Ok(x)
|
||||||
@@ -376,7 +472,7 @@ fn cvt(x: sys::Result) -> openxr::Result<sys::Result> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vulkan_to_wgpu(format: ash::vk::Format) -> Option<wgpu::TextureFormat> {
|
fn vulkan_to_wgpu(format: vk::Format) -> Option<wgpu::TextureFormat> {
|
||||||
use ash::vk::Format as F;
|
use ash::vk::Format as F;
|
||||||
use wgpu::TextureFormat as Tf;
|
use wgpu::TextureFormat as Tf;
|
||||||
use wgpu::{AstcBlock, AstcChannel};
|
use wgpu::{AstcBlock, AstcChannel};
|
||||||
@@ -624,7 +720,7 @@ fn vulkan_to_wgpu(format: ash::vk::Format) -> Option<wgpu::TextureFormat> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wgpu_to_vulkan(format: wgpu::TextureFormat) -> Option<ash::vk::Format> {
|
fn wgpu_to_vulkan(format: wgpu::TextureFormat) -> Option<vk::Format> {
|
||||||
// Copied with minor modification from:
|
// Copied with minor modification from:
|
||||||
// https://github.com/gfx-rs/wgpu/blob/a7defb723f856d946d6d220e9897d20dbb7b8f61/wgpu-hal/src/vulkan/conv.rs#L5-L151
|
// https://github.com/gfx-rs/wgpu/blob/a7defb723f856d946d6d220e9897d20dbb7b8f61/wgpu-hal/src/vulkan/conv.rs#L5-L151
|
||||||
// license: MIT OR Apache-2.0
|
// license: MIT OR Apache-2.0
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ impl Plugin for OxrInitPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<OxrInteractionProfileChanged>();
|
app.add_event::<OxrInteractionProfileChanged>();
|
||||||
app.init_resource::<OxrSessionConfig>();
|
app.init_resource::<OxrSessionConfig>();
|
||||||
match self.init_xr() {
|
let cfg = app.world_mut().remove_resource::<OxrManualGraphicsConfig>();
|
||||||
|
match self.init_xr(cfg.as_ref()) {
|
||||||
Ok((
|
Ok((
|
||||||
instance,
|
instance,
|
||||||
system_id,
|
system_id,
|
||||||
@@ -160,6 +161,31 @@ impl Plugin for OxrInitPlugin {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to initialize openxr: {e}");
|
error!("Failed to initialize openxr: {e}");
|
||||||
|
if let Some(cfg) = cfg {
|
||||||
|
if let Ok(WgpuGraphics(device, queue, adapter_info, adapter, wgpu_instance)) =
|
||||||
|
graphics_match!(
|
||||||
|
cfg.fallback_backend;
|
||||||
|
_ => Api::init_fallback_graphics(&self.app_info ,&cfg)
|
||||||
|
)
|
||||||
|
.inspect_err(|err| {
|
||||||
|
error!("Failed to initialize custom fallback graphics: {err}")
|
||||||
|
})
|
||||||
|
{
|
||||||
|
app.add_plugins(RenderPlugin {
|
||||||
|
render_creation: RenderCreation::manual(
|
||||||
|
device.into(),
|
||||||
|
RenderQueue(Arc::new(WgpuWrapper::new(queue))),
|
||||||
|
RenderAdapterInfo(WgpuWrapper::new(adapter_info)),
|
||||||
|
RenderAdapter(Arc::new(WgpuWrapper::new(adapter))),
|
||||||
|
RenderInstance(Arc::new(WgpuWrapper::new(wgpu_instance))),
|
||||||
|
),
|
||||||
|
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
|
||||||
|
debug_flags: self.render_debug_flags,
|
||||||
|
})
|
||||||
|
.insert_resource(XrState::Unavailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
app.add_plugins(RenderPlugin::default())
|
app.add_plugins(RenderPlugin::default())
|
||||||
.insert_resource(XrState::Unavailable);
|
.insert_resource(XrState::Unavailable);
|
||||||
}
|
}
|
||||||
@@ -203,6 +229,7 @@ fn detect_session_destroyed(
|
|||||||
impl OxrInitPlugin {
|
impl OxrInitPlugin {
|
||||||
fn init_xr(
|
fn init_xr(
|
||||||
&self,
|
&self,
|
||||||
|
cfg: Option<&OxrManualGraphicsConfig>,
|
||||||
) -> OxrResult<(
|
) -> OxrResult<(
|
||||||
OxrInstance,
|
OxrInstance,
|
||||||
OxrSystemId,
|
OxrSystemId,
|
||||||
@@ -272,7 +299,7 @@ impl OxrInitPlugin {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let (graphics, graphics_info) = instance.init_graphics(system_id)?;
|
let (graphics, graphics_info) = instance.init_graphics(system_id, cfg)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
instance,
|
instance,
|
||||||
|
|||||||
@@ -106,11 +106,12 @@ impl OxrInstance {
|
|||||||
pub fn init_graphics(
|
pub fn init_graphics(
|
||||||
&self,
|
&self,
|
||||||
system_id: openxr::SystemId,
|
system_id: openxr::SystemId,
|
||||||
|
manual_config: Option<&OxrManualGraphicsConfig>,
|
||||||
) -> OxrResult<(WgpuGraphics, SessionGraphicsCreateInfo)> {
|
) -> OxrResult<(WgpuGraphics, SessionGraphicsCreateInfo)> {
|
||||||
graphics_match!(
|
graphics_match!(
|
||||||
self.1;
|
self.1;
|
||||||
_ => {
|
_ => {
|
||||||
let (graphics, session_info) = Api::init_graphics(&self.2, self, system_id)?;
|
let (graphics, session_info) = Api::init_graphics(&self.2, self, system_id, manual_config)?;
|
||||||
|
|
||||||
Ok((graphics, SessionGraphicsCreateInfo(Api::wrap(session_info))))
|
Ok((graphics, SessionGraphicsCreateInfo(Api::wrap(session_info))))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user