Add a renderer escape hatch (wgpu default, glow fallback)
The desktop forces the wgpu/Vulkan renderer because glow/OpenGL crashes on NVIDIA + Wayland maximize. But on some systems wgpu creates the window and never presents a frame, so nothing appears. Keep wgpu the default but compile glow back in and let it be selected via `--renderer glow` or `YT_OFFLINE_RENDERER=glow` for those machines. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2692fa2c9e
commit
9ba375f7b1
4 changed files with 166 additions and 8 deletions
70
Cargo.lock
generated
70
Cargo.lock
generated
|
|
@ -744,6 +744,15 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cgl"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chacha20"
|
name = "chacha20"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
@ -1048,6 +1057,9 @@ dependencies = [
|
||||||
"egui-wgpu",
|
"egui-wgpu",
|
||||||
"egui-winit",
|
"egui-winit",
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
|
"glow 0.14.2",
|
||||||
|
"glutin",
|
||||||
|
"glutin-winit",
|
||||||
"image",
|
"image",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -1489,6 +1501,63 @@ dependencies = [
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glutin"
|
||||||
|
version = "0.32.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"cfg_aliases 0.2.1",
|
||||||
|
"cgl",
|
||||||
|
"dispatch2",
|
||||||
|
"glutin_egl_sys",
|
||||||
|
"glutin_glx_sys",
|
||||||
|
"glutin_wgl_sys",
|
||||||
|
"libloading",
|
||||||
|
"objc2 0.6.4",
|
||||||
|
"objc2-app-kit 0.3.2",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
"objc2-foundation 0.3.2",
|
||||||
|
"once_cell",
|
||||||
|
"raw-window-handle",
|
||||||
|
"wayland-sys",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
"x11-dl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glutin-winit"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg_aliases 0.2.1",
|
||||||
|
"glutin",
|
||||||
|
"raw-window-handle",
|
||||||
|
"winit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glutin_egl_sys"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2"
|
||||||
|
dependencies = [
|
||||||
|
"gl_generator",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glutin_glx_sys"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185"
|
||||||
|
dependencies = [
|
||||||
|
"gl_generator",
|
||||||
|
"x11-dl",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glutin_wgl_sys"
|
name = "glutin_wgl_sys"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
|
@ -2366,6 +2435,7 @@ dependencies = [
|
||||||
"bitflags 2.11.1",
|
"bitflags 2.11.1",
|
||||||
"block2 0.6.2",
|
"block2 0.6.2",
|
||||||
"objc2 0.6.4",
|
"objc2 0.6.4",
|
||||||
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ authors = ["InannaBeloved <anassaeneroi@pm.me>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Use the wgpu (Vulkan/Metal/DX) renderer instead of the default glow
|
# Default to the wgpu (Vulkan/Metal/DX) renderer instead of the default glow
|
||||||
# (OpenGL) one. NVIDIA + Wayland crashes the GL surface on window resize
|
# (OpenGL) one. NVIDIA + Wayland crashes the GL surface on window resize
|
||||||
# (Glutin EGL_BAD_ALLOC / OutOfMemory on maximize); wgpu's Vulkan path
|
# (Glutin EGL_BAD_ALLOC / OutOfMemory on maximize); wgpu's Vulkan path
|
||||||
# reconfigures the swapchain cleanly. We drop the `glow` default feature
|
# reconfigures the swapchain cleanly. Keep glow compiled in as an escape
|
||||||
# and keep the rest (accesskit, fonts, wayland, x11).
|
# hatch for machines where wgpu/Vulkan creates a window but never presents
|
||||||
eframe = { version = "0.29", default-features = false, features = ["accesskit", "default_fonts", "wayland", "x11", "wgpu"] }
|
# a frame (`YT_OFFLINE_RENDERER=glow` or `--renderer glow`).
|
||||||
|
eframe = { version = "0.29", default-features = false, features = ["accesskit", "default_fonts", "wayland", "x11", "wgpu", "glow"] }
|
||||||
image = { version = "0.25", default-features = false, features = ["webp", "jpeg", "png"] }
|
image = { version = "0.25", default-features = false, features = ["webp", "jpeg", "png"] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,27 @@ handles the resize cleanly. Make sure you have a working Vulkan driver
|
||||||
(`vulkan-icd-loader` + your GPU's Vulkan package), which any desktop with
|
(`vulkan-icd-loader` + your GPU's Vulkan package), which any desktop with
|
||||||
working graphics already has.
|
working graphics already has.
|
||||||
|
|
||||||
|
## The desktop window opens but stays blank
|
||||||
|
|
||||||
|
The desktop defaults to the wgpu/Vulkan renderer. On some systems with a
|
||||||
|
broken Vulkan stack, the OS can create the window while wgpu never
|
||||||
|
presents a frame. Try the OpenGL renderer:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
YT_OFFLINE_RENDERER=glow yt-offline
|
||||||
|
```
|
||||||
|
|
||||||
|
or:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yt-offline --renderer glow
|
||||||
|
```
|
||||||
|
|
||||||
|
If that works, update/reinstall your Vulkan driver later and switch back
|
||||||
|
to the default renderer. On NVIDIA + Wayland, prefer the default wgpu
|
||||||
|
renderer when possible because OpenGL has historically crashed on window
|
||||||
|
maximize.
|
||||||
|
|
||||||
## The web UI looks like an old version after an upgrade
|
## The web UI looks like an old version after an upgrade
|
||||||
|
|
||||||
The SPA is served `Cache-Control: no-store`, so a hard reload
|
The SPA is served `Cache-Control: no-store`, so a hard reload
|
||||||
|
|
|
||||||
74
src/main.rs
74
src/main.rs
|
|
@ -36,6 +36,33 @@ mod vtt;
|
||||||
mod web;
|
mod web;
|
||||||
mod ytdlp_bin;
|
mod ytdlp_bin;
|
||||||
|
|
||||||
|
fn renderer_from_name(requested: Option<&str>) -> eframe::Renderer {
|
||||||
|
match requested.map(|s| s.trim().to_ascii_lowercase()).as_deref() {
|
||||||
|
Some("glow" | "opengl" | "gl") => eframe::Renderer::Glow,
|
||||||
|
Some("wgpu" | "vulkan" | "vk") | None => eframe::Renderer::Wgpu,
|
||||||
|
Some(name) => {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: unknown renderer '{name}' (expected 'wgpu' or 'glow'); using wgpu."
|
||||||
|
);
|
||||||
|
eframe::Renderer::Wgpu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn renderer_from_args(args: &[String]) -> eframe::Renderer {
|
||||||
|
let requested = args
|
||||||
|
.iter()
|
||||||
|
.position(|a| a == "--renderer")
|
||||||
|
.and_then(|pos| args.get(pos + 1).map(String::as_str));
|
||||||
|
|
||||||
|
if requested.is_some() {
|
||||||
|
renderer_from_name(requested)
|
||||||
|
} else {
|
||||||
|
let env_renderer = std::env::var("YT_OFFLINE_RENDERER").ok();
|
||||||
|
renderer_from_name(env_renderer.as_deref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> eframe::Result<()> {
|
fn main() -> eframe::Result<()> {
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
|
||||||
|
|
@ -82,10 +109,11 @@ fn main() -> eframe::Result<()> {
|
||||||
.with_inner_size([1280.0, 820.0])
|
.with_inner_size([1280.0, 820.0])
|
||||||
.with_min_inner_size([800.0, 500.0])
|
.with_min_inner_size([800.0, 500.0])
|
||||||
.with_title("yt-offline"),
|
.with_title("yt-offline"),
|
||||||
// Force the wgpu (Vulkan) renderer. The default glow/OpenGL path
|
// Default to wgpu (Vulkan): the glow/OpenGL path crashes on some
|
||||||
// crashes on NVIDIA + Wayland when the window is maximized
|
// NVIDIA + Wayland maximizes (Glutin EGL_BAD_ALLOC). Keep a launch
|
||||||
// (Glutin EGL_BAD_ALLOC). wgpu reconfigures the swapchain cleanly.
|
// escape hatch for systems where Vulkan/wgpu opens a blank window:
|
||||||
renderer: eframe::Renderer::Wgpu,
|
// `YT_OFFLINE_RENDERER=glow yt-offline` or `yt-offline --renderer glow`.
|
||||||
|
renderer: renderer_from_args(&args),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
|
|
@ -94,3 +122,41 @@ fn main() -> eframe::Result<()> {
|
||||||
Box::new(|cc| Ok(Box::new(app::App::new(cc, tray)))),
|
Box::new(|cc| Ok(Box::new(app::App::new(cc, tray)))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn renderer_name_accepts_default_and_aliases() {
|
||||||
|
assert_eq!(super::renderer_from_name(None), eframe::Renderer::Wgpu);
|
||||||
|
assert_eq!(
|
||||||
|
super::renderer_from_name(Some("wgpu")),
|
||||||
|
eframe::Renderer::Wgpu
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
super::renderer_from_name(Some("vulkan")),
|
||||||
|
eframe::Renderer::Wgpu
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
super::renderer_from_name(Some("glow")),
|
||||||
|
eframe::Renderer::Glow
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
super::renderer_from_name(Some("opengl")),
|
||||||
|
eframe::Renderer::Glow
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
super::renderer_from_name(Some("unknown")),
|
||||||
|
eframe::Renderer::Wgpu
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn renderer_arg_overrides_env_parser_path() {
|
||||||
|
let args = vec![
|
||||||
|
"yt-offline".to_string(),
|
||||||
|
"--renderer".to_string(),
|
||||||
|
"gl".to_string(),
|
||||||
|
];
|
||||||
|
assert_eq!(super::renderer_from_args(&args), eframe::Renderer::Glow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue