Implement software adapter selection

This commit is contained in:
Dzmitry Malyshau 2021-10-01 08:06:03 -04:00 committed by Dzmitry Malyshau
parent 97d6db4d18
commit 1ee6036f44
10 changed files with 88 additions and 73 deletions

View File

@ -216,6 +216,7 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct RequestAdapterArgs { pub struct RequestAdapterArgs {
power_preference: Option<wgpu_types::PowerPreference>, power_preference: Option<wgpu_types::PowerPreference>,
force_fallback_adapter: bool,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -259,7 +260,7 @@ pub async fn op_webgpu_request_adapter(
Some(power_preference) => power_preference.into(), Some(power_preference) => power_preference.into(),
None => PowerPreference::default(), None => PowerPreference::default(),
}, },
// TODO(lucacasonato): respect forceFallbackAdapter force_fallback_adapter: args.force_fallback_adapter,
compatible_surface: None, // windowless compatible_surface: None, // windowless
}; };
let res = instance.request_adapter( let res = instance.request_adapter(

View File

@ -55,6 +55,7 @@ fn main() {
.request_adapter( .request_adapter(
&wgc::instance::RequestAdapterOptions { &wgc::instance::RequestAdapterOptions {
power_preference: wgt::PowerPreference::LowPower, power_preference: wgt::PowerPreference::LowPower,
force_fallback_adapter: false,
#[cfg(feature = "winit")] #[cfg(feature = "winit")]
compatible_surface: Some(surface), compatible_surface: Some(surface),
#[cfg(not(feature = "winit"))] #[cfg(not(feature = "winit"))]

View File

@ -186,6 +186,7 @@ impl Corpus {
let adapter = match global.request_adapter( let adapter = match global.request_adapter(
&wgc::instance::RequestAdapterOptions { &wgc::instance::RequestAdapterOptions {
power_preference: wgt::PowerPreference::LowPower, power_preference: wgt::PowerPreference::LowPower,
force_fallback_adapter: false,
compatible_surface: None, compatible_surface: None,
}, },
wgc::instance::AdapterInputs::IdSet( wgc::instance::AdapterInputs::IdSet(

View File

@ -551,7 +551,34 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
) -> Result<AdapterId, RequestAdapterError> { ) -> Result<AdapterId, RequestAdapterError> {
profiling::scope!("pick_adapter", "Instance"); profiling::scope!("pick_adapter", "Instance");
let instance = &self.instance; fn gather<A: HalApi, I: Clone>(
_: A,
instance: Option<&A::Instance>,
inputs: &AdapterInputs<I>,
compatible_surface: Option<&Surface>,
force_software: bool,
device_types: &mut Vec<wgt::DeviceType>,
) -> (Option<I>, Vec<hal::ExposedAdapter<A>>) {
let id = inputs.find(A::VARIANT);
match instance {
Some(inst) if id.is_some() => {
let mut adapters = unsafe { inst.enumerate_adapters() };
if force_software {
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
}
if let Some(surface) = compatible_surface {
let suf_raw = &A::get_surface(surface).raw;
adapters.retain(|exposed| unsafe {
exposed.adapter.surface_capabilities(suf_raw).is_some()
});
}
device_types.extend(adapters.iter().map(|ad| ad.info.device_type));
(id, adapters)
}
_ => (id, Vec::new()),
}
}
let mut token = Token::root(); let mut token = Token::root();
let (surface_guard, mut token) = self.surfaces.read(&mut token); let (surface_guard, mut token) = self.surfaces.read(&mut token);
let compatible_surface = desc let compatible_surface = desc
@ -564,67 +591,51 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.transpose()?; .transpose()?;
let mut device_types = Vec::new(); let mut device_types = Vec::new();
let mut id_vulkan = inputs.find(Backend::Vulkan); #[cfg(vulkan)]
let mut id_metal = inputs.find(Backend::Metal); let (mut id_vulkan, adapters_vk) = gather(
let mut id_dx12 = inputs.find(Backend::Dx12); hal::api::Vulkan,
let mut id_dx11 = inputs.find(Backend::Dx11); self.instance.vulkan.as_ref(),
let mut id_gl = inputs.find(Backend::Gl); &inputs,
compatible_surface,
backends_map! { desc.force_fallback_adapter,
let map = |(instance_backend, id_backend, surface_backend)| { &mut device_types,
match *instance_backend { );
Some(ref inst) if id_backend.is_some() => { #[cfg(metal)]
let mut adapters = unsafe { inst.enumerate_adapters() }; let (mut id_metal, adapters_metal) = gather(
if let Some(surface_backend) = compatible_surface.and_then(surface_backend) { hal::api::Metal,
adapters.retain(|exposed| unsafe { self.instance.metal.as_ref(),
exposed.adapter.surface_capabilities(&surface_backend.raw).is_some() &inputs,
}); compatible_surface,
} desc.force_fallback_adapter,
device_types.extend(adapters.iter().map(|ad| ad.info.device_type)); &mut device_types,
adapters );
} #[cfg(dx12)]
_ => Vec::new(), let (mut id_dx12, adapters_dx12) = gather(
} hal::api::Dx12,
}; self.instance.dx12.as_ref(),
&inputs,
// NB: The internal function definitions are a workaround for Rust compatible_surface,
// being weird with lifetimes for closure literals... desc.force_fallback_adapter,
#[cfg(vulkan)] &mut device_types,
let adapters_vk = map((&instance.vulkan, &id_vulkan, { );
fn surface_vulkan(surf: &Surface) -> Option<&HalSurface<hal::api::Vulkan>> { #[cfg(dx11)]
surf.vulkan.as_ref() let (mut id_dx11, adapters_dx11) = gather(
} hal::api::Dx11,
surface_vulkan self.instance.dx11.as_ref(),
})); &inputs,
#[cfg(metal)] compatible_surface,
let adapters_mtl = map((&instance.metal, &id_metal, { desc.force_fallback_adapter,
fn surface_metal(surf: &Surface) -> Option<&HalSurface<hal::api::Metal>> { &mut device_types,
surf.metal.as_ref() );
} #[cfg(gl)]
surface_metal let (mut id_gl, adapters_gl) = gather(
})); hal::api::Gles,
#[cfg(dx12)] self.instance.gl.as_ref(),
let adapters_dx12 = map((&instance.dx12, &id_dx12, { &inputs,
fn surface_dx12(surf: &Surface) -> Option<&HalSurface<hal::api::Dx12>> { compatible_surface,
surf.dx12.as_ref() desc.force_fallback_adapter,
} &mut device_types,
surface_dx12 );
}));
#[cfg(dx11)]
let adapters_dx11 = map((&instance.dx11, &id_dx11, {
fn surface_dx11(surf: &Surface) -> Option<&HalSurface<hal::api::Dx11>> {
surf.dx11.as_ref()
}
surface_dx11
}));
#[cfg(gl)]
let adapters_gl = map((&instance.gl, &id_gl, {
fn surface_gl(surf: &Surface) -> Option<&HalSurface<hal::api::Gles>> {
surf.gl.as_ref()
}
surface_gl
}));
}
if device_types.is_empty() { if device_types.is_empty() {
return Err(RequestAdapterError::NotFound); return Err(RequestAdapterError::NotFound);
@ -676,7 +687,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
#[cfg(vulkan)] #[cfg(vulkan)]
map(("Vulkan", &mut id_vulkan, adapters_vk)), map(("Vulkan", &mut id_vulkan, adapters_vk)),
#[cfg(metal)] #[cfg(metal)]
map(("Metal", &mut id_metal, adapters_mtl)), map(("Metal", &mut id_metal, adapters_metal)),
#[cfg(dx12)] #[cfg(dx12)]
map(("Dx12", &mut id_dx12, adapters_dx12)), map(("Dx12", &mut id_dx12, adapters_dx12)),
#[cfg(dx11)] #[cfg(dx11)]
@ -685,14 +696,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
map(("GL", &mut id_gl, adapters_gl)), map(("GL", &mut id_gl, adapters_gl)),
} }
let _ = ( let _ = selected;
selected,
id_vulkan.take(),
id_metal.take(),
id_dx12.take(),
id_dx11.take(),
id_gl.take(),
);
log::warn!("Some adapters are present, but enumerating them failed!"); log::warn!("Some adapters are present, but enumerating them failed!");
Err(RequestAdapterError::NotFound) Err(RequestAdapterError::NotFound)
} }

View File

@ -131,6 +131,9 @@ impl From<Backend> for Backends {
pub struct RequestAdapterOptions<S> { pub struct RequestAdapterOptions<S> {
/// Power preference for the adapter. /// Power preference for the adapter.
pub power_preference: PowerPreference, pub power_preference: PowerPreference,
/// Indicates that only a fallback adapter can be returned. This is generally a "software"
/// implementation on the system.
pub force_fallback_adapter: bool,
/// Surface that is required to be presentable with the requested adapter. This does not /// Surface that is required to be presentable with the requested adapter. This does not
/// create the surface, only guarantees that the adapter can present to said surface. /// create the surface, only guarantees that the adapter can present to said surface.
pub compatible_surface: Option<S>, pub compatible_surface: Option<S>,
@ -140,6 +143,7 @@ impl<S> Default for RequestAdapterOptions<S> {
fn default() -> Self { fn default() -> Self {
Self { Self {
power_preference: PowerPreference::default(), power_preference: PowerPreference::default(),
force_fallback_adapter: false,
compatible_surface: None, compatible_surface: None,
} }
} }

View File

@ -12,6 +12,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(), power_preference: wgpu::PowerPreference::default(),
force_fallback_adapter: false,
// Request an adapter which can render to our surface // Request an adapter which can render to our surface
compatible_surface: Some(&surface), compatible_surface: Some(&surface),
}) })

View File

@ -66,9 +66,9 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Window, wgpu::Color)>) {
.collect(); .collect();
let adapter = instance let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions { .request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
// Request an adapter which can render to our surface // Request an adapter which can render to our surface
compatible_surface: viewports.first().map(|desc| &desc.surface), compatible_surface: viewports.first().map(|desc| &desc.surface),
..Default::default()
}) })
.await .await
.expect("Failed to find an appropriate adapter"); .expect("Failed to find an appropriate adapter");

View File

@ -777,6 +777,7 @@ impl crate::Context for Context {
let id = self.0.request_adapter( let id = self.0.request_adapter(
&wgc::instance::RequestAdapterOptions { &wgc::instance::RequestAdapterOptions {
power_preference: options.power_preference, power_preference: options.power_preference,
force_fallback_adapter: options.force_fallback_adapter,
compatible_surface: options.compatible_surface.map(|surface| surface.id.id), compatible_surface: options.compatible_surface.map(|surface| surface.id.id),
}, },
wgc::instance::AdapterInputs::Mask(wgt::Backends::all(), |_| PhantomData), wgc::instance::AdapterInputs::Mask(wgt::Backends::all(), |_| PhantomData),

View File

@ -79,6 +79,7 @@ pub async fn initialize_adapter_from_env_or_default(
instance instance
.request_adapter(&RequestAdapterOptions { .request_adapter(&RequestAdapterOptions {
power_preference: power_preference_from_env().unwrap_or_default(), power_preference: power_preference_from_env().unwrap_or_default(),
force_fallback_adapter: false,
compatible_surface, compatible_surface,
}) })
.await .await

View File

@ -12,6 +12,7 @@ fn request_adapter_inner(power: wgt::PowerPreference) {
let _adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { let _adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: power, power_preference: power,
force_fallback_adapter: false,
compatible_surface: None, compatible_surface: None,
})) }))
.unwrap(); .unwrap();