Issue #136: applying the GPU setting never waits for the device on the UI thread

The first frame ran `app.gpu {enabled}` and its reply called `gpu::available()`, which waits
for the device that `warm_up` is creating off the UI thread: the window's first frame stalled
for the whole device and kernel setup (8-11 s under load). `app.gpu` takes `wait: false`, which
answers at once while the device is still being created (available/adapter/reason null), and
the UI uses it. `a_slow_photos_import_never_blocks_the_window` caught it (8.8 s -> 0.9 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
OneSlips
2026-10-22 19:17:02 +10:00
co-authored by Claude Opus 5.5
parent 31ee2643cf
commit 6376b1cebf
2 changed files with 13 additions and 2 deletions
+12 -1
View File
@@ -226,10 +226,21 @@ pub fn specs() -> Vec<CommandSpec> {
"versions": ph.versions.iter().map(|v| json!({"name": v.name, "created": v.created})).collect::<Vec<_>>(),
}))
}),
cmd!(query "app.gpu", "GPU Rendering", [], None, "{enabled?: bool} — allow/forbid GPU rendering (CPU fallback; LIGHTCRAFT_GPU=0 forbids it for the process); returns {enabled, available, adapter, reason (why the GPU is off), lastFallback (latest render redone on the CPU, and why)}", always, |_, p| {
cmd!(query "app.gpu", "GPU Rendering", [], None, "{enabled?: bool, wait?: bool} — allow/forbid GPU rendering (CPU fallback; LIGHTCRAFT_GPU=0 forbids it for the process); returns {enabled, available, adapter, reason (why the GPU is off), lastFallback (latest render redone on the CPU, and why)}. wait: false never waits for a device still being created (available, adapter and reason are then null)", always, |_, p| {
if let Some(on) = p.get("enabled").and_then(Value::as_bool) {
lightcraft_gpu::set_enabled(on);
}
// the UI applies the setting on its first frame: it must not wait seconds for the
// device there (issue #136; `warm_up` creates it off the UI thread)
if p.get("wait").and_then(Value::as_bool) == Some(false) && !lightcraft_gpu::ready() {
return Ok(json!({
"enabled": lightcraft_gpu::enabled(),
"available": null,
"adapter": null,
"reason": null,
"lastFallback": lightcraft_gpu::last_fallback(),
}));
}
Ok(json!({
"enabled": lightcraft_gpu::enabled(),
"available": lightcraft_gpu::available(),
+1 -1
View File
@@ -1263,7 +1263,7 @@ impl LightcraftApp {
fn apply_settings(&mut self, ctx: &egui::Context) {
if self.gpu_applied != Some(self.ui.settings.gpu) {
self.gpu_applied = Some(self.ui.settings.gpu);
let _ = self.session.execute("app.gpu", &serde_json::json!({"enabled": self.ui.settings.gpu}));
let _ = self.session.execute("app.gpu", &serde_json::json!({"enabled": self.ui.settings.gpu, "wait": false}));
// GPU device + kernels off the UI thread, once the window is up and only when GPU
// rendering is on: a broken driver must not keep the window from appearing (issue #136)
if self.ui.settings.gpu {