mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-10-13 23:08:16 +00:00
Linux: draw on the desktop's GPU, not always the discrete one (#164)
* Linux: draw on the desktop's GPU, not always the discrete one egui asks wgpu for the high-performance adapter. On a hybrid laptop in PRIME on-demand mode (Intel + NVIDIA, X11, GNOME) that is the NVIDIA GPU while the display server runs on the Intel one, so every frame is copied between the GPUs. During a resize the window then shows stale or garbled frames and can stop drawing until it is resized again. On Linux and the BSDs, ask for no power preference instead: wgpu then takes the first adapter Vulkan lists, and Mesa's device-select layer lists the display server's GPU first (or the one DRI_PRIME picks). Measured on an RTX 4060 + Intel RPL-S laptop: in on-demand mode the list starts with the Intel GPU, in `prime-select nvidia` mode with the NVIDIA one, so the launcher draws on whichever GPU drives the screens. WGPU_POWER_PREF still overrides it. Windows and macOS keep their current choice. Refs #69 * Linux GPU: keep wgpu's adapter order, but a software rasterizer last Without Mesa's device-select layer the Vulkan order follows the ICD files, and lavapipe can come before the real driver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 file changed
+45
-1
@@ -218,7 +218,38 @@ fn adapter_rank(backend: eframe::wgpu::Backend, device_type: eframe::wgpu::Devic
|
||||
(backend != Backend::Dx12, device)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
/// wgpu's adapter on Linux and the BSDs: the GPU the desktop runs on. egui asks for the
|
||||
/// high-performance GPU, which on a hybrid laptop in PRIME on-demand mode is the discrete one while
|
||||
/// the display server runs on the integrated one: every frame then crosses between the GPUs, and
|
||||
/// while the window is resized it shows stale or garbled frames and can stop drawing (issue #69).
|
||||
/// With no preference wgpu takes the first adapter Vulkan lists, and Mesa's device-select layer
|
||||
/// lists the display server's GPU first (or the one `DRI_PRIME` picks). Without that layer the
|
||||
/// order follows the ICD files, where lavapipe (`lvp_icd`) can sort before the real driver, so a
|
||||
/// software rasterizer only wins when nothing else can draw. `WGPU_POWER_PREF` (`low`, `high` or
|
||||
/// `none`) still overrides it, and then wgpu picks the adapter itself.
|
||||
#[cfg(not(any(windows, target_os = "macos")))]
|
||||
fn wgpu_options() -> eframe::WgpuConfiguration {
|
||||
use eframe::wgpu::{DeviceType, PowerPreference};
|
||||
let mut config = eframe::WgpuConfiguration::default();
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
|
||||
if let Some(preference) = PowerPreference::from_env() {
|
||||
setup.power_preference = preference;
|
||||
} else {
|
||||
setup.power_preference = PowerPreference::None;
|
||||
setup.native_adapter_selector = Some(Arc::new(|adapters, surface| {
|
||||
adapters
|
||||
.iter()
|
||||
.filter(|a| surface.is_none_or(|s| a.is_surface_supported(s)))
|
||||
.min_by_key(|a| a.get_info().device_type == DeviceType::Cpu)
|
||||
.cloned()
|
||||
.ok_or_else(|| "no graphics adapter can draw to the window".to_owned())
|
||||
}));
|
||||
}
|
||||
}
|
||||
config
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn wgpu_options() -> eframe::WgpuConfiguration {
|
||||
eframe::WgpuConfiguration::default()
|
||||
}
|
||||
@@ -970,4 +1001,17 @@ mod tests {
|
||||
assert!(adapter_rank(Backend::Dx12, discrete, false) < adapter_rank(Backend::Dx12, integrated, false));
|
||||
assert!(adapter_rank(Backend::Dx12, integrated, true) < adapter_rank(Backend::Dx12, discrete, true));
|
||||
}
|
||||
|
||||
#[cfg(not(any(windows, target_os = "macos")))]
|
||||
#[test]
|
||||
fn linux_draws_on_the_desktops_gpu_unless_told_otherwise() {
|
||||
use eframe::wgpu::PowerPreference;
|
||||
let config = wgpu_options();
|
||||
let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &config.wgpu_setup else {
|
||||
panic!("the launcher creates its own wgpu instance");
|
||||
};
|
||||
// egui would ask for the discrete GPU: on a PRIME laptop that's not the desktop's (issue #69).
|
||||
let expected = PowerPreference::from_env().unwrap_or(PowerPreference::None);
|
||||
assert_eq!(setup.power_preference, expected);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user