Better graphics backend fallback

This attempts the following in order:
- wgpu with user-selected backend
- wgpu with automatic backend
- glow (fallback OpenGL backend)

This should eliminate most issues
where objdiff fails to launch.
This commit is contained in:
Luke Street 2024-08-11 13:33:10 -06:00
parent 09cc9952df
commit 952b6a63c3
4 changed files with 105 additions and 29 deletions

View File

@ -18,7 +18,7 @@ name = "objdiff"
path = "src/main.rs" path = "src/main.rs"
[features] [features]
default = ["wgpu", "wsl"] default = ["glow", "wgpu", "wsl"]
glow = ["eframe/glow"] glow = ["eframe/glow"]
wgpu = ["eframe/wgpu", "dep:wgpu"] wgpu = ["eframe/wgpu", "dep:wgpu"]
wsl = [] wsl = []

View File

@ -275,7 +275,7 @@ impl App {
#[cfg(feature = "glow")] #[cfg(feature = "glow")]
if let Some(gl) = &cc.gl { if let Some(gl) = &cc.gl {
use eframe::glow::HasContext; use eframe::glow::HasContext;
app.view_state.graphics_state.active_backend = "OpenGL".to_string(); app.view_state.graphics_state.active_backend = "OpenGL (Fallback)".to_string();
app.view_state.graphics_state.active_device = app.view_state.graphics_state.active_device =
unsafe { gl.get_parameter_string(0x1F01) }; // GL_RENDERER unsafe { gl.get_parameter_string(0x1F01) }; // GL_RENDERER
} }

View File

@ -11,6 +11,7 @@ mod views;
use std::{ use std::{
path::PathBuf, path::PathBuf,
process::ExitCode,
rc::Rc, rc::Rc,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -37,7 +38,7 @@ const APP_NAME: &str = "objdiff";
// When compiling natively: // When compiling natively:
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn main() { fn main() -> ExitCode {
// Log to stdout (if you run with `RUST_LOG=debug`). // Log to stdout (if you run with `RUST_LOG=debug`).
tracing_subscriber::fmt::init(); tracing_subscriber::fmt::init();
@ -48,7 +49,6 @@ fn main() {
let app_path = std::env::current_exe().ok(); let app_path = std::env::current_exe().ok();
let exec_path: Rc<Mutex<Option<PathBuf>>> = Rc::new(Mutex::new(None)); let exec_path: Rc<Mutex<Option<PathBuf>>> = Rc::new(Mutex::new(None));
let exec_path_clone = exec_path.clone();
let mut native_options = let mut native_options =
eframe::NativeOptions { follow_system_theme: false, ..Default::default() }; eframe::NativeOptions { follow_system_theme: false, ..Default::default() };
match load_icon() { match load_icon() {
@ -56,7 +56,7 @@ fn main() {
native_options.viewport.icon = Some(Arc::new(data)); native_options.viewport.icon = Some(Arc::new(data));
} }
Err(e) => { Err(e) => {
log::warn!("Failed to load application icon: {}", e); log::warn!("Failed to load application icon: {e:?}");
} }
} }
let mut graphics_config = GraphicsConfig::default(); let mut graphics_config = GraphicsConfig::default();
@ -69,7 +69,7 @@ fn main() {
} }
Ok(None) => {} Ok(None) => {}
Err(e) => { Err(e) => {
log::error!("Failed to load native config: {:?}", e); log::error!("Failed to load native config: {e:?}");
} }
} }
graphics_config_path = Some(config_path); graphics_config_path = Some(config_path);
@ -87,6 +87,104 @@ fn main() {
}; };
} }
} }
let mut eframe_error = None;
if let Err(e) = run_eframe(
native_options.clone(),
utc_offset,
exec_path.clone(),
app_path.clone(),
graphics_config.clone(),
graphics_config_path.clone(),
) {
eframe_error = Some(e);
}
#[cfg(feature = "wgpu")]
if let Some(e) = eframe_error {
// Attempt to relaunch using wgpu auto backend if the desired backend failed
#[allow(unused_mut)]
let mut should_relaunch = graphics_config.desired_backend != GraphicsBackend::Auto;
#[cfg(feature = "glow")]
{
// If the desired backend is OpenGL, we should try to relaunch using the glow renderer
should_relaunch &= graphics_config.desired_backend != GraphicsBackend::OpenGL;
}
if should_relaunch {
log::warn!("Failed to launch application: {e:?}");
log::warn!("Attempting to relaunch using auto-detected backend");
native_options.wgpu_options.supported_backends = Default::default();
if let Err(e) = run_eframe(
native_options.clone(),
utc_offset,
exec_path.clone(),
app_path.clone(),
graphics_config.clone(),
graphics_config_path.clone(),
) {
eframe_error = Some(e);
} else {
eframe_error = None;
}
} else {
eframe_error = Some(e);
}
}
#[cfg(all(feature = "wgpu", feature = "glow"))]
if let Some(e) = eframe_error {
// Attempt to relaunch using the glow renderer if the wgpu backend failed
log::warn!("Failed to launch application: {e:?}");
log::warn!("Attempting to relaunch using fallback OpenGL backend");
native_options.renderer = eframe::Renderer::Glow;
if let Err(e) = run_eframe(
native_options,
utc_offset,
exec_path.clone(),
app_path,
graphics_config,
graphics_config_path,
) {
eframe_error = Some(e);
} else {
eframe_error = None;
}
}
if let Some(e) = eframe_error {
log::error!("Failed to launch application: {e:?}");
return ExitCode::FAILURE;
}
// Attempt to relaunch application from the updated path
if let Ok(mut guard) = exec_path.lock() {
if let Some(path) = guard.take() {
cfg_if! {
if #[cfg(unix)] {
let e = exec::Command::new(path)
.args(&std::env::args().collect::<Vec<String>>())
.exec();
log::error!("Failed to relaunch: {e:?}");
return ExitCode::FAILURE;
} else {
let result = std::process::Command::new(path)
.args(std::env::args())
.spawn();
if let Err(e) = result {
log::error!("Failed to relaunch: {e:?}");
return ExitCode::FAILURE;
}
}
}
}
};
ExitCode::SUCCESS
}
fn run_eframe(
native_options: eframe::NativeOptions,
utc_offset: UtcOffset,
exec_path_clone: Rc<Mutex<Option<PathBuf>>>,
app_path: Option<PathBuf>,
graphics_config: GraphicsConfig,
graphics_config_path: Option<PathBuf>,
) -> Result<(), eframe::Error> {
eframe::run_native( eframe::run_native(
APP_NAME, APP_NAME,
native_options, native_options,
@ -101,28 +199,6 @@ fn main() {
)) ))
}), }),
) )
.expect("Failed to run eframe application");
// Attempt to relaunch application from the updated path
if let Ok(mut guard) = exec_path.lock() {
if let Some(path) = guard.take() {
cfg_if! {
if #[cfg(unix)] {
let result = exec::Command::new(path)
.args(&std::env::args().collect::<Vec<String>>())
.exec();
log::error!("Failed to relaunch: {result:?}");
} else {
let result = std::process::Command::new(path)
.args(std::env::args())
.spawn();
if let Err(e) = result {
log::error!("Failed to relaunch: {:?}", e);
}
}
}
}
};
} }
// when compiling to web using trunk. // when compiling to web using trunk.

View File

@ -36,7 +36,7 @@ pub enum GraphicsBackend {
OpenGL, OpenGL,
} }
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct GraphicsConfig { pub struct GraphicsConfig {
#[serde(default)] #[serde(default)]
pub desired_backend: GraphicsBackend, pub desired_backend: GraphicsBackend,