Skip to content

Instantly share code, notes, and snippets.

@Noxime

Noxime/vulkan.rs Secret

Created October 23, 2022 19:29
Show Gist options
  • Save Noxime/ba570ca38c4e91470ddd34a3e23babd4 to your computer and use it in GitHub Desktop.
Save Noxime/ba570ca38c4e91470ddd34a3e23babd4 to your computer and use it in GitHub Desktop.
pub(crate) fn create_session(
openxr: &xr::Instance,
system: xr::SystemId,
features: wgpu::Features,
limits: wgpu::Limits,
) -> Result<Create> {
// MUST be queried before OpenXR is happy
let requirements = openxr.graphics_requirements::<xr::Vulkan>(system)?;
let flags = InstanceFlags::VALIDATION | InstanceFlags::DEBUG;
let api_min = requirements.min_api_version_supported;
let api_max = requirements.max_api_version_supported;
// Load our Vulkan library
let entry = unsafe { Entry::load()? };
let app_info = vk::ApplicationInfo::builder().api_version(vk::make_api_version(
0,
api_max.major() as u32,
api_max.minor() as u32,
api_max.patch(),
));
// WGPU requires some vulkan extensions to function that depend on the flags
let extensions = <Vulkan as Api>::Instance::required_extensions(&entry, flags)?;
let raw_extensions: Vec<_> = extensions.iter().map(|c| c.as_ptr()).collect();
let instance_info = vk::InstanceCreateInfo::builder()
.enabled_extension_names(&raw_extensions)
.application_info(&app_info);
unsafe {
let gipa = std::mem::transmute(entry.static_fn().get_instance_proc_addr);
// Create vulkan instance and physical device compatible with our OpenXR system
let vulkan_handle = openxr
.create_vulkan_instance(system, gipa, as_ptr(&instance_info))?
.map_err(vk_err)?;
let physical_handle = openxr.vulkan_graphics_device(system, vulkan_handle)?;
let physical_device = as_handle(physical_handle);
// Load the ash instance from our vulkan instance
let vulkan = ash::Instance::load(entry.static_fn(), as_handle(vulkan_handle));
let properties = vulkan.get_physical_device_properties(physical_device);
let api = vk_version(properties.api_version);
// Check our API version is compatible
if api < api_min || api > api_max {
warn!("Vulkan version is {api}, though we requested max {api_max}");
}
// Find a queue family which has GRAPHICS capability
let queue_family = vulkan
.get_physical_device_queue_family_properties(physical_device)
.into_iter()
.enumerate()
.find_map(|(i, info)| {
info.queue_flags
.contains(vk::QueueFlags::GRAPHICS)
.then_some(i as u32)
})
.ok_or(Error::BackendUnavailable)?;
// Create the HAL primitives
let instance = <Vulkan as Api>::Instance::from_raw(
entry,
vulkan,
properties.api_version,
0, // TODO: No Android support
extensions,
flags,
false, // TODO: No NVidia Optimus detection
None,
)?;
// "Expose" the physical device as an adapter
let exposed = instance
.expose_adapter(physical_device)
.ok_or(Error::BackendUnavailable)?;
// Query the required instance extensions for using WGPU on Vulkan
let extensions = exposed.adapter.required_device_extensions(features);
let raw_extensions: Vec<*const i8> = extensions.iter().map(|s| s.as_ptr()).collect();
// Configure the vulkan virtual device
let queue_info = vk::DeviceQueueCreateInfo::builder()
.queue_family_index(queue_family)
.queue_priorities(&[1.0])
.build();
let device_info = vk::DeviceCreateInfo::builder()
.enabled_extension_names(&raw_extensions)
.queue_create_infos(&[queue_info])
.build();
// Acquire a raw handle to a vulkan virtual device, using WGPU required extensions
let device_handle = openxr
.create_vulkan_device(system, gipa, physical_handle, as_ptr(&device_info))?
.map_err(vk_err)?;
let vk_device = ash::Device::load(
instance.shared_instance().raw_instance().fp_v1_0(),
as_handle(device_handle),
);
let uab = wgpu_hal::UpdateAfterBindTypes::from_limits(&limits, &properties.limits);
// "Open" the WGPU virtual device
let open = exposed.adapter.device_from_raw(
vk_device,
true,
&extensions,
features,
uab,
queue_family, // family_index,
0, // queue_index, this should be something!
)?;
// Create our concrete WGPU types from their HAL counterparts
let instance = wgpu::Instance::from_hal::<wgpu_hal::api::Vulkan>(instance);
let adapter = instance.create_adapter_from_hal(exposed);
let (device, queue) = adapter.create_device_from_hal(
open,
&wgpu::DeviceDescriptor {
label: Some("OpenXR"),
features,
limits,
},
None,
)?;
let (session, waiter, stream) = openxr.create_session::<Wgpu>(
system,
&SessionCreateInfo::Vulkan(openxr::vulkan::SessionCreateInfo {
instance: vulkan_handle,
physical_device: physical_device.as_raw() as *const _,
device: device_handle,
queue_family_index: queue_family,
queue_index: 0,
}),
)?;
Ok(Create {
instance,
adapter,
device,
queue,
session,
waiter,
stream,
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment