DX12/DX11 hookup, improved adapter selection

This commit is contained in:
Dzmitry Malyshau
2019-08-27 23:41:52 -04:00
parent b414b9f373
commit 175e992149
11 changed files with 323 additions and 90 deletions

View File

@@ -1,4 +1,5 @@
use crate::{
backend,
id::{Input, Output},
Adapter,
AdapterId,
@@ -156,10 +157,8 @@ pub trait Access<B> {}
pub enum Root {}
//TODO: establish an order instead of declaring all the pairs.
#[cfg(not(feature = "gfx-backend-gl"))]
impl Access<Instance> for Root {}
impl Access<Surface> for Root {}
#[cfg(not(feature = "gfx-backend-gl"))]
impl Access<Surface> for Instance {}
impl<B: hal::Backend> Access<Adapter<B>> for Root {}
impl<B: hal::Backend> Access<Adapter<B>> for Surface {}
@@ -296,7 +295,7 @@ impl<T, I: TypedId + Copy> Registry<T, I> {
#[cfg(feature = "remote")]
pub fn new_identity(&self, id_in: Input<I>) -> (I, Output<I>) {
//debug_assert_eq!(self.backend, id_in.backend());
//TODO: debug_assert_eq!(self.backend, id_in.backend());
(id_in, PhantomData)
}
@@ -379,9 +378,13 @@ impl<B: GfxBackend> Default for Hub<B> {
#[derive(Debug, Default)]
pub struct Hubs {
vulkan: Hub<gfx_backend_vulkan::Backend>,
vulkan: Hub<backend::Vulkan>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: Hub<gfx_backend_metal::Backend>,
metal: Hub<backend::Metal>,
#[cfg(windows)]
dx12: Hub<backend::Dx12>,
#[cfg(windows)]
dx11: Hub<backend::Dx11>,
}
#[derive(Debug)]
@@ -405,7 +408,7 @@ pub trait GfxBackend: hal::Backend {
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface;
}
impl GfxBackend for gfx_backend_vulkan::Backend {
impl GfxBackend for backend::Vulkan {
const VARIANT: Backend = Backend::Vulkan;
fn hub() -> &'static Hub<Self> {
&GLOBAL.hubs.vulkan
@@ -416,7 +419,7 @@ impl GfxBackend for gfx_backend_vulkan::Backend {
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
impl GfxBackend for gfx_backend_metal::Backend {
impl GfxBackend for backend::Metal {
const VARIANT: Backend = Backend::Metal;
fn hub() -> &'static Hub<Self> {
&GLOBAL.hubs.metal
@@ -425,3 +428,25 @@ impl GfxBackend for gfx_backend_metal::Backend {
&mut surface.metal
}
}
#[cfg(windows)]
impl GfxBackend for backend::Dx12 {
const VARIANT: Backend = Backend::Dx12;
fn hub() -> &'static Hub<Self> {
&GLOBAL.hubs.dx12
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
surface.dx12.as_mut().unwrap()
}
}
#[cfg(windows)]
impl GfxBackend for backend::Dx11 {
const VARIANT: Backend = Backend::Dx11;
fn hub() -> &'static Hub<Self> {
&GLOBAL.hubs.dx11
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
&mut surface.dx11
}
}

View File

@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use std::{fmt, marker::PhantomData};
const BACKEND_BITS: usize = 3;
const EPOCH_MASK: u32 = (1 << (32 - BACKEND_BITS)) - 1;
type Dummy = crate::backend::Empty;
#[repr(transparent)]
@@ -15,10 +16,10 @@ impl<T> Id<T> {
match self.0 >> (64 - BACKEND_BITS) as u8 {
0 => Backend::Empty,
1 => Backend::Vulkan,
2 => Backend::Gl,
3 => Backend::Metal,
4 => Backend::Dx12,
5 => Backend::Dx11,
2 => Backend::Metal,
3 => Backend::Dx12,
4 => Backend::Dx11,
5 => Backend::Gl,
_ => unreachable!(),
}
}
@@ -57,13 +58,17 @@ pub trait TypedId {
impl<T> TypedId for Id<T> {
fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self {
assert_eq!(0, epoch >> 32 - BACKEND_BITS);
assert_eq!(0, epoch >> (32 - BACKEND_BITS));
let v = index as u64 | ((epoch as u64) << 32) | ((backend as u64) << (64 - BACKEND_BITS));
Id(v, PhantomData)
}
fn unzip(self) -> (Index, Epoch, Backend) {
(self.0 as u32, (self.0 >> 32) as u32, self.backend())
(
self.0 as u32,
(self.0 >> 32) as u32 & EPOCH_MASK,
self.backend(),
)
}
}
@@ -103,3 +108,18 @@ pub type ComputePassId = Id<crate::ComputePass<Dummy>>;
// Swap chain
pub type SurfaceId = Id<crate::Surface>;
pub type SwapChainId = Id<crate::SwapChain<Dummy>>;
#[test]
fn test_id_backend() {
for &b in &[
Backend::Empty,
Backend::Vulkan,
Backend::Metal,
Backend::Dx12,
Backend::Dx11,
Backend::Gl,
] {
let id: Id<()> = Id::zip(0, 0, b);
assert_eq!(id.backend(), b);
}
}

View File

@@ -1,4 +1,5 @@
use crate::{
backend,
binding_model::MAX_BIND_GROUPS,
device::BIND_BUFFER_ALIGNMENT,
hub::{GfxBackend, Token, GLOBAL},
@@ -23,22 +24,32 @@ use hal::{self, Instance as _, PhysicalDevice as _};
use std::marker::PhantomData;
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct Instance {
vulkan: Option<gfx_backend_vulkan::Instance>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: gfx_backend_metal::Instance,
#[cfg(windows)]
dx12: Option<gfx_backend_dx12::Instance>,
#[cfg(windows)]
dx11: gfx_backend_dx11::Instance,
}
impl Instance {
pub(crate) fn new(name: &str, version: u32) -> Self {
Instance {
#[cfg(any(unix, windows))]
vulkan: Some(gfx_backend_vulkan::Instance::create(name, version)),
#[cfg(not(any(unix, windows)))]
vulkan: None,
//TODO: reconsider once `create` returns a `Result`
vulkan: if cfg!(all(unix, not(target_os = "ios"), not(target_os = "macos"))) {
Some(gfx_backend_vulkan::Instance::create(name, version))
} else {
None
},
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: gfx_backend_metal::Instance::create(name, version),
#[cfg(windows)]
dx12: Some(gfx_backend_dx12::Instance::create(name, version)),
#[cfg(windows)]
dx11: gfx_backend_dx11::Instance::create(name, version),
}
}
}
@@ -48,9 +59,13 @@ type GfxSurface<B> = <B as hal::Backend>::Surface;
#[derive(Debug)]
pub struct Surface {
pub(crate) swap_chain: Option<SwapChainId>,
pub(crate) vulkan: Option<GfxSurface<gfx_backend_vulkan::Backend>>,
pub(crate) vulkan: Option<GfxSurface<backend::Vulkan>>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub(crate) metal: GfxSurface<gfx_backend_metal::Backend>,
pub(crate) metal: GfxSurface<backend::Metal>,
#[cfg(windows)]
pub(crate) dx12: Option<GfxSurface<backend::Dx12>>,
#[cfg(windows)]
pub(crate) dx11: GfxSurface<backend::Dx11>,
}
#[derive(Debug)]
@@ -138,15 +153,6 @@ pub struct DeviceDescriptor {
pub limits: Limits,
}
#[cfg(all(not(feature = "remote"), feature = "glutin"))]
pub fn wgpu_create_gl_surface(
windowed_context: back::glutin::RawContext<back::glutin::PossiblyCurrent>,
) -> SurfaceId {
let raw = back::Surface::from_context(windowed_context);
let surface = SurfaceHandle::new(raw);
GLOBAL.surfaces.register_local(surface, &mut Token::root())
}
#[cfg(not(feature = "remote"))]
pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> SurfaceId {
use raw_window_handle::RawWindowHandle as Rwh;
@@ -172,7 +178,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
.metal
.create_surface_from_nsview(h.ns_view, cfg!(debug_assertions)),
},
#[cfg(unix)]
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
Rwh::X11(h) => Surface {
swap_chain: None,
vulkan: instance
@@ -180,7 +186,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
.as_ref()
.map(|inst| inst.create_surface_from_xlib(h.display as _, h.window as _)),
},
#[cfg(unix)]
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
Rwh::Wayland(h) => Surface {
swap_chain: None,
vulkan: instance
@@ -195,10 +201,11 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
.vulkan
.as_ref()
.map(|inst| inst.create_surface_from_hwnd(std::ptr::null_mut(), h.hwnd)),
//dx11: instance.dx11.create_surface_from_hwnd(h.hwnd),
//dx12: instance.dx11
// .as_ref()
// .map(|inst| inst.create_surface_from_hwnd(h.hwnd),
dx12: instance
.dx12
.as_ref()
.map(|inst| inst.create_surface_from_hwnd(h.hwnd)),
dx11: instance.dx11.create_surface_from_hwnd(h.hwnd),
},
_ => panic!("Unsupported window handle"),
};
@@ -209,7 +216,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su
.register_identity(PhantomData, surface, &mut token)
}
#[cfg(all(not(feature = "remote"), unix))]
#[cfg(all(not(feature = "remote"), unix, not(target_os = "ios"), not(target_os = "macos")))]
#[no_mangle]
pub extern "C" fn wgpu_create_surface_from_xlib(
display: *mut *const std::ffi::c_void,
@@ -228,15 +235,11 @@ pub extern "C" fn wgpu_create_surface_from_xlib(
pub extern "C" fn wgpu_create_surface_from_metal_layer(layer: *mut std::ffi::c_void) -> SurfaceId {
let surface = Surface {
swap_chain: None,
vulkan: GLOBAL
.instance
.vulkan
.as_ref()
.map(|inst| inst.create_surface_from_layer(h.ns_view)),
vulkan: None, //TODO: currently requires `NSView`
metal: GLOBAL
.instance
.metal
.create_surface_from_nsview(h.ns_view, cfg!(debug_assertions)),
.create_surface_from_layer(layer as *mut _, cfg!(debug_assertions)),
};
GLOBAL
@@ -250,20 +253,15 @@ pub extern "C" fn wgpu_create_surface_from_windows_hwnd(
_hinstance: *mut std::ffi::c_void,
hwnd: *mut std::ffi::c_void,
) -> SurfaceId {
use raw_window_handle::windows::Handle;
use raw_window_handle::windows::WindowsHandle;
wgpu_create_surface(raw_window_handle::RawWindowHandle::Windows(
raw_window_handle::windows::Handle {
raw_window_handle::windows::WindowsHandle {
hwnd,
..Handle::empty()
..WindowsHandle::empty()
},
))
}
#[cfg(all(not(feature = "remote"), feature = "gfx-backend-gl"))]
pub fn wgpu_get_gl_surface() -> SurfaceId {
instance_id
}
pub fn request_adapter(
desc: &RequestAdapterOptions,
input_ids: &[Input<AdapterId>],
@@ -285,51 +283,67 @@ pub fn request_adapter(
let id_vulkan = find_input(Backend::Vulkan);
let id_metal = find_input(Backend::Metal);
let id_dx12 = find_input(Backend::Dx12);
let id_dx11 = find_input(Backend::Dx11);
let mut adapters_vk = match instance.vulkan {
Some(ref inst) if id_vulkan.is_some() => inst.enumerate_adapters(),
Some(ref inst) if id_vulkan.is_some() => {
let adapters = inst.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
}
_ => Vec::new(),
};
device_types.extend(adapters_vk.iter().map(|ad| ad.info.device_type.clone()));
#[cfg(any(target_os = "ios", target_os = "macos"))]
let mut adaptres_mtl = if id_metal.is_some() {
let mut adapters_mtl = if id_metal.is_some() {
let adapters = instance.metal.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
} else {
Vec::new()
};
#[cfg(windows)]
let mut adapters_dx12 = match instance.dx12 {
Some(ref inst) if id_dx12.is_some() => {
let adapters = inst.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
}
_ => Vec::new(),
};
#[cfg(windows)]
let mut adapters_dx11 = if id_dx11.is_some() {
let adapters = instance.dx11.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
} else {
Vec::new()
};
if device_types.is_empty() {
panic!("No adapters are available!");
}
let (mut integrated_first, mut discrete_first, mut discrete_last) = (None, None, None);
let (mut integrated, mut discrete, mut other) = (None, None, None);
// On Windows > 1803, dx12 enumerate_adapters returns the adapters in order from highest to
// lowest performance. Therefore, the first found adapter in each category is selected.
//
// TODO: move power/performance policy querying into gfx, which has more context into
// performance policy than wgpu
for (i, ty) in device_types.into_iter().enumerate() {
match ty {
hal::adapter::DeviceType::IntegratedGpu => {
integrated_first = integrated_first.or(Some(i));
integrated = integrated.or(Some(i));
}
hal::adapter::DeviceType::DiscreteGpu => {
discrete_first = discrete_first.or(Some(i));
discrete_last = Some(i);
discrete = discrete.or(Some(i));
}
_ => {
other = other.or(Some(i));
}
_ => {}
}
}
let preferred_gpu = match desc.power_preference {
// If `LowPower`, prefer lowest power `DiscreteGPU`
PowerPreference::LowPower => integrated_first.or(discrete_last),
PowerPreference::HighPerformance | PowerPreference::Default => {
discrete_first.or(integrated_first)
}
PowerPreference::Default => integrated.or(discrete).or(other),
PowerPreference::LowPower => integrated.or(other).or(discrete),
PowerPreference::HighPerformance => discrete.or(other).or(integrated),
};
let mut token = Token::root();
@@ -340,9 +354,11 @@ pub fn request_adapter(
raw: adapters_vk.swap_remove(selected),
};
info!("Adapter Vulkan {:?}", adapter.raw.info);
let id_out = gfx_backend_vulkan::Backend::hub()
.adapters
.register_identity(id_vulkan.unwrap(), adapter, &mut token);
let id_out = backend::Vulkan::hub().adapters.register_identity(
id_vulkan.unwrap(),
adapter,
&mut token,
);
return Some(id_out);
}
selected -= adapters_vk.len();
@@ -354,14 +370,45 @@ pub fn request_adapter(
raw: adapters_mtl.swap_remove(selected),
};
info!("Adapter Metal {:?}", adapter.raw.info);
let id_out = gfx_backend_metal::Backend::hub()
.adapters
.register_identity(id_metal.unwrap(), adapter, &mut token);
let id_out = backend::Metal::hub().adapters.register_identity(
id_metal.unwrap(),
adapter,
&mut token,
);
return Some(id_out);
}
selected -= adapters_mtl.len();
}
let _ = (selected, id_metal);
#[cfg(windows)]
{
if selected < adapters_dx12.len() {
let adapter = Adapter {
raw: adapters_dx12.swap_remove(selected),
};
info!("Adapter Dx12 {:?}", adapter.raw.info);
let id_out = backend::Dx12::hub().adapters.register_identity(
id_dx12.unwrap(),
adapter,
&mut token,
);
return Some(id_out);
}
selected -= adapters_dx12.len();
if selected < adapters_dx11.len() {
let adapter = Adapter {
raw: adapters_dx11.swap_remove(selected),
};
info!("Adapter Dx11 {:?}", adapter.raw.info);
let id_out = backend::Dx11::hub().adapters.register_identity(
id_dx11.unwrap(),
adapter,
&mut token,
);
return Some(id_out);
}
selected -= adapters_dx11.len();
}
let _ = (selected, id_metal, id_dx12, id_dx11);
None
}

View File

@@ -1,4 +1,8 @@
pub mod backend {
#[cfg(windows)]
pub use gfx_backend_dx11::Backend as Dx11;
#[cfg(windows)]
pub use gfx_backend_dx12::Backend as Dx12;
pub use gfx_backend_empty::Backend as Empty;
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub use gfx_backend_metal::Backend as Metal;
@@ -29,9 +33,6 @@ pub use self::resource::*;
pub use self::swap_chain::*;
pub use hal::pso::read_spirv;
#[cfg(feature = "glutin")]
pub use back::glutin;
use std::{
os::raw::c_char,
ptr,
@@ -47,10 +48,10 @@ type Epoch = u32;
pub enum Backend {
Empty = 0,
Vulkan = 1,
Gl = 2,
Metal = 3,
Dx12 = 4,
Dx11 = 5,
Metal = 2,
Dx12 = 3,
Dx11 = 4,
Gl = 5,
}
pub type BufferAddress = u64;
@@ -204,6 +205,10 @@ macro_rules! gfx_select {
$crate::Backend::Vulkan => $function::<$crate::backend::Vulkan>( $($param),+ ),
#[cfg(any(target_os = "ios", target_os = "macos"))]
$crate::Backend::Metal => $function::<$crate::backend::Metal>( $($param),+ ),
#[cfg(windows)]
$crate::Backend::Dx12 => $function::<$crate::backend::Dx12>( $($param),+ ),
#[cfg(windows)]
$crate::Backend::Dx11 => $function::<$crate::backend::Dx11>( $($param),+ ),
_ => unreachable!()
}
};