From ea14647e7a4b108200595b18b141a4d2ccbad998 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 31 Jul 2026 12:09:17 +0000 Subject: [PATCH] Deprioritize old Intel Mesa Vulkan adapters by version, not name Warp freezes on the startup message on an `Intel(R) Xe Graphics (TGL GT2)` with Mesa 21.2.6: every `get_current_texture` call returns a validation error, so no frame after the first ever renders. This is the same failure as the Intel UHD (ICL GT1) report, but the name-based allowlist in `is_older_vulkan_intel_uhd_adapter` missed it because the adapter is an `Xe`/`GT2` part rather than a `UHD`/`GT1` one, even though the broken driver is identical. Replace the allowlist with a Mesa-version check: a Vulkan integrated adapter using the Mesa Intel driver on Mesa older than 21.3.6 is deprioritized, so the healthy GL adapter for the same GPU is picked instead. This only affects ranking, so the Vulkan adapter is still used when nothing else can present to the surface. Also split the stability ranking out of `adapter_stability_sort_func` into `adapter_support`, which takes `wgpu::AdapterInfo`, so adapter ranking can be unit tested without a real GPU. Fixes #14577 Co-Authored-By: Oz --- crates/warpui/src/rendering/wgpu/resources.rs | 86 +++++---- .../src/rendering/wgpu/resources_tests.rs | 169 +++++++++++++++++- 2 files changed, 218 insertions(+), 37 deletions(-) diff --git a/crates/warpui/src/rendering/wgpu/resources.rs b/crates/warpui/src/rendering/wgpu/resources.rs index 7981048c714..01d9237fd3b 100644 --- a/crates/warpui/src/rendering/wgpu/resources.rs +++ b/crates/warpui/src/rendering/wgpu/resources.rs @@ -41,12 +41,12 @@ lazy_static! { static ref MIN_SUPPORTED_LAVAPIPE_VERSION: Version<'static> = Version::from("24.0.2") .expect("should not fail to parse version"); - /// The minimum supported driver version for Vulkan-backed Intel UHD integrated graphics. + /// The minimum supported Mesa driver version for Vulkan-backed Intel integrated graphics. /// /// Some issues we've seen: PLAT-744 and PLAT-599. /// Mesa changelog mentions a fix for flickering on Intel UHD: /// https://docs.mesa3d.org/relnotes/21.3.6.html#:~:text=Flickering%20Intel%20Uhd%20620%20Graphics - static ref MIN_SUPPORTED_INTEL_UHD_VERSION: Version<'static> = Version::from("21.3.6") + static ref MIN_SUPPORTED_INTEL_MESA_VERSION: Version<'static> = Version::from("21.3.6") .expect("should not fail to parse version"); /// Nvidia drivers version 535 have problems with Wayland window managers, e.g. PLAT-667 and @@ -469,37 +469,47 @@ fn is_gl_to_metal_adapter_on_windows_in_parallels(adapter_info: &wgpu::AdapterIn && adapter_info.name.to_lowercase().starts_with("parallels") } -/// Returns whether or not the provided adapter is an unsupported Intel UHD Mesa driver version for -/// warpui to render properly. Affected adapters include: -/// - `Intel(R) HD Graphics 620` (KBL GT2) — flickering (PLAT-744) -/// - `Intel(R) UHD Graphics (ICL GT1)` — stuck at "Starting zsh..." on Mesa 21.2.6 (GH #14325) -/// - `Intel(R) UHD Graphics (TGL GT1)` — window flashing/flicker on older Mesa (PLAT-599, GH #4533) +/// Returns whether the provided adapter uses the Mesa open-source Intel driver (ANV for Vulkan, +/// Iris/i965 for GL). +fn is_intel_mesa_adapter(adapter_info: &wgpu::AdapterInfo) -> bool { + // The Mesa Intel Vulkan driver reports itself as "Intel open-source Mesa driver", so requiring + // "Mesa" in the driver name keeps us from misinterpreting non-Mesa (e.g. Windows) Intel driver + // version strings as Mesa versions. + adapter_info.driver.contains("Mesa") + && (adapter_info.driver.contains("Intel") || adapter_info.name.contains("Intel")) +} + +/// Returns whether or not the provided adapter is an Intel integrated GPU running a Mesa Vulkan +/// driver that is too old for warpui to render properly. +/// +/// This is keyed off the Mesa version rather than an allowlist of adapter names: every Intel +/// integrated GPU we've seen fail this way (`Intel(R) HD Graphics 620` (KBL GT2), `Intel(R) UHD +/// Graphics (ICL GT1)`, `Intel(R) UHD Graphics (TGL GT1)`, `Intel(R) Xe Graphics (TGL GT2)`) has +/// been on Mesa older than [`MIN_SUPPORTED_INTEL_MESA_VERSION`], and name-based matching kept +/// missing new Intel graphics families and GT tiers on the exact same broken drivers. +/// +/// Symptoms range from flickering (PLAT-744, PLAT-599, GH #4533) to a permanently frozen window +/// caused by every `get_current_texture` call returning a validation error (GH #14325, GH #14577). +/// +/// Note that this only deprioritizes the adapter: if no other adapter can present to the surface, +/// we still fall back to using it rather than failing to open a window. /// /// See the Mesa 21.3.6 changelog for the upstream fix: /// -fn is_older_vulkan_intel_uhd_adapter(adapter_info: &wgpu::AdapterInfo) -> bool { +fn is_older_vulkan_intel_mesa_adapter(adapter_info: &wgpu::AdapterInfo) -> bool { if adapter_info.backend != wgpu::Backend::Vulkan || adapter_info.device_type != wgpu::DeviceType::IntegratedGpu { return false; } - let affected_names = [ - "Intel(R) HD Graphics 620", - "Intel(R) UHD Graphics (ICL GT1)", - "Intel(R) UHD Graphics (TGL GT1)", - ]; - - if !affected_names - .iter() - .any(|name| adapter_info.name.contains(name)) - { + if !is_intel_mesa_adapter(adapter_info) { return false; } mesa_driver_version_is_below_minimum( &adapter_info.driver_info, - &MIN_SUPPORTED_INTEL_UHD_VERSION, + &MIN_SUPPORTED_INTEL_MESA_VERSION, ) } @@ -753,8 +763,22 @@ fn adapter_stability_sort_func( windowing_system: Option, downrank_non_nvidia_vulkan_adapters: bool, ) -> AdapterSupport { - let adapter_info = adapter.get_info(); + adapter_support( + &adapter.get_info(), + windowing_system, + downrank_non_nvidia_vulkan_adapters, + ) +} +/// Computes the [`AdapterSupport`] level for the given adapter info. +/// +/// This is split out from [`adapter_stability_sort_func`] so that it can be unit tested without a +/// real GPU adapter. +fn adapter_support( + adapter_info: &wgpu::AdapterInfo, + windowing_system: Option, + downrank_non_nvidia_vulkan_adapters: bool, +) -> AdapterSupport { let window_server_is_wayland = matches!( windowing_system, Some(windowing::System::Wayland) | Some(windowing::System::X11 { is_x_wayland: true }) @@ -762,7 +786,7 @@ fn adapter_stability_sort_func( if downrank_non_nvidia_vulkan_adapters && adapter_info.backend == Backend::Vulkan - && !is_vulkan_nvidia_adapter(&adapter_info) + && !is_vulkan_nvidia_adapter(adapter_info) { log::info!( "Deprioritizing non-NVIDIA Vulkan adapter (the PRIME performance profile is likely enabled)" @@ -770,37 +794,37 @@ fn adapter_stability_sort_func( return AdapterSupport::Unsupported; } - if is_v3d_vulkan_adapter(&adapter_info) { + if is_v3d_vulkan_adapter(adapter_info) { log::warn!("Deprioritizing Vulkan-backed V3D adapter"); return AdapterSupport::Unsupported; } - if is_intel_uhd_620_adapter_on_windows_with_vulkan_backend(&adapter_info) { + if is_intel_uhd_620_adapter_on_windows_with_vulkan_backend(adapter_info) { log::warn!("Deprioritizing Vulkan-backed Intel UHD 620 adapter"); return AdapterSupport::SupportedWithIssues; } - if is_intel_uhd_770_adapter_on_windows(&adapter_info) { + if is_intel_uhd_770_adapter_on_windows(adapter_info) { log::warn!("Deprioritizing Intel UHD 770 integrated GPU on Windows"); return AdapterSupport::SupportedWithIssues; } - if is_older_vulkan_intel_uhd_adapter(&adapter_info) { + if is_older_vulkan_intel_mesa_adapter(adapter_info) { log::warn!( - "Deprioritizing Vulkan-backed Intel UHD adapter due to Mesa < {} (unsupported)", - *MIN_SUPPORTED_INTEL_UHD_VERSION + "Deprioritizing Vulkan-backed Intel adapter due to Mesa < {} (unsupported)", + *MIN_SUPPORTED_INTEL_MESA_VERSION ); AdapterSupport::SupportedWithIssues } // Deprioritize older lavapipe adapters where we have evidence that they are less stable. - else if is_older_lavapipe_adapter(&adapter_info) { + else if is_older_lavapipe_adapter(adapter_info) { log::warn!( "Deprioritizing Vulkan-backed llvmpipe adapter due to Mesa < {} (unsupported)", *MIN_SUPPORTED_LAVAPIPE_VERSION ); AdapterSupport::Unsupported // Same with Nvidia drivers, though this is only an issue with a Wayland window server. - } else if window_server_is_wayland && is_older_nvidia_adapter(&adapter_info) { + } else if window_server_is_wayland && is_older_nvidia_adapter(adapter_info) { log::warn!( "Deprioritizing Vulkan-backed Nvidia adapter due to version < {} (unsupported).\nSee \ the \"Graphics\" secion of our docs here: \ @@ -808,7 +832,7 @@ fn adapter_stability_sort_func( *MIN_SUPPORTED_NVIDIA_VERSION ); AdapterSupport::Unsupported - } else if is_newer_nondx12_nvidia_adapter_on_windows(&adapter_info) { + } else if is_newer_nondx12_nvidia_adapter_on_windows(adapter_info) { log::warn!( "Deprioritizing non DX12 Nvidia adapter due to version > {} (unsupported). Newer NVIDIA \ drivers can crash if multiple windows are created if the `Vulkan / OpenGL Present Method\ @@ -816,7 +840,7 @@ fn adapter_stability_sort_func( *MAX_SUPPORTED_NVIDIA_VERSION_ON_WINDOWS ); AdapterSupport::SupportedWithIssues - } else if is_gl_to_metal_adapter_on_windows_in_parallels(&adapter_info) { + } else if is_gl_to_metal_adapter_on_windows_in_parallels(adapter_info) { log::warn!("Deprioritizing integrated OpenGL Windows Parallels adapter."); AdapterSupport::SupportedWithIssues } else { diff --git a/crates/warpui/src/rendering/wgpu/resources_tests.rs b/crates/warpui/src/rendering/wgpu/resources_tests.rs index 68588d0d42d..0c79f54484f 100644 --- a/crates/warpui/src/rendering/wgpu/resources_tests.rs +++ b/crates/warpui/src/rendering/wgpu/resources_tests.rs @@ -40,9 +40,68 @@ fn test_is_unsupported_llvmpipe_adapter() { assert!(is_older_lavapipe_adapter(&unsupported_adapter_info)); } +/// Builds an [`wgpu::AdapterInfo`] with the fields our adapter selection logic looks at. +fn adapter_info( + name: &str, + driver: &str, + driver_info: &str, + backend: wgpu::Backend, + device_type: wgpu::DeviceType, +) -> wgpu::AdapterInfo { + wgpu::AdapterInfo { + name: name.to_owned(), + vendor: 0, + device: 0, + device_type, + driver: driver.to_owned(), + driver_info: driver_info.to_owned(), + backend, + device_pci_bus_id: "01:00.0".to_owned(), + subgroup_min_size: wgpu::MINIMUM_SUBGROUP_MIN_SIZE, + subgroup_max_size: wgpu::MAXIMUM_SUBGROUP_MAX_SIZE, + transient_saves_memory: Some(false), + limit_bucket: None, + } +} + +/// The adapter reported in https://github.com/warpdotdev/warp/issues/14577: every frame fails with +/// a validation error when rendering through Vulkan on Mesa 21.2.6. +fn intel_xe_tgl_gt2_vulkan_adapter_info(mesa_version: &str) -> wgpu::AdapterInfo { + adapter_info( + "Intel(R) Xe Graphics (TGL GT2)", + "Intel open-source Mesa driver", + &format!("Mesa {mesa_version}"), + wgpu::Backend::Vulkan, + wgpu::DeviceType::IntegratedGpu, + ) +} + +/// The healthy GL adapter enumerated alongside the Vulkan one in the same report. +fn intel_xe_tgl_gt2_gl_adapter_info(mesa_version: &str) -> wgpu::AdapterInfo { + adapter_info( + "Mesa Intel(R) Xe Graphics (TGL GT2)", + "", + &format!("4.6 (Core Profile) Mesa {mesa_version}"), + wgpu::Backend::Gl, + wgpu::DeviceType::IntegratedGpu, + ) +} + +/// Ranks adapter infos the same way the final (and dominant) sorting step in [`sort_adapters`] +/// does, so we can assert on selection order without a real GPU. +fn rank_by_support(adapter_infos: Vec) -> Vec { + let windowing_system = Some(windowing::System::X11 { + is_x_wayland: false, + }); + adapter_infos + .into_iter() + .sorted_by_key(|info| adapter_support(info, windowing_system, false)) + .collect_vec() +} + #[test] fn test_is_unsupported_intel_uhd_adapter() { - assert!(is_older_vulkan_intel_uhd_adapter(&wgpu::AdapterInfo { + assert!(is_older_vulkan_intel_mesa_adapter(&wgpu::AdapterInfo { name: String::from("Intel(R) HD Graphics 620 (KBL GT2)"), vendor: 0, device: 0, @@ -56,7 +115,7 @@ fn test_is_unsupported_intel_uhd_adapter() { transient_saves_memory: Some(false), limit_bucket: None, })); - assert!(!is_older_vulkan_intel_uhd_adapter(&wgpu::AdapterInfo { + assert!(!is_older_vulkan_intel_mesa_adapter(&wgpu::AdapterInfo { name: String::from("Intel(R) HD Graphics 620 (KBL GT2)"), vendor: 0, device: 0, @@ -71,7 +130,7 @@ fn test_is_unsupported_intel_uhd_adapter() { transient_saves_memory: Some(false), limit_bucket: None, })); - assert!(!is_older_vulkan_intel_uhd_adapter(&wgpu::AdapterInfo { + assert!(!is_older_vulkan_intel_mesa_adapter(&wgpu::AdapterInfo { name: String::from("Intel(R) HD Graphics 620 (KBL GT2)"), vendor: 0, device: 0, @@ -86,7 +145,7 @@ fn test_is_unsupported_intel_uhd_adapter() { transient_saves_memory: Some(false), limit_bucket: None, })); - assert!(is_older_vulkan_intel_uhd_adapter(&wgpu::AdapterInfo { + assert!(is_older_vulkan_intel_mesa_adapter(&wgpu::AdapterInfo { name: String::from("Intel(R) HD Graphics 620 (KBL GT2)"), vendor: 0, device: 0, @@ -101,7 +160,7 @@ fn test_is_unsupported_intel_uhd_adapter() { transient_saves_memory: Some(false), limit_bucket: None, })); - assert!(!is_older_vulkan_intel_uhd_adapter(&wgpu::AdapterInfo { + assert!(!is_older_vulkan_intel_mesa_adapter(&wgpu::AdapterInfo { name: String::from("Intel(R) HD Graphics 620 (KBL GT2)"), vendor: 0, device: 0, @@ -116,7 +175,7 @@ fn test_is_unsupported_intel_uhd_adapter() { transient_saves_memory: Some(false), limit_bucket: None, })); - assert!(is_older_vulkan_intel_uhd_adapter(&wgpu::AdapterInfo { + assert!(is_older_vulkan_intel_mesa_adapter(&wgpu::AdapterInfo { name: String::from("Intel(R) HD Graphics 620 (KBL GT2)"), vendor: 0, device: 0, @@ -132,3 +191,101 @@ fn test_is_unsupported_intel_uhd_adapter() { limit_bucket: None, })); } + +/// The Intel graphics family/GT tier in the adapter name must not affect the result: matching is +/// based on the Mesa driver version. See https://github.com/warpdotdev/warp/issues/14577. +#[test] +fn test_older_vulkan_intel_mesa_adapters_are_matched_regardless_of_family() { + for name in [ + "Intel(R) Xe Graphics (TGL GT2)", + "Intel(R) UHD Graphics (TGL GT1)", + "Intel(R) UHD Graphics (ICL GT1)", + "Intel(R) HD Graphics 620 (KBL GT2)", + "Intel(R) Graphics (ADL GT2)", + ] { + let info = adapter_info( + name, + "Intel open-source Mesa driver", + "Mesa 21.2.6", + wgpu::Backend::Vulkan, + wgpu::DeviceType::IntegratedGpu, + ); + assert!( + is_older_vulkan_intel_mesa_adapter(&info), + "expected {name} on Mesa 21.2.6 to be considered unsupported" + ); + } +} + +#[test] +fn test_non_mesa_and_non_intel_adapters_are_unaffected() { + // Windows Intel drivers aren't Mesa, so their version strings must not be parsed as Mesa + // versions. + assert!(!is_older_vulkan_intel_mesa_adapter(&adapter_info( + "Intel(R) Iris(R) Xe Graphics", + "Intel Corporation", + "Intel driver 31.0.101.5445", + wgpu::Backend::Vulkan, + wgpu::DeviceType::IntegratedGpu, + ))); + // Non-Intel Mesa drivers (e.g. RADV) are out of scope for this check. + assert!(!is_older_vulkan_intel_mesa_adapter(&adapter_info( + "AMD Radeon Graphics (RADV RENOIR)", + "radv", + "Mesa 21.2.6", + wgpu::Backend::Vulkan, + wgpu::DeviceType::IntegratedGpu, + ))); + // The GL adapter for the same Intel GPU renders fine and must stay fully supported. + assert!(!is_older_vulkan_intel_mesa_adapter( + &intel_xe_tgl_gt2_gl_adapter_info("21.2.6") + )); +} + +#[test] +fn test_intel_xe_tgl_gt2_prefers_gl_on_older_mesa() { + let vulkan = intel_xe_tgl_gt2_vulkan_adapter_info("21.2.6"); + let gl = intel_xe_tgl_gt2_gl_adapter_info("21.2.6"); + + assert_eq!( + adapter_support(&vulkan, None, false), + AdapterSupport::SupportedWithIssues + ); + assert_eq!(adapter_support(&gl, None, false), AdapterSupport::Supported); + + // The Vulkan adapter is enumerated first, but the GL adapter should win the ranking. + let ranked = rank_by_support(vec![vulkan, gl]); + assert_eq!(ranked[0].backend, wgpu::Backend::Gl); + assert_eq!(ranked[1].backend, wgpu::Backend::Vulkan); +} + +#[test] +fn test_intel_xe_tgl_gt2_is_used_on_newer_mesa() { + let vulkan = intel_xe_tgl_gt2_vulkan_adapter_info("24.0.2"); + let gl = intel_xe_tgl_gt2_gl_adapter_info("24.0.2"); + + assert!(!is_older_vulkan_intel_mesa_adapter(&vulkan)); + assert_eq!( + adapter_support(&vulkan, None, false), + AdapterSupport::Supported + ); + // With both adapters equally supported, the stability sort is a no-op and the earlier + // backend-priority sort (which prefers Vulkan on Linux) decides. + let ranked = rank_by_support(vec![vulkan, gl]); + assert_eq!(ranked[0].backend, wgpu::Backend::Vulkan); +} + +/// Deprioritizing is not filtering: when no GL adapter can present, the old Intel Mesa Vulkan +/// adapter is still the best (and only) candidate, so we must not rank it as `Unsupported`. +#[test] +fn test_intel_xe_tgl_gt2_is_still_used_without_a_gl_fallback() { + let vulkan = intel_xe_tgl_gt2_vulkan_adapter_info("21.2.6"); + let support = adapter_support(&vulkan, None, false); + + assert_eq!(support, AdapterSupport::SupportedWithIssues); + assert!(support < AdapterSupport::Unsupported); + + let ranked = rank_by_support(vec![vulkan]); + assert_eq!(ranked.len(), 1); + assert_eq!(ranked[0].backend, wgpu::Backend::Vulkan); +}