From 65edb0636173c49371ebe79d7921f42ff3928849 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Fri, 1 Dec 2023 08:53:11 +0000 Subject: [PATCH 01/10] Fix Vulkan version message --- src/graphics/vulkan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index b53ed02..8e69685 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -123,7 +123,7 @@ pub fn initialize_xr_instance( || vk_target_version_xr.major() > reqs.max_api_version_supported.major() { panic!( - "OpenXR runtime requires Vulkan version > {}, < {}.0.0", + "OpenXR runtime requires Vulkan version >= {}, < {}.0.0", reqs.min_api_version_supported, reqs.max_api_version_supported.major() + 1 ); From f63081906df6f92cf43fec1052e2d649230840db Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Fri, 1 Dec 2023 10:28:46 +0000 Subject: [PATCH 02/10] Copy paste static parts of wgpu format table --- src/graphics/vulkan.rs | 191 ++++++++++++++++++++++++++++------------- 1 file changed, 130 insertions(+), 61 deletions(-) diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index 8e69685..6a5379d 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -470,67 +470,136 @@ pub fn start_xr_session( } fn wgpu_to_vulkan(format: wgpu::TextureFormat) -> vk::Format { - use vk::Format; + // Copied with minor modification from: + // https://github.com/gfx-rs/wgpu/blob/v0.19/wgpu-hal/src/vulkan/conv.rs#L5C1-L153 + // license: MIT OR Apache-2.0 + use ash::vk::Format as F; + use wgpu::TextureFormat as Tf; + use wgpu::{AstcBlock, AstcChannel}; match format { - wgpu::TextureFormat::R8Unorm => Format::R8_UNORM, - wgpu::TextureFormat::R8Snorm => Format::R8_SNORM, - wgpu::TextureFormat::R8Uint => Format::R8_UINT, - wgpu::TextureFormat::R8Sint => Format::R8_SINT, - wgpu::TextureFormat::R16Uint => Format::R16_UINT, - wgpu::TextureFormat::R16Sint => Format::R16_SINT, - wgpu::TextureFormat::R16Unorm => Format::R16_UNORM, - wgpu::TextureFormat::R16Snorm => Format::R16_SNORM, - wgpu::TextureFormat::R16Float => Format::R16_SFLOAT, - wgpu::TextureFormat::Rg8Unorm => Format::R8G8_UNORM, - wgpu::TextureFormat::Rg8Snorm => Format::R8G8_SNORM, - wgpu::TextureFormat::Rg8Uint => Format::R8G8_UINT, - wgpu::TextureFormat::Rg8Sint => Format::R8G8_SINT, - wgpu::TextureFormat::R32Uint => Format::R32_UINT, - wgpu::TextureFormat::R32Sint => Format::R32_SINT, - wgpu::TextureFormat::R32Float => Format::R32_SFLOAT, - wgpu::TextureFormat::Rg16Uint => Format::R16G16_UINT, - wgpu::TextureFormat::Rg16Sint => Format::R16G16_SINT, - wgpu::TextureFormat::Rg16Unorm => Format::R16G16_UNORM, - wgpu::TextureFormat::Rg16Snorm => Format::R16G16_SNORM, - wgpu::TextureFormat::Rg16Float => Format::R16G16_SFLOAT, - wgpu::TextureFormat::Rgba8Unorm => Format::R8G8B8A8_UNORM, - wgpu::TextureFormat::Rgba8UnormSrgb => Format::R8G8B8A8_SRGB, - wgpu::TextureFormat::Rgba8Snorm => Format::R8G8B8A8_SNORM, - wgpu::TextureFormat::Rgba8Uint => Format::R8G8B8A8_UINT, - wgpu::TextureFormat::Rgba8Sint => Format::R8G8B8A8_SINT, - wgpu::TextureFormat::Bgra8Unorm => Format::B8G8R8A8_UNORM, - wgpu::TextureFormat::Bgra8UnormSrgb => Format::B8G8R8A8_SRGB, - wgpu::TextureFormat::Rgb9e5Ufloat => Format::E5B9G9R9_UFLOAT_PACK32, // this might be the wrong type??? i can't tell - wgpu::TextureFormat::Rgb10a2Unorm => Format::A2R10G10B10_UNORM_PACK32, - wgpu::TextureFormat::Rg11b10Float => panic!("this texture type invokes nothing but fear within my soul and i don't think vulkan has a proper type for this"), - wgpu::TextureFormat::Rg32Uint => Format::R32G32_UINT, - wgpu::TextureFormat::Rg32Sint => Format::R32G32_SINT, - wgpu::TextureFormat::Rg32Float => Format::R32G32_SFLOAT, - wgpu::TextureFormat::Rgba16Uint => Format::R16G16B16A16_UINT, - wgpu::TextureFormat::Rgba16Sint => Format::R16G16B16A16_SINT, - wgpu::TextureFormat::Rgba16Unorm => Format::R16G16B16A16_UNORM, - wgpu::TextureFormat::Rgba16Snorm => Format::R16G16B16A16_SNORM, - wgpu::TextureFormat::Rgba16Float => Format::R16G16B16A16_SFLOAT, - wgpu::TextureFormat::Rgba32Uint => Format::R32G32B32A32_UINT, - wgpu::TextureFormat::Rgba32Sint => Format::R32G32B32A32_SINT, - wgpu::TextureFormat::Rgba32Float => Format::R32G32B32A32_SFLOAT, - wgpu::TextureFormat::Stencil8 => Format::S8_UINT, - wgpu::TextureFormat::Depth16Unorm => Format::D16_UNORM, - wgpu::TextureFormat::Depth24Plus => Format::X8_D24_UNORM_PACK32, - wgpu::TextureFormat::Depth24PlusStencil8 => Format::D24_UNORM_S8_UINT, - wgpu::TextureFormat::Depth32Float => Format::D32_SFLOAT, - wgpu::TextureFormat::Depth32FloatStencil8 => Format::D32_SFLOAT_S8_UINT, - wgpu::TextureFormat::Etc2Rgb8Unorm => Format::ETC2_R8G8B8_UNORM_BLOCK, - wgpu::TextureFormat::Etc2Rgb8UnormSrgb => Format::ETC2_R8G8B8_SRGB_BLOCK, - wgpu::TextureFormat::Etc2Rgb8A1Unorm => Format::ETC2_R8G8B8A1_UNORM_BLOCK, - wgpu::TextureFormat::Etc2Rgb8A1UnormSrgb => Format::ETC2_R8G8B8A1_SRGB_BLOCK, - wgpu::TextureFormat::Etc2Rgba8Unorm => Format::ETC2_R8G8B8A8_UNORM_BLOCK, - wgpu::TextureFormat::Etc2Rgba8UnormSrgb => Format::ETC2_R8G8B8A8_SRGB_BLOCK, - wgpu::TextureFormat::EacR11Unorm => Format::EAC_R11_UNORM_BLOCK, - wgpu::TextureFormat::EacR11Snorm => Format::EAC_R11_SNORM_BLOCK, - wgpu::TextureFormat::EacRg11Unorm => Format::EAC_R11G11_UNORM_BLOCK, - wgpu::TextureFormat::EacRg11Snorm => Format::EAC_R11G11_SNORM_BLOCK, - wgpu::TextureFormat::Astc { .. } => panic!("please god kill me now"), - _ => panic!("fuck no") + Tf::R8Unorm => F::R8_UNORM, + Tf::R8Snorm => F::R8_SNORM, + Tf::R8Uint => F::R8_UINT, + Tf::R8Sint => F::R8_SINT, + Tf::R16Uint => F::R16_UINT, + Tf::R16Sint => F::R16_SINT, + Tf::R16Unorm => F::R16_UNORM, + Tf::R16Snorm => F::R16_SNORM, + Tf::R16Float => F::R16_SFLOAT, + Tf::Rg8Unorm => F::R8G8_UNORM, + Tf::Rg8Snorm => F::R8G8_SNORM, + Tf::Rg8Uint => F::R8G8_UINT, + Tf::Rg8Sint => F::R8G8_SINT, + Tf::Rg16Unorm => F::R16G16_UNORM, + Tf::Rg16Snorm => F::R16G16_SNORM, + Tf::R32Uint => F::R32_UINT, + Tf::R32Sint => F::R32_SINT, + Tf::R32Float => F::R32_SFLOAT, + Tf::Rg16Uint => F::R16G16_UINT, + Tf::Rg16Sint => F::R16G16_SINT, + Tf::Rg16Float => F::R16G16_SFLOAT, + Tf::Rgba8Unorm => F::R8G8B8A8_UNORM, + Tf::Rgba8UnormSrgb => F::R8G8B8A8_SRGB, + Tf::Bgra8UnormSrgb => F::B8G8R8A8_SRGB, + Tf::Rgba8Snorm => F::R8G8B8A8_SNORM, + Tf::Bgra8Unorm => F::B8G8R8A8_UNORM, + Tf::Rgba8Uint => F::R8G8B8A8_UINT, + Tf::Rgba8Sint => F::R8G8B8A8_SINT, + Tf::Rgb10a2Uint => F::A2B10G10R10_UINT_PACK32, + Tf::Rgb10a2Unorm => F::A2B10G10R10_UNORM_PACK32, + Tf::Rg11b10Float => F::B10G11R11_UFLOAT_PACK32, + Tf::Rg32Uint => F::R32G32_UINT, + Tf::Rg32Sint => F::R32G32_SINT, + Tf::Rg32Float => F::R32G32_SFLOAT, + Tf::Rgba16Uint => F::R16G16B16A16_UINT, + Tf::Rgba16Sint => F::R16G16B16A16_SINT, + Tf::Rgba16Unorm => F::R16G16B16A16_UNORM, + Tf::Rgba16Snorm => F::R16G16B16A16_SNORM, + Tf::Rgba16Float => F::R16G16B16A16_SFLOAT, + Tf::Rgba32Uint => F::R32G32B32A32_UINT, + Tf::Rgba32Sint => F::R32G32B32A32_SINT, + Tf::Rgba32Float => F::R32G32B32A32_SFLOAT, + Tf::Depth32Float => F::D32_SFLOAT, + Tf::Depth32FloatStencil8 => F::D32_SFLOAT_S8_UINT, + Tf::Depth24Plus | Tf::Depth24PlusStencil8 | Tf::Stencil8 => { + panic!("Cannot convert format that is dependent on device properties") + } + Tf::Depth16Unorm => F::D16_UNORM, + Tf::NV12 => F::G8_B8R8_2PLANE_420_UNORM, + Tf::Rgb9e5Ufloat => F::E5B9G9R9_UFLOAT_PACK32, + Tf::Bc1RgbaUnorm => F::BC1_RGBA_UNORM_BLOCK, + Tf::Bc1RgbaUnormSrgb => F::BC1_RGBA_SRGB_BLOCK, + Tf::Bc2RgbaUnorm => F::BC2_UNORM_BLOCK, + Tf::Bc2RgbaUnormSrgb => F::BC2_SRGB_BLOCK, + Tf::Bc3RgbaUnorm => F::BC3_UNORM_BLOCK, + Tf::Bc3RgbaUnormSrgb => F::BC3_SRGB_BLOCK, + Tf::Bc4RUnorm => F::BC4_UNORM_BLOCK, + Tf::Bc4RSnorm => F::BC4_SNORM_BLOCK, + Tf::Bc5RgUnorm => F::BC5_UNORM_BLOCK, + Tf::Bc5RgSnorm => F::BC5_SNORM_BLOCK, + Tf::Bc6hRgbUfloat => F::BC6H_UFLOAT_BLOCK, + Tf::Bc6hRgbFloat => F::BC6H_SFLOAT_BLOCK, + Tf::Bc7RgbaUnorm => F::BC7_UNORM_BLOCK, + Tf::Bc7RgbaUnormSrgb => F::BC7_SRGB_BLOCK, + Tf::Etc2Rgb8Unorm => F::ETC2_R8G8B8_UNORM_BLOCK, + Tf::Etc2Rgb8UnormSrgb => F::ETC2_R8G8B8_SRGB_BLOCK, + Tf::Etc2Rgb8A1Unorm => F::ETC2_R8G8B8A1_UNORM_BLOCK, + Tf::Etc2Rgb8A1UnormSrgb => F::ETC2_R8G8B8A1_SRGB_BLOCK, + Tf::Etc2Rgba8Unorm => F::ETC2_R8G8B8A8_UNORM_BLOCK, + Tf::Etc2Rgba8UnormSrgb => F::ETC2_R8G8B8A8_SRGB_BLOCK, + Tf::EacR11Unorm => F::EAC_R11_UNORM_BLOCK, + Tf::EacR11Snorm => F::EAC_R11_SNORM_BLOCK, + Tf::EacRg11Unorm => F::EAC_R11G11_UNORM_BLOCK, + Tf::EacRg11Snorm => F::EAC_R11G11_SNORM_BLOCK, + Tf::Astc { block, channel } => match channel { + AstcChannel::Unorm => match block { + AstcBlock::B4x4 => F::ASTC_4X4_UNORM_BLOCK, + AstcBlock::B5x4 => F::ASTC_5X4_UNORM_BLOCK, + AstcBlock::B5x5 => F::ASTC_5X5_UNORM_BLOCK, + AstcBlock::B6x5 => F::ASTC_6X5_UNORM_BLOCK, + AstcBlock::B6x6 => F::ASTC_6X6_UNORM_BLOCK, + AstcBlock::B8x5 => F::ASTC_8X5_UNORM_BLOCK, + AstcBlock::B8x6 => F::ASTC_8X6_UNORM_BLOCK, + AstcBlock::B8x8 => F::ASTC_8X8_UNORM_BLOCK, + AstcBlock::B10x5 => F::ASTC_10X5_UNORM_BLOCK, + AstcBlock::B10x6 => F::ASTC_10X6_UNORM_BLOCK, + AstcBlock::B10x8 => F::ASTC_10X8_UNORM_BLOCK, + AstcBlock::B10x10 => F::ASTC_10X10_UNORM_BLOCK, + AstcBlock::B12x10 => F::ASTC_12X10_UNORM_BLOCK, + AstcBlock::B12x12 => F::ASTC_12X12_UNORM_BLOCK, + }, + AstcChannel::UnormSrgb => match block { + AstcBlock::B4x4 => F::ASTC_4X4_SRGB_BLOCK, + AstcBlock::B5x4 => F::ASTC_5X4_SRGB_BLOCK, + AstcBlock::B5x5 => F::ASTC_5X5_SRGB_BLOCK, + AstcBlock::B6x5 => F::ASTC_6X5_SRGB_BLOCK, + AstcBlock::B6x6 => F::ASTC_6X6_SRGB_BLOCK, + AstcBlock::B8x5 => F::ASTC_8X5_SRGB_BLOCK, + AstcBlock::B8x6 => F::ASTC_8X6_SRGB_BLOCK, + AstcBlock::B8x8 => F::ASTC_8X8_SRGB_BLOCK, + AstcBlock::B10x5 => F::ASTC_10X5_SRGB_BLOCK, + AstcBlock::B10x6 => F::ASTC_10X6_SRGB_BLOCK, + AstcBlock::B10x8 => F::ASTC_10X8_SRGB_BLOCK, + AstcBlock::B10x10 => F::ASTC_10X10_SRGB_BLOCK, + AstcBlock::B12x10 => F::ASTC_12X10_SRGB_BLOCK, + AstcBlock::B12x12 => F::ASTC_12X12_SRGB_BLOCK, + }, + AstcChannel::Hdr => match block { + AstcBlock::B4x4 => F::ASTC_4X4_SFLOAT_BLOCK_EXT, + AstcBlock::B5x4 => F::ASTC_5X4_SFLOAT_BLOCK_EXT, + AstcBlock::B5x5 => F::ASTC_5X5_SFLOAT_BLOCK_EXT, + AstcBlock::B6x5 => F::ASTC_6X5_SFLOAT_BLOCK_EXT, + AstcBlock::B6x6 => F::ASTC_6X6_SFLOAT_BLOCK_EXT, + AstcBlock::B8x5 => F::ASTC_8X5_SFLOAT_BLOCK_EXT, + AstcBlock::B8x6 => F::ASTC_8X6_SFLOAT_BLOCK_EXT, + AstcBlock::B8x8 => F::ASTC_8X8_SFLOAT_BLOCK_EXT, + AstcBlock::B10x5 => F::ASTC_10X5_SFLOAT_BLOCK_EXT, + AstcBlock::B10x6 => F::ASTC_10X6_SFLOAT_BLOCK_EXT, + AstcBlock::B10x8 => F::ASTC_10X8_SFLOAT_BLOCK_EXT, + AstcBlock::B10x10 => F::ASTC_10X10_SFLOAT_BLOCK_EXT, + AstcBlock::B12x10 => F::ASTC_12X10_SFLOAT_BLOCK_EXT, + AstcBlock::B12x12 => F::ASTC_12X12_SFLOAT_BLOCK_EXT, + }, + }, } } From 2f89242f32426c394d248bfede030507af38f3a2 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Fri, 1 Dec 2023 09:14:47 +0000 Subject: [PATCH 03/10] Initial implementation of D3D12 --- Cargo.toml | 8 +- src/graphics/d3d12.rs | 430 ++++++++++++++++++++++++++++++++++++++++++ src/graphics/mod.rs | 43 ++++- src/lib.rs | 28 +-- src/passthrough.rs | 18 +- src/resources.rs | 47 +++++ 6 files changed, 545 insertions(+), 29 deletions(-) create mode 100644 src/graphics/d3d12.rs diff --git a/Cargo.toml b/Cargo.toml index 847c1b6..6051a60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,10 @@ license = "MIT/Apache-2.0" [features] -default = [] +default = ["vulkan"] force-link = ["openxr/linked"] +vulkan = ["wgpu-core/vulkan"] +d3d12 = ["wgpu-core/dx12", "dep:winapi", "dep:d3d12"] [workspace] members = ["examples/android", "examples/demo"] @@ -20,9 +22,11 @@ ash = "0.37.3" bevy = "0.13" futures-lite = "2.0.1" mint = "0.5.9" +winapi = { version = "0.3.9", optional = true } wgpu = "0.19" -wgpu-core = { version = "0.19", features = ["vulkan"] } +wgpu-core = { version = "0.19" } wgpu-hal = "0.19" +d3d12 = { version = "0.19", features = ["libloading"], optional = true } eyre = "0.6.11" [target.'cfg(windows)'.dependencies] diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs new file mode 100644 index 0000000..64cd939 --- /dev/null +++ b/src/graphics/d3d12.rs @@ -0,0 +1,430 @@ +use std::ffi::{c_void, CString}; +use std::sync::atomic::AtomicBool; +use std::sync::{Arc, Mutex}; + +// use anyhow::Context; +use bevy::math::uvec2; +use bevy::prelude::*; +use bevy::render::renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; +use bevy::window::RawHandleWrapper; +use eyre::{Context, ContextCompat}; +use openxr as xr; +use wgpu::Instance; +use wgpu_hal::{api::Dx12, Api}; +use wgpu_hal::{Adapter as HalAdapter, Instance as HalInstance}; +use winapi::shared::dxgiformat::{self, DXGI_FORMAT}; +use winapi::um::{d3d12 as winapi_d3d12, d3dcommon}; +use xr::EnvironmentBlendMode; + +use crate::graphics::extensions::XrExtensions; +use crate::input::XrInput; + +use crate::resources::{ + OXrSessionSetupInfo, Swapchain, SwapchainInner, XrEnvironmentBlendMode, XrFormat, XrFrameState, + XrFrameWaiter, XrInstance, XrResolution, XrSession, XrSessionRunning, XrSwapchain, XrViews, +}; + +#[cfg(feature = "d3d12")] +use crate::resources::D3D12OXrSessionSetupInfo; +#[cfg(feature = "vulkan")] +use crate::resources::VulkanOXrSessionSetupInfo; + +use super::{XrAppInfo, XrPreferdBlendMode}; +use crate::VIEW_TYPE; + +pub fn initialize_xr_instance( + window: Option, + reqeusted_extensions: XrExtensions, + prefered_blend_mode: XrPreferdBlendMode, + app_info: XrAppInfo, +) -> eyre::Result<( + XrInstance, + OXrSessionSetupInfo, + XrEnvironmentBlendMode, + RenderDevice, + RenderQueue, + RenderAdapterInfo, + RenderAdapter, + Instance, +)> { + let xr_entry = super::xr_entry()?; + + #[cfg(target_os = "android")] + xr_entry.initialize_android_loader()?; + + let available_extensions: XrExtensions = xr_entry.enumerate_extensions()?.into(); + assert!(available_extensions.raw().khr_d3d12_enable); + //info!("available xr exts: {:#?}", available_extensions); + + let mut enabled_extensions: xr::ExtensionSet = + (available_extensions & reqeusted_extensions).into(); + enabled_extensions.khr_d3d12_enable = true; + + let available_layers = xr_entry.enumerate_layers()?; + //info!("available xr layers: {:#?}", available_layers); + + let xr_instance = xr_entry.create_instance( + &xr::ApplicationInfo { + application_name: &app_info.name, + engine_name: "Bevy", + ..Default::default() + }, + &enabled_extensions, + &[], + )?; + info!("created instance"); + let instance_props = xr_instance.properties()?; + let xr_system_id = xr_instance.system(xr::FormFactor::HEAD_MOUNTED_DISPLAY)?; + info!("created system"); + let system_props = xr_instance.system_properties(xr_system_id).unwrap(); + info!( + "loaded OpenXR runtime: {} {} {}", + instance_props.runtime_name, + instance_props.runtime_version, + if system_props.system_name.is_empty() { + "" + } else { + &system_props.system_name + } + ); + + let blend_modes = xr_instance.enumerate_environment_blend_modes(xr_system_id, VIEW_TYPE)?; + let blend_mode: EnvironmentBlendMode = match prefered_blend_mode { + XrPreferdBlendMode::Opaque if blend_modes.contains(&EnvironmentBlendMode::OPAQUE) => { + bevy::log::info!("Using Opaque"); + EnvironmentBlendMode::OPAQUE + } + XrPreferdBlendMode::Additive if blend_modes.contains(&EnvironmentBlendMode::ADDITIVE) => { + bevy::log::info!("Using Additive"); + EnvironmentBlendMode::ADDITIVE + } + XrPreferdBlendMode::AlphaBlend + if blend_modes.contains(&EnvironmentBlendMode::ALPHA_BLEND) => + { + bevy::log::info!("Using AlphaBlend"); + EnvironmentBlendMode::ALPHA_BLEND + } + _ => { + bevy::log::info!("Using Opaque"); + EnvironmentBlendMode::OPAQUE + } + }; + + // wgpu hardcodes this, so we'll hardcode it here too + let d3d_target_version: u32 = d3dcommon::D3D_FEATURE_LEVEL_11_0; + + let reqs = xr_instance.graphics_requirements::(xr_system_id)?; + if (d3d_target_version) < (reqs.min_feature_level as u32) { + panic!( + "OpenXR runtime requires D3D12 feature level >= {}", + reqs.min_feature_level + ); + } + let instance_descriptor = &wgpu_hal::InstanceDescriptor { + name: &app_info.name, + dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(), + flags: wgpu::InstanceFlags::from_build_config().with_env(), + gles_minor_version: Default::default(), + }; + let wgpu_raw_instance: wgpu_hal::dx12::Instance = + unsafe { wgpu_hal::dx12::Instance::init(instance_descriptor)? }; + let wgpu_adapters: Vec> = + unsafe { wgpu_raw_instance.enumerate_adapters() }; + let wgpu_exposed_adapter = wgpu_adapters + .into_iter() + .find(|a| { + let mut desc = unsafe { std::mem::zeroed() }; + unsafe { a.adapter.raw_adapter().GetDesc1(&mut desc) }; + desc.AdapterLuid.HighPart == reqs.adapter_luid.HighPart + && desc.AdapterLuid.LowPart == reqs.adapter_luid.LowPart + }) + .context("Failed to find DXGI adapter matching LUID provided by runtime")?; + + let wgpu_instance = + unsafe { wgpu::Instance::from_hal::(wgpu_raw_instance) }; + + let wgpu_features = wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES + | wgpu::Features::MULTIVIEW + | wgpu::Features::MULTI_DRAW_INDIRECT_COUNT + | wgpu::Features::MULTI_DRAW_INDIRECT; + + let wgpu_limits = wgpu::Limits { + max_bind_groups: 8, + max_storage_buffer_binding_size: wgpu_exposed_adapter + .capabilities + .limits + .max_storage_buffer_binding_size, + max_push_constant_size: 4, + ..Default::default() + }; + + let wgpu_open_device = unsafe { + wgpu_exposed_adapter + .adapter + .open(wgpu_features, &wgpu_limits)? + }; + + let wgpu_adapter = unsafe { wgpu_instance.create_adapter_from_hal(wgpu_exposed_adapter) }; + let raw_device = wgpu_open_device.device.raw_device().as_mut_ptr(); + let raw_queue = wgpu_open_device.device.raw_queue().as_mut_ptr(); + let (wgpu_device, wgpu_queue) = unsafe { + wgpu_adapter.create_device_from_hal( + wgpu_open_device, + &wgpu::DeviceDescriptor { + label: Some("bevy_oxr device"), + required_features: wgpu_features, + required_limits: wgpu_limits, + }, + None, + )? + }; + + Ok(( + xr_instance.into(), + OXrSessionSetupInfo::D3D12(D3D12OXrSessionSetupInfo { + raw_device, + raw_queue, + xr_system_id, + }), + blend_mode.into(), + wgpu_device.into(), + RenderQueue(wgpu_queue.into()), + RenderAdapterInfo(wgpu_adapter.get_info()), + RenderAdapter(wgpu_adapter.into()), + wgpu_instance.into(), + )) +} + +pub fn start_xr_session( + window: Option, + ptrs: &OXrSessionSetupInfo, + xr_instance: &XrInstance, + render_device: &RenderDevice, + render_adapter: &RenderAdapter, + wgpu_instance: &Instance, +) -> eyre::Result<( + XrSession, + XrResolution, + XrFormat, + XrSessionRunning, + XrFrameWaiter, + XrSwapchain, + XrInput, + XrViews, + XrFrameState, +)> { + let wgpu_device = render_device.wgpu_device(); + let wgpu_adapter = &render_adapter.0; + + #[allow(unreachable_patterns)] + let setup_info = match ptrs { + OXrSessionSetupInfo::D3D12(v) => v, + _ => eyre::bail!("Wrong Graphics Api"), + }; + let (session, frame_wait, frame_stream) = unsafe { + xr_instance.create_session::( + setup_info.xr_system_id, + &xr::d3d::SessionCreateInfoD3D12 { + device: setup_info.raw_device as *mut *mut c_void, + queue: setup_info.raw_queue as *mut *mut c_void, + }, + ) + }?; + + let views = + xr_instance.enumerate_view_configuration_views(setup_info.xr_system_id, VIEW_TYPE)?; + let surface = window.map(|wrapper| unsafe { + // SAFETY: Plugins should be set up on the main thread. + let handle = wrapper.get_handle(); + wgpu_instance + .create_surface(handle) + .expect("Failed to create wgpu surface") + }); + let swapchain_format = surface + .as_ref() + .map(|surface| surface.get_capabilities(wgpu_adapter).formats[0]) + .unwrap_or(wgpu::TextureFormat::Rgba8UnormSrgb); + + // TODO: Log swapchain format + + let resolution = uvec2( + views[0].recommended_image_rect_width, + views[0].recommended_image_rect_height, + ); + + let handle = session + .create_swapchain(&xr::SwapchainCreateInfo { + create_flags: xr::SwapchainCreateFlags::EMPTY, + usage_flags: xr::SwapchainUsageFlags::COLOR_ATTACHMENT + | xr::SwapchainUsageFlags::SAMPLED, + format: wgpu_to_d3d12(swapchain_format).expect("unsupported texture format"), + // The Vulkan graphics pipeline we create is not set up for multisampling, + // so we hardcode this to 1. If we used a proper multisampling setup, we + // could set this to `views[0].recommended_swapchain_sample_count`. + sample_count: 1, + width: resolution.x, + height: resolution.y, + face_count: 1, + array_size: 2, + mip_count: 1, + }) + .unwrap(); + + let images = handle.enumerate_images().unwrap(); + + let buffers = images + .into_iter() + .map(|color_image| { + info!("image map swapchain"); + let wgpu_hal_texture = unsafe { + ::Device::texture_from_raw( + d3d12::ComPtr::from_raw(color_image as *mut _), + swapchain_format, + wgpu::TextureDimension::D2, + wgpu::Extent3d { + width: resolution.x, + height: resolution.y, + depth_or_array_layers: 2, + }, + 1, + 1, + ) + }; + let texture = unsafe { + wgpu_device.create_texture_from_hal::( + wgpu_hal_texture, + &wgpu::TextureDescriptor { + label: Some("VR Swapchain"), + size: wgpu::Extent3d { + width: resolution.x, + height: resolution.y, + depth_or_array_layers: 2, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: swapchain_format, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT + | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }, + ) + }; + texture + }) + .collect(); + + Ok(( + XrSession::D3D12(session.clone()), + resolution.into(), + swapchain_format.into(), + // TODO: this shouldn't be in here + AtomicBool::new(false).into(), + frame_wait.into(), + Swapchain::D3D12(SwapchainInner { + stream: Mutex::new(frame_stream), + handle: Mutex::new(handle), + buffers, + image_index: Mutex::new(0), + }) + .into(), + XrInput::new(xr_instance, &session.into_any_graphics())?, + Vec::default().into(), + // TODO: Feels wrong to return a FrameState here, we probably should just wait for the next frame + xr::FrameState { + predicted_display_time: xr::Time::from_nanos(1), + predicted_display_period: xr::Duration::from_nanos(1), + should_render: true, + } + .into(), + )) +} + +fn wgpu_to_d3d12(format: wgpu::TextureFormat) -> Option { + // Copied wholesale from: + // https://github.com/gfx-rs/wgpu/blob/v0.19/wgpu-hal/src/auxil/dxgi/conv.rs#L12-L94 + // license: MIT OR Apache-2.0 + use wgpu::TextureFormat as Tf; + use winapi::shared::dxgiformat::*; + + Some(match format { + Tf::R8Unorm => DXGI_FORMAT_R8_UNORM, + Tf::R8Snorm => DXGI_FORMAT_R8_SNORM, + Tf::R8Uint => DXGI_FORMAT_R8_UINT, + Tf::R8Sint => DXGI_FORMAT_R8_SINT, + Tf::R16Uint => DXGI_FORMAT_R16_UINT, + Tf::R16Sint => DXGI_FORMAT_R16_SINT, + Tf::R16Unorm => DXGI_FORMAT_R16_UNORM, + Tf::R16Snorm => DXGI_FORMAT_R16_SNORM, + Tf::R16Float => DXGI_FORMAT_R16_FLOAT, + Tf::Rg8Unorm => DXGI_FORMAT_R8G8_UNORM, + Tf::Rg8Snorm => DXGI_FORMAT_R8G8_SNORM, + Tf::Rg8Uint => DXGI_FORMAT_R8G8_UINT, + Tf::Rg8Sint => DXGI_FORMAT_R8G8_SINT, + Tf::Rg16Unorm => DXGI_FORMAT_R16G16_UNORM, + Tf::Rg16Snorm => DXGI_FORMAT_R16G16_SNORM, + Tf::R32Uint => DXGI_FORMAT_R32_UINT, + Tf::R32Sint => DXGI_FORMAT_R32_SINT, + Tf::R32Float => DXGI_FORMAT_R32_FLOAT, + Tf::Rg16Uint => DXGI_FORMAT_R16G16_UINT, + Tf::Rg16Sint => DXGI_FORMAT_R16G16_SINT, + Tf::Rg16Float => DXGI_FORMAT_R16G16_FLOAT, + Tf::Rgba8Unorm => DXGI_FORMAT_R8G8B8A8_UNORM, + Tf::Rgba8UnormSrgb => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + Tf::Bgra8UnormSrgb => DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, + Tf::Rgba8Snorm => DXGI_FORMAT_R8G8B8A8_SNORM, + Tf::Bgra8Unorm => DXGI_FORMAT_B8G8R8A8_UNORM, + Tf::Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT, + Tf::Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT, + Tf::Rgb9e5Ufloat => DXGI_FORMAT_R9G9B9E5_SHAREDEXP, + Tf::Rgb10a2Uint => DXGI_FORMAT_R10G10B10A2_UINT, + Tf::Rgb10a2Unorm => DXGI_FORMAT_R10G10B10A2_UNORM, + Tf::Rg11b10Float => DXGI_FORMAT_R11G11B10_FLOAT, + Tf::Rg32Uint => DXGI_FORMAT_R32G32_UINT, + Tf::Rg32Sint => DXGI_FORMAT_R32G32_SINT, + Tf::Rg32Float => DXGI_FORMAT_R32G32_FLOAT, + Tf::Rgba16Uint => DXGI_FORMAT_R16G16B16A16_UINT, + Tf::Rgba16Sint => DXGI_FORMAT_R16G16B16A16_SINT, + Tf::Rgba16Unorm => DXGI_FORMAT_R16G16B16A16_UNORM, + Tf::Rgba16Snorm => DXGI_FORMAT_R16G16B16A16_SNORM, + Tf::Rgba16Float => DXGI_FORMAT_R16G16B16A16_FLOAT, + Tf::Rgba32Uint => DXGI_FORMAT_R32G32B32A32_UINT, + Tf::Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT, + Tf::Rgba32Float => DXGI_FORMAT_R32G32B32A32_FLOAT, + Tf::Stencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT, + Tf::Depth16Unorm => DXGI_FORMAT_D16_UNORM, + Tf::Depth24Plus => DXGI_FORMAT_D24_UNORM_S8_UINT, + Tf::Depth24PlusStencil8 => DXGI_FORMAT_D24_UNORM_S8_UINT, + Tf::Depth32Float => DXGI_FORMAT_D32_FLOAT, + Tf::Depth32FloatStencil8 => DXGI_FORMAT_D32_FLOAT_S8X24_UINT, + Tf::NV12 => DXGI_FORMAT_NV12, + Tf::Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM, + Tf::Bc1RgbaUnormSrgb => DXGI_FORMAT_BC1_UNORM_SRGB, + Tf::Bc2RgbaUnorm => DXGI_FORMAT_BC2_UNORM, + Tf::Bc2RgbaUnormSrgb => DXGI_FORMAT_BC2_UNORM_SRGB, + Tf::Bc3RgbaUnorm => DXGI_FORMAT_BC3_UNORM, + Tf::Bc3RgbaUnormSrgb => DXGI_FORMAT_BC3_UNORM_SRGB, + Tf::Bc4RUnorm => DXGI_FORMAT_BC4_UNORM, + Tf::Bc4RSnorm => DXGI_FORMAT_BC4_SNORM, + Tf::Bc5RgUnorm => DXGI_FORMAT_BC5_UNORM, + Tf::Bc5RgSnorm => DXGI_FORMAT_BC5_SNORM, + Tf::Bc6hRgbUfloat => DXGI_FORMAT_BC6H_UF16, + Tf::Bc6hRgbFloat => DXGI_FORMAT_BC6H_SF16, + Tf::Bc7RgbaUnorm => DXGI_FORMAT_BC7_UNORM, + Tf::Bc7RgbaUnormSrgb => DXGI_FORMAT_BC7_UNORM_SRGB, + Tf::Etc2Rgb8Unorm + | Tf::Etc2Rgb8UnormSrgb + | Tf::Etc2Rgb8A1Unorm + | Tf::Etc2Rgb8A1UnormSrgb + | Tf::Etc2Rgba8Unorm + | Tf::Etc2Rgba8UnormSrgb + | Tf::EacR11Unorm + | Tf::EacR11Snorm + | Tf::EacRg11Unorm + | Tf::EacRg11Snorm + | Tf::Astc { + block: _, + channel: _, + } => return None, + }) +} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 147fa1c..4256cfb 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,4 +1,8 @@ pub mod extensions; + +#[cfg(feature = "d3d12")] +mod d3d12; +#[cfg(feature = "vulkan")] mod vulkan; use bevy::ecs::query::With; @@ -63,14 +67,28 @@ pub fn start_xr_session( XrViews, XrFrameState, )> { - vulkan::start_xr_session( - window, - session_setup_data, - xr_instance, - render_device, - render_adapter, - wgpu_instance, - ) + #[cfg(feature = "vulkan")] + { + vulkan::start_xr_session( + window, + session_setup_data, + xr_instance, + render_device, + render_adapter, + wgpu_instance, + ) + } + #[cfg(feature = "d3d12")] + { + d3d12::start_xr_session( + window, + session_setup_data, + xr_instance, + render_device, + render_adapter, + wgpu_instance, + ) + } } pub fn initialize_xr_instance( window: Option, @@ -87,7 +105,14 @@ pub fn initialize_xr_instance( RenderAdapter, Instance, )> { - vulkan::initialize_xr_instance(window, reqeusted_extensions, prefered_blend_mode, app_info) + #[cfg(feature = "vulkan")] + { + vulkan::initialize_xr_instance(window, reqeusted_extensions, prefered_blend_mode, app_info) + } + #[cfg(feature = "d3d12")] + { + d3d12::initialize_xr_instance(window, reqeusted_extensions, prefered_blend_mode, app_info) + } } pub fn try_full_init( diff --git a/src/lib.rs b/src/lib.rs index ca7f0a2..b1c6122 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,19 +212,21 @@ fn xr_skip_frame( environment_blend_mode: Res, ) { let swapchain: &Swapchain = &xr_swapchain; - match swapchain { - Swapchain::Vulkan(swap) => { - swap.stream - .lock() - .unwrap() - .end( - xr_frame_state.predicted_display_time, - **environment_blend_mode, - &[], - ) - .unwrap(); - } - } + let stream = match swapchain { + #[cfg(feature = "vulkan")] + Swapchain::Vulkan(swap) => &swap.stream, + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swap) => &swap.stream, + }; + stream + .lock() + .unwrap() + .end( + xr_frame_state.predicted_display_time, + **environment_blend_mode, + &[], + ) + .unwrap(); } pub struct DefaultXrPlugins { diff --git a/src/passthrough.rs b/src/passthrough.rs index e6eb1e5..58d0205 100644 --- a/src/passthrough.rs +++ b/src/passthrough.rs @@ -195,17 +195,25 @@ pub fn supports_passthrough(instance: &XrInstance, system: xr::SystemId) -> xr:: pub fn create_passthrough( xr_session: &XrSession, ) -> xr::Result<(xr::Passthrough, xr::PassthroughLayer)> { + let flags = xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION; + let purpose = xr::PassthroughLayerPurposeFB::RECONSTRUCTION; let passthrough = match xr_session { + #[cfg(feature = "vulkan")] XrSession::Vulkan(session) => { session.create_passthrough(xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION) } + #[cfg(feature = "d3d12")] + XrSession::D3D12(session) => { + session.create_passthrough(xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION) + } }?; let passthrough_layer = match xr_session { - XrSession::Vulkan(session) => session.create_passthrough_layer( - &passthrough, - xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION, - xr::PassthroughLayerPurposeFB::RECONSTRUCTION, - ), + #[cfg(feature = "vulkan")] + XrSession::Vulkan(session) => { + session.create_passthrough_layer(&passthrough, flags, purpose) + } + #[cfg(feature = "d3d12")] + XrSession::D3D12(session) => session.create_passthrough_layer(&passthrough, flags, purpose), }?; Ok((passthrough, passthrough_layer)) } diff --git a/src/resources.rs b/src/resources.rs index 1dd64ad..d005dca 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -14,6 +14,8 @@ use bevy::render::extract_component::ExtractComponent; use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; use core::ptr; use openxr as xr; +#[cfg(feature = "d3d12")] +use winapi::um::d3d12::{ID3D12CommandQueue, ID3D12Device}; xr_resource_wrapper!(XrInstance, xr::Instance); xr_resource_wrapper_copy!(XrEnvironmentBlendMode, xr::EnvironmentBlendMode); @@ -27,7 +29,10 @@ xr_no_clone_resource_wrapper!(XrFrameWaiter, xr::FrameWaiter); #[derive(Clone, Resource, ExtractResource)] pub enum XrSession { + #[cfg(feature = "vulkan")] Vulkan(xr::Session), + #[cfg(feature = "d3d12")] + D3D12(xr::Session), } impl std::ops::Deref for XrSession { @@ -37,12 +42,16 @@ impl std::ops::Deref for XrSession { // SAFTEY: should be fine i think -Schmarni unsafe { match self { + #[cfg(feature = "vulkan")] XrSession::Vulkan(sess) => std::mem::transmute(sess), + #[cfg(feature = "d3d12")] + XrSession::D3D12(sess) => std::mem::transmute(sess), } } } } +#[cfg(feature = "vulkan")] pub struct VulkanOXrSessionSetupInfo { pub(crate) device_ptr: *const c_void, pub(crate) physical_device_ptr: *const c_void, @@ -51,8 +60,18 @@ pub struct VulkanOXrSessionSetupInfo { pub(crate) xr_system_id: xr::SystemId, } +#[cfg(feature = "d3d12")] +pub struct D3D12OXrSessionSetupInfo { + pub(crate) raw_device: *mut ID3D12Device, + pub(crate) raw_queue: *mut ID3D12CommandQueue, + pub(crate) xr_system_id: xr::SystemId, +} + pub enum OXrSessionSetupInfo { + #[cfg(feature = "vulkan")] Vulkan(VulkanOXrSessionSetupInfo), + #[cfg(feature = "d3d12")] + D3D12(D3D12OXrSessionSetupInfo), } pub struct XrResourcePlugin; @@ -72,37 +91,55 @@ impl Plugin for XrResourcePlugin { } pub enum Swapchain { + #[cfg(feature = "vulkan")] Vulkan(SwapchainInner), + #[cfg(feature = "d3d12")] + D3D12(SwapchainInner), } impl Swapchain { pub(crate) fn begin(&self) -> xr::Result<()> { match self { + #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.begin(), + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swapchain) => swapchain.begin(), } } pub(crate) fn get_render_views(&self) -> (wgpu::TextureView, wgpu::TextureView) { match self { + #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.get_render_views(), + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swapchain) => swapchain.get_render_views(), } } pub(crate) fn acquire_image(&self) -> xr::Result<()> { match self { + #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.acquire_image(), + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swapchain) => swapchain.acquire_image(), } } pub(crate) fn wait_image(&self) -> xr::Result<()> { match self { + #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.wait_image(), + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swapchain) => swapchain.wait_image(), } } pub(crate) fn release_image(&self) -> xr::Result<()> { match self { + #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.release_image(), + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swapchain) => swapchain.release_image(), } } @@ -116,6 +153,7 @@ impl Swapchain { passthrough_layer: Option<&XrPassthroughLayer>, ) -> xr::Result<()> { match self { + #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.end( predicted_display_time, views, @@ -124,6 +162,15 @@ impl Swapchain { environment_blend_mode, passthrough_layer, ), + #[cfg(feature = "d3d12")] + Swapchain::D3D12(swapchain) => swapchain.end( + predicted_display_time, + views, + stage, + resolution, + environment_blend_mode, + passthrough_layer, + ), } } } From a4397a5fbbd9d432103f887a38f6eed579247bae Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Sun, 10 Dec 2023 00:11:39 +0000 Subject: [PATCH 04/10] Replace as with .cast() --- src/graphics/d3d12.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs index 64cd939..b696af4 100644 --- a/src/graphics/d3d12.rs +++ b/src/graphics/d3d12.rs @@ -1,4 +1,3 @@ -use std::ffi::{c_void, CString}; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex}; @@ -225,8 +224,8 @@ pub fn start_xr_session( xr_instance.create_session::( setup_info.xr_system_id, &xr::d3d::SessionCreateInfoD3D12 { - device: setup_info.raw_device as *mut *mut c_void, - queue: setup_info.raw_queue as *mut *mut c_void, + device: setup_info.raw_device.cast(), + queue: setup_info.raw_queue.cast(), }, ) }?; From ff4ff6472aa3c1193e5a7e0e1fa5bbb17a99a5e5 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Fri, 1 Dec 2023 12:03:02 +0000 Subject: [PATCH 05/10] Add runtime backend selection --- src/graphics/d3d12.rs | 5 ++-- src/graphics/mod.rs | 55 +++++++++++++++++++++++++++++++++++++----- src/graphics/vulkan.rs | 5 ++-- src/lib.rs | 18 ++++++++++++++ 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs index b696af4..e162197 100644 --- a/src/graphics/d3d12.rs +++ b/src/graphics/d3d12.rs @@ -33,7 +33,9 @@ use crate::VIEW_TYPE; pub fn initialize_xr_instance( window: Option, + xr_entry: xr::Entry, reqeusted_extensions: XrExtensions, + available_extensions: XrExtensions, prefered_blend_mode: XrPreferdBlendMode, app_info: XrAppInfo, ) -> eyre::Result<( @@ -46,12 +48,9 @@ pub fn initialize_xr_instance( RenderAdapter, Instance, )> { - let xr_entry = super::xr_entry()?; - #[cfg(target_os = "android")] xr_entry.initialize_android_loader()?; - let available_extensions: XrExtensions = xr_entry.enumerate_extensions()?.into(); assert!(available_extensions.raw().khr_d3d12_enable); //info!("available xr exts: {:#?}", available_extensions); diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 4256cfb..67bff10 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -21,6 +21,8 @@ use crate::resources::{ }; use crate::OXrSessionSetupInfo; +use crate::Backend; + use openxr as xr; use self::extensions::XrExtensions; @@ -91,6 +93,7 @@ pub fn start_xr_session( } } pub fn initialize_xr_instance( + backend_preference: &[Backend], window: Option, reqeusted_extensions: XrExtensions, prefered_blend_mode: XrPreferdBlendMode, @@ -105,18 +108,57 @@ pub fn initialize_xr_instance( RenderAdapter, Instance, )> { - #[cfg(feature = "vulkan")] - { - vulkan::initialize_xr_instance(window, reqeusted_extensions, prefered_blend_mode, app_info) + if backend_preference.is_empty() { + eyre::bail!("Cannot initialize with no backend selected"); } - #[cfg(feature = "d3d12")] - { - d3d12::initialize_xr_instance(window, reqeusted_extensions, prefered_blend_mode, app_info) + let xr_entry = xr_entry()?; + + #[cfg(target_os = "android")] + xr_entry.initialize_android_loader()?; + + let available_extensions: XrExtensions = xr_entry.enumerate_extensions()?.into(); + + for backend in backend_preference { + match backend { + #[cfg(feature = "vulkan")] + Backend::Vulkan => { + if !available_extensions.raw().khr_vulkan_enable2 { + continue; + } + return vulkan::initialize_xr_instance( + window, + xr_entry, + reqeusted_extensions, + available_extensions, + prefered_blend_mode, + app_info, + ); + } + #[cfg(feature = "d3d12")] + Backend::D3D12 => { + if !available_extensions.raw().khr_d3d12_enable { + continue; + } + return d3d12::initialize_xr_instance( + window, + xr_entry, + reqeusted_extensions, + available_extensions, + prefered_blend_mode, + app_info, + ); + } + } } + eyre::bail!( + "No selected backend was supported by the runtime. Selected: {:?}", + backend_preference + ); } pub fn try_full_init( world: &mut World, + backend_preference: &[Backend], reqeusted_extensions: XrExtensions, prefered_blend_mode: XrPreferdBlendMode, app_info: XrAppInfo, @@ -140,6 +182,7 @@ pub fn try_full_init( render_adapter, wgpu_instance, ) = initialize_xr_instance( + backend_preference, primary_window.clone(), reqeusted_extensions, prefered_blend_mode, diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index 6a5379d..72c5d00 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -28,7 +28,9 @@ use super::{XrAppInfo, XrPreferdBlendMode}; pub fn initialize_xr_instance( window: Option, + xr_entry: xr::Entry, reqeusted_extensions: XrExtensions, + available_extensions: XrExtensions, prefered_blend_mode: XrPreferdBlendMode, app_info: XrAppInfo, ) -> eyre::Result<( @@ -41,12 +43,9 @@ pub fn initialize_xr_instance( RenderAdapter, Instance, )> { - let xr_entry = super::xr_entry()?; - #[cfg(target_os = "android")] xr_entry.initialize_android_loader()?; - let available_extensions: XrExtensions = xr_entry.enumerate_extensions()?.into(); assert!(available_extensions.raw().khr_vulkan_enable2); //info!("available xr exts: {:#?}", available_extensions); diff --git a/src/lib.rs b/src/lib.rs index b1c6122..80e2bff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ pub const RIGHT_XR_TEXTURE_HANDLE: ManualTextureViewHandle = ManualTextureViewHa /// Adds OpenXR support to an App pub struct OpenXrPlugin { + pub backend_preference: Vec, pub reqeusted_extensions: XrExtensions, pub prefered_blend_mode: XrPreferdBlendMode, pub app_info: XrAppInfo, @@ -59,6 +60,7 @@ impl Plugin for OpenXrPlugin { app.insert_resource(ExitAppOnSessionExit::default()); #[cfg(not(target_arch = "wasm32"))] match graphics::initialize_xr_instance( + &self.backend_preference, SystemState::>>::new(&mut app.world) .get(&app.world) .get_single() @@ -169,6 +171,14 @@ impl Plugin for OpenXrPlugin { } } +#[derive(Debug)] +pub enum Backend { + #[cfg(feature = "vulkan")] + Vulkan, + #[cfg(feature = "d3d12")] + D3D12, +} + #[derive(Resource)] struct DoPipelinedRendering; @@ -230,6 +240,7 @@ fn xr_skip_frame( } pub struct DefaultXrPlugins { + pub backend_preference: Vec, pub reqeusted_extensions: XrExtensions, pub prefered_blend_mode: XrPreferdBlendMode, pub app_info: XrAppInfo, @@ -238,6 +249,12 @@ pub struct DefaultXrPlugins { impl Default for DefaultXrPlugins { fn default() -> Self { Self { + backend_preference: vec![ + #[cfg(feature = "vulkan")] + Backend::Vulkan, + #[cfg(feature = "d3d12")] + Backend::D3D12, + ], reqeusted_extensions: default(), prefered_blend_mode: default(), app_info: default(), @@ -263,6 +280,7 @@ impl PluginGroup for DefaultXrPlugins { }) .disable::() .add_before::(OpenXrPlugin { + backend_preference: self.backend_preference, prefered_blend_mode: self.prefered_blend_mode, reqeusted_extensions: self.reqeusted_extensions, app_info: self.app_info.clone(), From 8e0837b8ca16b003b67f7955c8a267f048aaa992 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Fri, 1 Dec 2023 12:10:00 +0000 Subject: [PATCH 06/10] Make d3d12 build by default if possible --- Cargo.toml | 7 ++++--- src/graphics/d3d12.rs | 2 +- src/graphics/mod.rs | 20 +++++++++----------- src/lib.rs | 39 ++++++++++++++++++++++++--------------- src/passthrough.rs | 4 ++-- src/resources.rs | 24 ++++++++++++------------ 6 files changed, 52 insertions(+), 44 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6051a60..1eacc55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT/Apache-2.0" [features] -default = ["vulkan"] +default = ["vulkan", "d3d12"] force-link = ["openxr/linked"] vulkan = ["wgpu-core/vulkan"] d3d12 = ["wgpu-core/dx12", "dep:winapi", "dep:d3d12"] @@ -22,11 +22,9 @@ ash = "0.37.3" bevy = "0.13" futures-lite = "2.0.1" mint = "0.5.9" -winapi = { version = "0.3.9", optional = true } wgpu = "0.19" wgpu-core = { version = "0.19" } wgpu-hal = "0.19" -d3d12 = { version = "0.19", features = ["libloading"], optional = true } eyre = "0.6.11" [target.'cfg(windows)'.dependencies] @@ -35,6 +33,9 @@ openxr = { git = "https://github.com/Ralith/openxrs", rev = "0177d2d", features "static", "mint", ] } +winapi = { version = "0.3.9", optional = true } +d3d12 = { version = "0.19", features = ["libloading"], optional = true } + [target.'cfg(all(target_family = "unix", not(target_arch = "wasm32")) )'.dependencies] openxr = { git = "https://github.com/Ralith/openxrs", rev = "0177d2d", features = [ "mint", diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs index e162197..2340e15 100644 --- a/src/graphics/d3d12.rs +++ b/src/graphics/d3d12.rs @@ -23,7 +23,7 @@ use crate::resources::{ XrFrameWaiter, XrInstance, XrResolution, XrSession, XrSessionRunning, XrSwapchain, XrViews, }; -#[cfg(feature = "d3d12")] +#[cfg(all(feature = "d3d12", windows))] use crate::resources::D3D12OXrSessionSetupInfo; #[cfg(feature = "vulkan")] use crate::resources::VulkanOXrSessionSetupInfo; diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 67bff10..c897604 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,6 +1,6 @@ pub mod extensions; -#[cfg(feature = "d3d12")] +#[cfg(all(feature = "d3d12", windows))] mod d3d12; #[cfg(feature = "vulkan")] mod vulkan; @@ -69,27 +69,25 @@ pub fn start_xr_session( XrViews, XrFrameState, )> { - #[cfg(feature = "vulkan")] - { - vulkan::start_xr_session( + match session_setup_data { + #[cfg(feature = "vulkan")] + OXrSessionSetupInfo::Vulkan(_) => vulkan::start_xr_session( window, session_setup_data, xr_instance, render_device, render_adapter, wgpu_instance, - ) - } - #[cfg(feature = "d3d12")] - { - d3d12::start_xr_session( + ), + #[cfg(all(feature = "d3d12", windows))] + OXrSessionSetupInfo::D3D12(_) => d3d12::start_xr_session( window, session_setup_data, xr_instance, render_device, render_adapter, wgpu_instance, - ) + ), } } pub fn initialize_xr_instance( @@ -134,7 +132,7 @@ pub fn initialize_xr_instance( app_info, ); } - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Backend::D3D12 => { if !available_extensions.raw().khr_d3d12_enable { continue; diff --git a/src/lib.rs b/src/lib.rs index 80e2bff..fe1b93a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,7 +175,7 @@ impl Plugin for OpenXrPlugin { pub enum Backend { #[cfg(feature = "vulkan")] Vulkan, - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] D3D12, } @@ -222,21 +222,30 @@ fn xr_skip_frame( environment_blend_mode: Res, ) { let swapchain: &Swapchain = &xr_swapchain; - let stream = match swapchain { + match swapchain { #[cfg(feature = "vulkan")] - Swapchain::Vulkan(swap) => &swap.stream, - #[cfg(feature = "d3d12")] - Swapchain::D3D12(swap) => &swap.stream, + Swapchain::Vulkan(swap) => &swap + .stream + .lock() + .unwrap() + .end( + xr_frame_state.predicted_display_time, + **environment_blend_mode, + &[], + ) + .unwrap(), + #[cfg(all(feature = "d3d12", windows))] + Swapchain::D3D12(swap) => &swap + .stream + .lock() + .unwrap() + .end( + xr_frame_state.predicted_display_time, + **environment_blend_mode, + &[], + ) + .unwrap(), }; - stream - .lock() - .unwrap() - .end( - xr_frame_state.predicted_display_time, - **environment_blend_mode, - &[], - ) - .unwrap(); } pub struct DefaultXrPlugins { @@ -252,7 +261,7 @@ impl Default for DefaultXrPlugins { backend_preference: vec![ #[cfg(feature = "vulkan")] Backend::Vulkan, - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Backend::D3D12, ], reqeusted_extensions: default(), diff --git a/src/passthrough.rs b/src/passthrough.rs index 58d0205..c6d67c8 100644 --- a/src/passthrough.rs +++ b/src/passthrough.rs @@ -202,7 +202,7 @@ pub fn create_passthrough( XrSession::Vulkan(session) => { session.create_passthrough(xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION) } - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] XrSession::D3D12(session) => { session.create_passthrough(xr::PassthroughFlagsFB::IS_RUNNING_AT_CREATION) } @@ -212,7 +212,7 @@ pub fn create_passthrough( XrSession::Vulkan(session) => { session.create_passthrough_layer(&passthrough, flags, purpose) } - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] XrSession::D3D12(session) => session.create_passthrough_layer(&passthrough, flags, purpose), }?; Ok((passthrough, passthrough_layer)) diff --git a/src/resources.rs b/src/resources.rs index d005dca..1f1e2f9 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -14,7 +14,7 @@ use bevy::render::extract_component::ExtractComponent; use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; use core::ptr; use openxr as xr; -#[cfg(feature = "d3d12")] +#[cfg(all(feature = "d3d12", windows))] use winapi::um::d3d12::{ID3D12CommandQueue, ID3D12Device}; xr_resource_wrapper!(XrInstance, xr::Instance); @@ -31,7 +31,7 @@ xr_no_clone_resource_wrapper!(XrFrameWaiter, xr::FrameWaiter); pub enum XrSession { #[cfg(feature = "vulkan")] Vulkan(xr::Session), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] D3D12(xr::Session), } @@ -44,7 +44,7 @@ impl std::ops::Deref for XrSession { match self { #[cfg(feature = "vulkan")] XrSession::Vulkan(sess) => std::mem::transmute(sess), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] XrSession::D3D12(sess) => std::mem::transmute(sess), } } @@ -60,7 +60,7 @@ pub struct VulkanOXrSessionSetupInfo { pub(crate) xr_system_id: xr::SystemId, } -#[cfg(feature = "d3d12")] +#[cfg(all(feature = "d3d12", windows))] pub struct D3D12OXrSessionSetupInfo { pub(crate) raw_device: *mut ID3D12Device, pub(crate) raw_queue: *mut ID3D12CommandQueue, @@ -70,7 +70,7 @@ pub struct D3D12OXrSessionSetupInfo { pub enum OXrSessionSetupInfo { #[cfg(feature = "vulkan")] Vulkan(VulkanOXrSessionSetupInfo), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] D3D12(D3D12OXrSessionSetupInfo), } @@ -93,7 +93,7 @@ impl Plugin for XrResourcePlugin { pub enum Swapchain { #[cfg(feature = "vulkan")] Vulkan(SwapchainInner), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] D3D12(SwapchainInner), } @@ -102,7 +102,7 @@ impl Swapchain { match self { #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.begin(), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Swapchain::D3D12(swapchain) => swapchain.begin(), } } @@ -111,7 +111,7 @@ impl Swapchain { match self { #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.get_render_views(), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Swapchain::D3D12(swapchain) => swapchain.get_render_views(), } } @@ -120,7 +120,7 @@ impl Swapchain { match self { #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.acquire_image(), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Swapchain::D3D12(swapchain) => swapchain.acquire_image(), } } @@ -129,7 +129,7 @@ impl Swapchain { match self { #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.wait_image(), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Swapchain::D3D12(swapchain) => swapchain.wait_image(), } } @@ -138,7 +138,7 @@ impl Swapchain { match self { #[cfg(feature = "vulkan")] Swapchain::Vulkan(swapchain) => swapchain.release_image(), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Swapchain::D3D12(swapchain) => swapchain.release_image(), } } @@ -162,7 +162,7 @@ impl Swapchain { environment_blend_mode, passthrough_layer, ), - #[cfg(feature = "d3d12")] + #[cfg(all(feature = "d3d12", windows))] Swapchain::D3D12(swapchain) => swapchain.end( predicted_display_time, views, From faa0f699e255695bcaa4a8c129b56e07fad4197f Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Sun, 10 Dec 2023 00:06:19 +0000 Subject: [PATCH 07/10] Log message consistency --- src/graphics/d3d12.rs | 10 +++++----- src/graphics/vulkan.rs | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs index 2340e15..9b21e6b 100644 --- a/src/graphics/d3d12.rs +++ b/src/graphics/d3d12.rs @@ -70,10 +70,10 @@ pub fn initialize_xr_instance( &enabled_extensions, &[], )?; - info!("created instance"); + info!("created OpenXR instance"); let instance_props = xr_instance.properties()?; let xr_system_id = xr_instance.system(xr::FormFactor::HEAD_MOUNTED_DISPLAY)?; - info!("created system"); + info!("created OpenXR system"); let system_props = xr_instance.system_properties(xr_system_id).unwrap(); info!( "loaded OpenXR runtime: {} {} {}", @@ -136,7 +136,7 @@ pub fn initialize_xr_instance( desc.AdapterLuid.HighPart == reqs.adapter_luid.HighPart && desc.AdapterLuid.LowPart == reqs.adapter_luid.LowPart }) - .context("Failed to find DXGI adapter matching LUID provided by runtime")?; + .context("failed to find DXGI adapter matching LUID provided by runtime")?; let wgpu_instance = unsafe { wgpu::Instance::from_hal::(wgpu_raw_instance) }; @@ -255,7 +255,7 @@ pub fn start_xr_session( create_flags: xr::SwapchainCreateFlags::EMPTY, usage_flags: xr::SwapchainUsageFlags::COLOR_ATTACHMENT | xr::SwapchainUsageFlags::SAMPLED, - format: wgpu_to_d3d12(swapchain_format).expect("unsupported texture format"), + format: wgpu_to_d3d12(swapchain_format).expect("Unsupported texture format"), // The Vulkan graphics pipeline we create is not set up for multisampling, // so we hardcode this to 1. If we used a proper multisampling setup, we // could set this to `views[0].recommended_swapchain_sample_count`. @@ -292,7 +292,7 @@ pub fn start_xr_session( wgpu_device.create_texture_from_hal::( wgpu_hal_texture, &wgpu::TextureDescriptor { - label: Some("VR Swapchain"), + label: Some("bevy_openxr swapchain"), size: wgpu::Extent3d { width: resolution.x, height: resolution.y, diff --git a/src/graphics/vulkan.rs b/src/graphics/vulkan.rs index 72c5d00..441cc1d 100644 --- a/src/graphics/vulkan.rs +++ b/src/graphics/vulkan.rs @@ -47,7 +47,7 @@ pub fn initialize_xr_instance( xr_entry.initialize_android_loader()?; assert!(available_extensions.raw().khr_vulkan_enable2); - //info!("available xr exts: {:#?}", available_extensions); + // info!("available OpenXR extensions: {:#?}", available_extensions); let mut enabled_extensions: xr::ExtensionSet = (available_extensions & reqeusted_extensions).into(); @@ -58,7 +58,7 @@ pub fn initialize_xr_instance( } let available_layers = xr_entry.enumerate_layers()?; - //info!("available xr layers: {:#?}", available_layers); + // info!("available OpenXR layers: {:#?}", available_layers); let xr_instance = xr_entry.create_instance( &xr::ApplicationInfo { @@ -69,10 +69,10 @@ pub fn initialize_xr_instance( &enabled_extensions, &[], )?; - info!("created instance"); + info!("created OpenXR instance"); let instance_props = xr_instance.properties()?; let xr_system_id = xr_instance.system(xr::FormFactor::HEAD_MOUNTED_DISPLAY)?; - info!("created system"); + info!("created OpenXR system"); let system_props = xr_instance.system_properties(xr_system_id).unwrap(); info!( "loaded OpenXR runtime: {} {} {}", @@ -138,7 +138,7 @@ pub fn initialize_xr_instance( ash::extensions::khr::TimelineSemaphore::name(), ]; info!( - "creating vulkan instance with these extensions: {:#?}", + "creating Vulkan instance with these extensions: {:#?}", extensions ); @@ -162,7 +162,7 @@ pub fn initialize_xr_instance( .enabled_extension_names(&extensions_cchar) as *const _ as *const _, ) - .context("XR error creating Vulkan instance") + .context("OpenXR error creating Vulkan instance") .unwrap() .map_err(vk::Result::from_raw) .context("Vulkan error creating Vulkan instance") @@ -173,7 +173,7 @@ pub fn initialize_xr_instance( vk::Instance::from_raw(vk_instance as _), ) }; - info!("created vulkan instance"); + info!("created Vulkan instance"); let vk_instance_ptr = vk_instance.handle().as_raw() as *const c_void; @@ -246,7 +246,7 @@ pub fn initialize_xr_instance( vk_physical_device.as_raw() as _, &info as *const _ as *const _, ) - .context("XR error creating Vulkan device")? + .context("OpenXR error creating Vulkan device")? .map_err(vk::Result::from_raw) .context("Vulkan error creating Vulkan device")?; @@ -400,7 +400,7 @@ pub fn start_xr_session( ::Device::texture_from_raw( color_image, &wgpu_hal::TextureDescriptor { - label: Some("VR Swapchain"), + label: Some("bevy_openxr swapchain"), // unused internally size: wgpu::Extent3d { width: resolution.x, height: resolution.y, @@ -422,7 +422,7 @@ pub fn start_xr_session( wgpu_device.create_texture_from_hal::( wgpu_hal_texture, &wgpu::TextureDescriptor { - label: Some("VR Swapchain"), + label: Some("bevy_openxr swapchain"), size: wgpu::Extent3d { width: resolution.x, height: resolution.y, From 7502fc16ea800fad1a1dcb15ca73f7c182e66275 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Sun, 10 Dec 2023 02:11:11 +0000 Subject: [PATCH 08/10] Add error if no backend is enabled --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index fe1b93a..e35d09e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,6 +171,9 @@ impl Plugin for OpenXrPlugin { } } +#[cfg(all(not(feature = "vulkan"), not(all(feature = "d3d12", windows))))] +compile_error!("At least one platform-compatible backend feature must be enabled."); + #[derive(Debug)] pub enum Backend { #[cfg(feature = "vulkan")] From 91a4f2a544cd66889aa046ce4cf04daef4baff46 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Sun, 10 Dec 2023 02:57:03 +0000 Subject: [PATCH 09/10] Dynamically detect D3D12 feature level --- src/graphics/d3d12.rs | 59 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs index 9b21e6b..8970e40 100644 --- a/src/graphics/d3d12.rs +++ b/src/graphics/d3d12.rs @@ -108,16 +108,8 @@ pub fn initialize_xr_instance( } }; - // wgpu hardcodes this, so we'll hardcode it here too - let d3d_target_version: u32 = d3dcommon::D3D_FEATURE_LEVEL_11_0; - let reqs = xr_instance.graphics_requirements::(xr_system_id)?; - if (d3d_target_version) < (reqs.min_feature_level as u32) { - panic!( - "OpenXR runtime requires D3D12 feature level >= {}", - reqs.min_feature_level - ); - } + let instance_descriptor = &wgpu_hal::InstanceDescriptor { name: &app_info.name, dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(), @@ -162,6 +154,26 @@ pub fn initialize_xr_instance( .open(wgpu_features, &wgpu_limits)? }; + let device_supported_feature_level: d3d12::FeatureLevel = + get_device_feature_level(wgpu_open_device.device.raw_device()); + + if (device_supported_feature_level as u32) < (reqs.min_feature_level as u32) { + panic!( + "OpenXR runtime requires D3D12 feature level >= {}", + reqs.min_feature_level + ); + } + + let (session, frame_wait, frame_stream) = unsafe { + xr_instance.create_session::( + xr_system_id, + &xr::d3d::SessionCreateInfoD3D12 { + device: wgpu_open_device.device.raw_device().as_mut_ptr().cast(), + queue: wgpu_open_device.device.raw_queue().as_mut_ptr().cast(), + }, + ) + }?; + let wgpu_adapter = unsafe { wgpu_instance.create_adapter_from_hal(wgpu_exposed_adapter) }; let raw_device = wgpu_open_device.device.raw_device().as_mut_ptr(); let raw_queue = wgpu_open_device.device.raw_queue().as_mut_ptr(); @@ -338,6 +350,35 @@ pub fn start_xr_session( )) } +// Extracted from https://github.com/gfx-rs/wgpu/blob/1161a22f4fbb4fc204eb06f2ac4243f83e0e980d/wgpu-hal/src/dx12/adapter.rs#L73-L94 +// license: MIT OR Apache-2.0 +fn get_device_feature_level( + device: &d3d12::ComPtr, +) -> d3d12::FeatureLevel { + // Detect the highest supported feature level. + let d3d_feature_level = [ + d3d12::FeatureLevel::L12_1, + d3d12::FeatureLevel::L12_0, + d3d12::FeatureLevel::L11_1, + d3d12::FeatureLevel::L11_0, + ]; + type FeatureLevelsInfo = winapi_d3d12::D3D12_FEATURE_DATA_FEATURE_LEVELS; + let mut device_levels: FeatureLevelsInfo = unsafe { std::mem::zeroed() }; + device_levels.NumFeatureLevels = d3d_feature_level.len() as u32; + device_levels.pFeatureLevelsRequested = d3d_feature_level.as_ptr().cast(); + unsafe { + device.CheckFeatureSupport( + winapi_d3d12::D3D12_FEATURE_FEATURE_LEVELS, + (&mut device_levels as *mut FeatureLevelsInfo).cast(), + std::mem::size_of::() as _, + ) + }; + // This cast should never fail because we only requested feature levels that are already in the enum. + let max_feature_level = d3d12::FeatureLevel::try_from(device_levels.MaxSupportedFeatureLevel) + .expect("Unexpected feature level"); + max_feature_level +} + fn wgpu_to_d3d12(format: wgpu::TextureFormat) -> Option { // Copied wholesale from: // https://github.com/gfx-rs/wgpu/blob/v0.19/wgpu-hal/src/auxil/dxgi/conv.rs#L12-L94 From 59ce1f52d1249548040d9afb48e91e883c2da2d0 Mon Sep 17 00:00:00 2001 From: Charlton Rodda Date: Tue, 12 Dec 2023 17:03:41 +0000 Subject: [PATCH 10/10] Default to dxc compiler because fxc is too slow This does require dxil.dll and dxcompiler.dll to be available, falling back to fxc if these cannot be found. Can be overridden by setting the WGPU_DX12_COMPILER environment variable to "fxc". --- src/graphics/d3d12.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/graphics/d3d12.rs b/src/graphics/d3d12.rs index 8970e40..af7643e 100644 --- a/src/graphics/d3d12.rs +++ b/src/graphics/d3d12.rs @@ -112,7 +112,12 @@ pub fn initialize_xr_instance( let instance_descriptor = &wgpu_hal::InstanceDescriptor { name: &app_info.name, - dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(), + dx12_shader_compiler: wgpu::util::dx12_shader_compiler_from_env().unwrap_or( + wgpu::Dx12Compiler::Dxc { + dxil_path: None, + dxc_path: None, + }, + ), flags: wgpu::InstanceFlags::from_build_config().with_env(), gles_minor_version: Default::default(), };