Browse Source

Add vulkan device creation

main
Jens Pitkänen 4 months ago
parent
commit
0cae0fbcf8
2 changed files with 169 additions and 21 deletions
  1. +1
    -1
      src/main.rs
  2. +168
    -20
      src/xr_main.rs

+ 1
- 1
src/main.rs View File

@ -12,7 +12,7 @@ fn main() {
);
let xr = XrStateMachine::new().unwrap();
if let Err(err) = xr.run() {
log::error!("Encountered fatal OpenXR error: {}", err);
log::error!("{}", err);
} else {
log::info!("Shutting down.");
}


+ 168
- 20
src/xr_main.rs View File

@ -1,49 +1,66 @@
use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0};
use ash::vk;
use ash::vk::Handle;
use openxr::*;
use openxr_sys::platform::*;
use openxr_sys::Result as XrResult;
use pkg_version::{pkg_version_major, pkg_version_minor, pkg_version_patch};
use std::error::Error;
use std::thread;
use std::os::raw::c_char;
use std::time::Duration;
use std::{fmt, mem, thread};
pub struct XrStateMachine {
instance: Instance,
vk_entry: ash::Entry,
}
impl XrStateMachine {
/// Creates an OpenXR instance, ready to create a session.
pub fn new() -> Result<XrStateMachine, Box<dyn Error>> {
pub fn new() -> Result<XrStateMachine, Error> {
log::trace!("Loading an OpenXR loader.");
let entry = openxr::Entry::load()?;
let vk_entry = unsafe { ash::Entry::new()? };
log::trace!("Creating an OpenXR instance.");
let info = ApplicationInfo {
let info = openxr::ApplicationInfo {
application_name: env!("CARGO_PKG_NAME"),
application_version: pkg_version_major!() * 1_000_000
+ pkg_version_minor!() * 1_000
+ pkg_version_patch!(),
application_version: vk::make_version(
pkg_version_major!(),
pkg_version_minor!(),
pkg_version_patch!(),
),
engine_name: "",
engine_version: 0,
};
let mut extensions = ExtensionSet::default();
// Enables openxr::Instance::create_vulkan_instance.
extensions.khr_vulkan_enable2 = true;
let layers = [];
let instance = entry.create_instance(&info, &extensions, &layers)?;
log::trace!("OpenXR instance created.");
if let Ok(props) = instance.properties() {
log::trace!(
"OpenXR runtime: {} version {}.",
props.runtime_name,
props.runtime_version
);
}
Ok(XrStateMachine { instance })
Ok(XrStateMachine { instance, vk_entry })
}
/// Creates a session (or multiple, if it gets recoverably
/// destroyed) and starts rendering when the user is ready to
/// receive pixels.
pub fn run(&self) -> openxr::Result<()> {
pub fn run(&self) -> Result<(), Error> {
let mut session_recreation_attempts = 0;
loop {
log::trace!("Creating an OpenXR session.");
let xr_result = xr_main(&self.instance);
let xr_result = xr_main(&self.instance, &self.vk_entry);
log::trace!("OpenXR session destroyed.");
if let Err(XrResult::ERROR_SESSION_LOST)
| Err(XrResult::ERROR_FORM_FACTOR_UNAVAILABLE) = xr_result
if let Err(Error::Xr(XrResult::ERROR_SESSION_LOST))
| Err(Error::Xr(XrResult::ERROR_FORM_FACTOR_UNAVAILABLE)) = xr_result
{
// Both of these errors require recreating the
// session, but are not fatal. So keep trying to
@ -61,14 +78,87 @@ impl XrStateMachine {
}
}
fn xr_main(xr_instance: &Instance) -> openxr::Result<()> {
fn xr_main(xr_instance: &Instance, vk_entry: &ash::Entry) -> Result<(), Error> {
// Set up the parameters for creating the OpenXR session.
log::trace!("Querying info for session.");
log::trace!("Setting up the session.");
let system = xr_instance.system(FormFactor::HEAD_MOUNTED_DISPLAY)?;
let (vk_instance, physical_device, device, queue_family_index, queue_index) = {
// TODO: Load Vulkan and get the stuff listed above
todo!()
let vk_reqs = xr_instance.graphics_requirements::<Vulkan>(system)?;
let vk_version = openxr::Version::new(1, 0, 0);
if vk_reqs.min_api_version_supported > vk_version
|| vk_reqs.max_api_version_supported < vk_version
{
Err("Vulkan 1.0 not supported")?;
}
let application_name = format!("{}\0", env!("CARGO_PKG_NAME"));
let application_info = vk::ApplicationInfo {
p_application_name: application_name.as_ptr() as *const c_char,
application_version: vk::make_version(
pkg_version_major!(),
pkg_version_minor!(),
pkg_version_patch!(),
),
..Default::default()
};
let instance_create_info = [vk::InstanceCreateInfo {
p_application_info: &application_info,
..Default::default()
}];
let get_instance_proc_addr =
unsafe { mem::transmute(vk_entry.static_fn().get_instance_proc_addr) };
let vk_instance = unsafe {
xr_instance.create_vulkan_instance(
system,
get_instance_proc_addr,
instance_create_info.as_ptr() as *const VkInstanceCreateInfo,
)??
};
let vk_instance = unsafe {
ash::Instance::load(
vk_entry.static_fn(),
vk::Instance::from_raw(vk_instance as u64),
)
};
let physical_device = xr_instance
.vulkan_graphics_device(system, vk_instance.handle().as_raw() as VkInstance)?;
let physical_device = vk::PhysicalDevice::from_raw(physical_device as u64);
let queue_family_properties =
unsafe { vk_instance.get_physical_device_queue_family_properties(physical_device) };
let queue_family_index = queue_family_properties
.into_iter()
.position(|props| props.queue_flags.contains(vk::QueueFlags::GRAPHICS))
.ok_or("device picked by the OpenXR runtime does not have a graphics queue")?
as u32;
let queue_priorities = [1.0, 0.0];
let queue_create_infos = [vk::DeviceQueueCreateInfo {
queue_family_index,
queue_count: 1,
p_queue_priorities: queue_priorities.as_ptr(),
..Default::default()
}];
let device_create_info = [vk::DeviceCreateInfo {
queue_create_info_count: queue_create_infos.len() as u32,
p_queue_create_infos: queue_create_infos.as_ptr(),
..Default::default()
}];
let device = unsafe {
xr_instance.create_vulkan_device(
system,
get_instance_proc_addr,
physical_device.as_raw() as VkPhysicalDevice,
device_create_info.as_ptr() as *const VkDeviceCreateInfo,
)??
};
let device = unsafe {
ash::Device::load(vk_instance.fp_v1_0(), vk::Device::from_raw(device as u64))
};
(vk_instance, physical_device, device, queue_family_index, 0)
};
// These were referred to in the docs, but may not be needed:
// - xrGetInstanceProperties
// - xrGetSystemProperties
@ -83,9 +173,9 @@ fn xr_main(xr_instance: &Instance) -> openxr::Result<()> {
// - xrSuggestInteractionProfileBindings
log::trace!("Creating the session.");
let info = vulkan::SessionCreateInfo {
instance: vk_instance,
physical_device,
device,
instance: vk_instance.handle().as_raw() as VkInstance,
physical_device: physical_device.as_raw() as VkPhysicalDevice,
device: device.handle().as_raw() as VkDevice,
queue_family_index,
queue_index,
};
@ -102,6 +192,7 @@ fn xr_main(xr_instance: &Instance) -> openxr::Result<()> {
// - xrCreateActionSpace
// - xrAttachSessionActionSets
log::trace!("Booting up Vulkan.");
let _queue = unsafe { device.get_device_queue(queue_family_index, queue_index) };
// TODO: Boot up Vulkan:
// - xrEnumerateSwapchainFormats
// - xrCreateSwapchain
@ -129,7 +220,7 @@ fn xr_main(xr_instance: &Instance) -> openxr::Result<()> {
// perspective. xrDestroySession is called in the
// session's Drop implementation.
log::trace!("The OpenXR runtime returned LOSS_PENDING, recreating session.");
return Err(XrResult::ERROR_SESSION_LOST);
Err(XrResult::ERROR_SESSION_LOST)?;
}
if session_state == SessionState::EXITING {
log::trace!("Exiting session as requested.");
@ -178,3 +269,60 @@ fn xr_main(xr_instance: &Instance) -> openxr::Result<()> {
}
}
}
#[derive(Debug)]
pub enum Error {
XrLoadError(LoadError),
VkLoadError(ash::LoadingError),
Xr(XrResult),
Vk(vk::Result),
Generic(&'static str),
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::XrLoadError(err) => write!(fmt, "OpenXR loading error: {}", err),
Error::VkLoadError(err) => write!(fmt, "Vulkan loading error: {}", err),
Error::Xr(err) => write!(fmt, "OpenXR error: {}", err),
Error::Vk(err) => write!(fmt, "Vulkan error: {}", err),
Error::Generic(s) => write!(fmt, "Error: {}", s),
}
}
}
impl From<LoadError> for Error {
fn from(other: LoadError) -> Error {
Error::XrLoadError(other)
}
}
impl From<ash::LoadingError> for Error {
fn from(other: ash::LoadingError) -> Error {
Error::VkLoadError(other)
}
}
impl From<XrResult> for Error {
fn from(other: XrResult) -> Error {
Error::Xr(other)
}
}
impl From<vk::Result> for Error {
fn from(other: vk::Result) -> Error {
Error::Vk(other)
}
}
impl From<&'static str> for Error {
fn from(other: &'static str) -> Error {
Error::Generic(other)
}
}
impl From<openxr_sys::platform::VkResult> for Error {
fn from(other: openxr_sys::platform::VkResult) -> Error {
Error::Vk(vk::Result::from_raw(other))
}
}

Loading…
Cancel
Save