mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
DX12/DX11 hookup, improved adapter selection
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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!()
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user