Merge PR #1644: fix(gpu): no popup when renderer falls back from DX12 at pro

This commit is contained in:
francoisgn
2026-10-22 22:31:16 +03:00
2 changed files with 36 additions and 14 deletions
+34 -13
View File
@@ -93,7 +93,6 @@ pub fn choose(files: &Files) -> Chosen {
let compiled = wgpu::Instance::enabled_backend_features();
let os = std::env::consts::OS;
let order = backend::window_renderer_order(forced, remembered, failed, os, compiled, true);
let mut notice = failed.map(|f| format!("The window could not start with its {} renderer last time.", f.name()));
let mut problems = Vec::new();
let chosen = if cfg!(windows) {
pick_probed(&order, &mut problems)
@@ -104,18 +103,7 @@ pub fn choose(files: &Files) -> Chosen {
Some((WindowRenderer::Wgpu(backend::window_backends()), None))
};
let (which, existing) = chosen.unwrap_or((WindowRenderer::Glow, None));
if !problems.is_empty() {
notice = Some(format!("{} {}", notice.unwrap_or_default(), problems.join(" ")).trim().to_string());
}
let notice = notice.map(|n| {
format!(
"{n} {app} now draws its window with {}. To choose another, start {app} with {var}=dx12, vulkan, gl or glow \
(see docs/gpu-pipeline.md → Troubleshooting).",
which.name(),
app = "LightCraft",
var = "LIGHTCRAFT_GPU_BACKEND",
)
});
let notice = user_notice(failed, forced, &problems, which);
log::info!("window: renderer {} (order {:?})", which.name(), order.iter().map(|r| r.name()).collect::<Vec<_>>());
let mut wgpu_options = base_options();
let renderer = match (which, existing) {
@@ -134,6 +122,25 @@ pub fn choose(files: &Files) -> Chosen {
Chosen { renderer, wgpu_options, which, notice }
}
/// What to tell the user about the window's renderer. A renderer that failed its probe is skipped
/// silently (it is logged, and the one that worked is remembered): the app works, so a pop-up with
/// wgpu's error only alarms (#1624). Shown: the last start died, or the forced renderer failed.
fn user_notice(failed: Option<WindowRenderer>, forced: Option<WindowRenderer>, problems: &[String], which: WindowRenderer) -> Option<String> {
let mut notice = failed.map(|f| format!("The window could not start with its {} renderer last time.", f.name()));
if forced.is_some() && !problems.is_empty() {
notice = Some(format!("{} {}", notice.unwrap_or_default(), problems.join(" ")).trim().to_string());
}
notice.map(|n| {
format!(
"{n} {app} now draws its window with {}. To choose another, start {app} with {var}=dx12, vulkan, gl or glow \
(see docs/gpu-pipeline.md → Troubleshooting).",
which.name(),
app = "LightCraft",
var = "LIGHTCRAFT_GPU_BACKEND",
)
})
}
/// eframe's defaults with the app's backends and DX12 shader compiler (issues #136, #471).
pub fn base_options() -> WgpuConfiguration {
let mut c = WgpuConfiguration::default();
@@ -269,6 +276,20 @@ mod tests {
let _ = std::fs::remove_dir_all(&d);
}
/// #1624: a renderer skipped by the probe (DX12 → Vulkan) is no pop-up; a died start or a
/// failed forced renderer still is.
#[test]
fn probe_fallback_is_silent() {
let (dx, vk) = (WindowRenderer::Wgpu(Backends::DX12), WindowRenderer::Wgpu(Backends::VULKAN));
let problems = vec!["The dx12 renderer failed (Validation Error).".to_string()];
assert_eq!(user_notice(None, None, &problems, vk), None);
assert_eq!(user_notice(None, None, &[], vk), None);
let forced = user_notice(None, Some(dx), &problems, vk).unwrap();
assert!(forced.starts_with("The dx12 renderer failed") && forced.contains("now draws its window with vulkan"), "{forced}");
let died = user_notice(Some(dx), None, &problems, vk).unwrap();
assert!(died.contains("last time") && !died.contains("Validation Error"), "{died}");
}
/// The crash report: a pipeline that fails validation must come back as an error, never as
/// wgpu's default panic. Needs an adapter; skipped where there is none (CI without a GPU).
#[test]
+2 -1
View File
@@ -105,7 +105,8 @@ or worked around with `LIGHTCRAFT_GPU_BACKEND`.
**The window's renderer and its fallback (Windows).** Before the window opens, each renderer is probed in
order: DX12, Vulkan, GL, then eframe's OpenGL renderer (glow). A probe creates a device and builds egui's
pipeline inside wgpu error scopes, so a driver that cannot compile egui's shaders ("The parameter is
incorrect. (0x80070057)" in `egui_pipeline`) is logged and skipped instead of killing the app. The renderer
incorrect. (0x80070057)" in `egui_pipeline`) is logged and skipped instead of killing the app; no pop-up
unless that renderer was forced (#1624). The renderer
that worked is remembered in the settings folder (`window-renderer`); a start that dies before the window is up
leaves `window-init.marker`, and the next start (relaunched automatically, at most 4 times) tries that
renderer last. `LIGHTCRAFT_GPU_BACKEND=dx12 | vulkan | gl | glow` (or `WGPU_BACKEND`) forces one; DX12 stays