From d23288e455eec657c5632d7c24410d0d2ef2057e Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 2 Sep 2021 14:27:27 -0400 Subject: [PATCH] hal/linux: Work around Intel+Nvidia presentation conflict --- wgpu-hal/src/auxil/mod.rs | 3 +++ wgpu-hal/src/vulkan/adapter.rs | 5 +++++ wgpu-hal/src/vulkan/instance.rs | 27 +++++++++++++++++++++++++-- wgpu-hal/src/vulkan/mod.rs | 2 ++ wgpu-types/src/lib.rs | 2 ++ wgpu/examples/framework.rs | 7 ++++--- wgpu/src/util/init.rs | 5 +++-- wgpu/tests/common/mod.rs | 1 + 8 files changed, 45 insertions(+), 7 deletions(-) diff --git a/wgpu-hal/src/auxil/mod.rs b/wgpu-hal/src/auxil/mod.rs index bf4470f8e..6a0e99a74 100644 --- a/wgpu-hal/src/auxil/mod.rs +++ b/wgpu-hal/src/auxil/mod.rs @@ -7,6 +7,9 @@ pub mod db { pub const DEVICE_KABY_LAKE_MASK: u32 = 0x5900; pub const DEVICE_SKY_LAKE_MASK: u32 = 0x1900; } + pub mod nvidia { + pub const VENDOR: u32 = 0x10DE; + } } pub fn map_naga_stage(stage: naga::ShaderStage) -> wgt::ShaderStages { diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 94b46791b..ba393d348 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -698,6 +698,7 @@ impl super::Instance { .contains(vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT) }, non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1, + can_present: true, }; let capabilities = crate::Capabilities { @@ -1023,6 +1024,10 @@ impl crate::Adapter for super::Adapter { &self, surface: &super::Surface, ) -> Option { + if !self.private_caps.can_present { + return None; + } + let queue_family_index = 0; //TODO match surface.functor.get_physical_device_surface_support( self.raw, diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 2bd3b5233..bda9eaaa1 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -600,10 +600,33 @@ impl crate::Instance for super::Instance { } }; - raw_devices + let mut exposed_adapters = raw_devices .into_iter() .flat_map(|device| self.expose_adapter(device)) - .collect() + .collect::>(); + + // detect if it's an Intel + NVidia configuration + if cfg!(target_os = "linux") { + use crate::auxil::db; + let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| { + exposed.info.device_type == wgt::DeviceType::DiscreteGpu + && exposed.info.vendor == db::nvidia::VENDOR as usize + }); + if has_nvidia_dgpu { + for exposed in exposed_adapters.iter_mut() { + if exposed.info.device_type == wgt::DeviceType::IntegratedGpu + && exposed.info.vendor == db::intel::VENDOR as usize + { + // See https://gitlab.freedesktop.org/mesa/mesa/-/issues/4688 + log::warn!("Disabling presentation on '{}' (id {:?}) because of an Nvidia dGPU (on Linux)", + exposed.info.name, exposed.adapter.raw); + exposed.adapter.private_caps.can_present = false; + } + } + } + } + + exposed_adapters } } diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 28559ec6d..f348f2304 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -158,6 +158,8 @@ struct PrivateCapabilities { timeline_semaphores: bool, texture_d24: bool, texture_d24_s8: bool, + /// Ability to present contents to any screen. Only needed to work around broken platform configurations. + can_present: bool, non_coherent_map_mask: wgt::BufferAddress, } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index ae739290a..9854602df 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -824,6 +824,8 @@ pub enum DeviceType { Cpu, } +//TODO: convert `vendor` and `device` to `u32` + /// Information about an adapter. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index ad12c84fb..12fbe5548 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -118,9 +118,10 @@ async fn setup(title: &str) -> Setup { let surface = instance.create_surface(&window); (size, surface) }; - let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, backend) - .await - .expect("No suitable GPU adapters found on the system!"); + let adapter = + wgpu::util::initialize_adapter_from_env_or_default(&instance, backend, Some(&surface)) + .await + .expect("No suitable GPU adapters found on the system!"); #[cfg(not(target_arch = "wasm32"))] { diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index 91e0011f0..4c5d6c3f7 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -1,6 +1,6 @@ use wgt::{Backends, PowerPreference, RequestAdapterOptions}; -use crate::{Adapter, Instance}; +use crate::{Adapter, Instance, Surface}; /// Get a set of backend bits from the environment variable WGPU_BACKEND. pub fn backend_bits_from_env() -> Option { @@ -72,6 +72,7 @@ pub fn initialize_adapter_from_env( pub async fn initialize_adapter_from_env_or_default( instance: &Instance, backend_bits: wgt::Backends, + compatible_surface: Option<&Surface>, ) -> Option { match initialize_adapter_from_env(instance, backend_bits) { Some(a) => Some(a), @@ -80,7 +81,7 @@ pub async fn initialize_adapter_from_env_or_default( .request_adapter(&RequestAdapterOptions { power_preference: power_preference_from_env() .unwrap_or_else(PowerPreference::default), - compatible_surface: None, + compatible_surface, }) .await } diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index 5c1b9c69c..9ee1840ba 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -186,6 +186,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te let adapter = pollster::block_on(util::initialize_adapter_from_env_or_default( &instance, backend_bits, + None, )) .expect("could not find sutable adapter on the system");