From f47fb8607722179a1a6494337a7b0d2f36705e45 Mon Sep 17 00:00:00 2001 From: dev-null-undefined Date: Tue, 13 Oct 2026 01:24:26 +0200 Subject: [PATCH] LR-BEHAV-GPU: say once when no GPU is found, instead of quietly rendering on the CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With GPU rendering on and no graphics adapter at all (wgpu: "no GPU adapter among …", e.g. no Vulkan loader: a `cargo run` outside `nix develop` on NixOS), every render ran on the CPU, much slower, and only Settings ▸ Performance, Help ▸ System Info and `perf.gpuReason` said why. The desktop app now queues one start-up notice per session once the device has been tried (`gpu::ready()`, never blocking): "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.", on Linux with "On NixOS, start it from `nix develop`." (→, not ▸: no installed font paints ▸.) `panels::notices::gpu_notice` decides from the reason: nothing when the GPU was turned off (preference, LIGHTCRAFT_GPU, LIGHTCRAFT_GPU_BACKEND=off), only a software adapter was skipped, or it failed later. Headless sessions and tests never show it (`app.gpu_notice` is set by the desktop app only). Translated in all nine catalogs; one README sentence in the Nix section. Co-Authored-By: Claude --- README.md | 3 ++ apps/lightcraft/src/main.rs | 1 + crates/ui-egui/locales/de.json | 4 ++- crates/ui-egui/locales/es.json | 4 ++- crates/ui-egui/locales/fr.json | 4 ++- crates/ui-egui/locales/ja.json | 4 ++- crates/ui-egui/locales/pt-br.json | 4 ++- crates/ui-egui/locales/ru.json | 4 ++- crates/ui-egui/locales/uk.json | 4 ++- crates/ui-egui/locales/zh-hans.json | 4 ++- crates/ui-egui/locales/zh-hant.json | 4 ++- crates/ui-egui/src/lib.rs | 4 +++ crates/ui-egui/src/panels/notices.rs | 52 +++++++++++++++++++++++++++- docs/parity-checklist.md | 2 +- docs/whats-new.md | 7 ++++ 15 files changed, 94 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8884f2bd3..30a6f1a7b 100644 --- a/README.md +++ b/README.md @@ -409,6 +409,9 @@ nix build github:storytold/lightcraft # → ./result/bin/{light nix develop github:storytold/lightcraft # rust toolchain + native deps + fonts ``` +On NixOS, run a `cargo` build from `nix develop`: outside it the app can't find `libvulkan.so.1`, finds no GPU and +renders on the CPU, much more slowly (it says so once at start-up). `nix run` and `nix build` set the path themselves. + In a flake configuration (NixOS, home-manager, nix-darwin): ```nix diff --git a/apps/lightcraft/src/main.rs b/apps/lightcraft/src/main.rs index c9b9696e1..170604ccd 100644 --- a/apps/lightcraft/src/main.rs +++ b/apps/lightcraft/src/main.rs @@ -842,6 +842,7 @@ fn main() -> eframe::Result { app.notices.extend(prefs_warning); app.notices.extend(launch_notices); app.notices.extend(window_notice); + app.gpu_notice = true; // what's on disk now: only changes are written let writer = PrefsWriter { path: if in_memory { None } else { prefs_path() }, diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index 10cc7e0ed..63149650b 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -2109,5 +2109,7 @@ "Adding to Apple Photos…": "Wird zu Apple Fotos hinzugefügt…", "not added to Apple Photos (cancelled)": "nicht zu Apple Fotos hinzugefügt (abgebrochen)", "The first time, macOS asks whether LightCraft may control Photos.": "Beim ersten Mal fragt macOS, ob LightCraft Fotos steuern darf.", - "Adding to Apple Photos": "Wird zu Apple Fotos hinzugefügt" + "Adding to Apple Photos": "Wird zu Apple Fotos hinzugefügt", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "Kein Grafikprozessor gefunden: LightCraft rendert auf der CPU, was viel langsamer ist. Details unter Hilfe → Systeminformationen.", + "On NixOS, start it from `nix develop`.": "Unter NixOS starten Sie es aus `nix develop`." } diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index ff672e88d..fc5dee59f 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -1951,5 +1951,7 @@ "Adding to Apple Photos…": "Añadiendo a Fotos de Apple…", "not added to Apple Photos (cancelled)": "no se añadieron a Fotos de Apple (cancelado)", "The first time, macOS asks whether LightCraft may control Photos.": "La primera vez, macOS pregunta si LightCraft puede controlar Fotos.", - "Adding to Apple Photos": "Añadiendo a Fotos de Apple" + "Adding to Apple Photos": "Añadiendo a Fotos de Apple", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "No se encontró ningún procesador gráfico: LightCraft renderiza en la CPU, lo que es mucho más lento. Detalles en Ayuda → Información del sistema.", + "On NixOS, start it from `nix develop`.": "En NixOS, inícielo desde `nix develop`." } diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index f7c469ffd..259b694a2 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -1951,5 +1951,7 @@ "Adding to Apple Photos…": "Ajout à Apple Photos…", "not added to Apple Photos (cancelled)": "non ajouté à Apple Photos (annulé)", "The first time, macOS asks whether LightCraft may control Photos.": "La première fois, macOS demande si LightCraft peut contrôler Photos.", - "Adding to Apple Photos": "Ajout à Apple Photos" + "Adding to Apple Photos": "Ajout à Apple Photos", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "Aucun processeur graphique trouvé : LightCraft effectue le rendu sur le processeur, ce qui est beaucoup plus lent. Détails dans Aide → Informations système.", + "On NixOS, start it from `nix develop`.": "Sous NixOS, lancez-le depuis `nix develop`." } diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index 9b9ae4c35..e51b0f8a2 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -1953,5 +1953,7 @@ "Adding to Apple Photos…": "Appleの写真に追加中…", "not added to Apple Photos (cancelled)": "Appleの写真には追加されませんでした(キャンセル)", "The first time, macOS asks whether LightCraft may control Photos.": "初回は、LightCraftに写真の操作を許可するかmacOSが確認します。", - "Adding to Apple Photos": "Appleの写真に追加中" + "Adding to Apple Photos": "Appleの写真に追加中", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "グラフィックプロセッサが見つかりません。LightCraftはCPUで描画するため、かなり遅くなります。詳細は「ヘルプ → システム情報」を参照してください。", + "On NixOS, start it from `nix develop`.": "NixOSでは `nix develop` から起動してください。" } diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index 9c16f1110..daee81957 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -1951,5 +1951,7 @@ "Adding to Apple Photos…": "Adicionando ao Fotos da Apple…", "not added to Apple Photos (cancelled)": "não adicionadas ao Fotos da Apple (cancelado)", "The first time, macOS asks whether LightCraft may control Photos.": "Na primeira vez, o macOS pergunta se o LightCraft pode controlar o Fotos.", - "Adding to Apple Photos": "Adicionando ao Fotos da Apple" + "Adding to Apple Photos": "Adicionando ao Fotos da Apple", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "Nenhum processador gráfico encontrado: o LightCraft renderiza na CPU, o que é muito mais lento. Detalhes em Ajuda → Informações do sistema.", + "On NixOS, start it from `nix develop`.": "No NixOS, inicie-o a partir de `nix develop`." } diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index a84297a05..cfe182aa6 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -2143,5 +2143,7 @@ "Adding to Apple Photos…": "Добавление в Apple Фото…", "not added to Apple Photos (cancelled)": "не добавлено в Apple Фото (отменено)", "The first time, macOS asks whether LightCraft may control Photos.": "В первый раз macOS спросит, может ли LightCraft управлять приложением «Фото».", - "Adding to Apple Photos": "Добавление в Apple Фото" + "Adding to Apple Photos": "Добавление в Apple Фото", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "Графический процессор не найден: LightCraft выполняет рендеринг на CPU, а это намного медленнее. Подробности: Справка → Сведения о системе.", + "On NixOS, start it from `nix develop`.": "В NixOS запускайте его из `nix develop`." } diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index 839de65f7..e409aaa6b 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -2145,5 +2145,7 @@ "Adding to Apple Photos…": "Додавання до Apple Фото…", "not added to Apple Photos (cancelled)": "не додано до Apple Фото (скасовано)", "The first time, macOS asks whether LightCraft may control Photos.": "Першого разу macOS запитає, чи може LightCraft керувати програмою «Фото».", - "Adding to Apple Photos": "Додавання до Apple Фото" + "Adding to Apple Photos": "Додавання до Apple Фото", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "Графічний процесор не знайдено: LightCraft виконує рендеринг на ЦП, а це набагато повільніше. Докладніше: Довідка → Інформація про систему.", + "On NixOS, start it from `nix develop`.": "У NixOS запускайте його з `nix develop`." } diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index 2b48b8e9b..a807797be 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -1989,5 +1989,7 @@ "Adding to Apple Photos…": "正在添加到 Apple 照片…", "not added to Apple Photos (cancelled)": "未添加到 Apple 照片(已取消)", "The first time, macOS asks whether LightCraft may control Photos.": "首次使用时,macOS 会询问是否允许 LightCraft 控制“照片”。", - "Adding to Apple Photos": "正在添加到 Apple 照片" + "Adding to Apple Photos": "正在添加到 Apple 照片", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "未找到图形处理器:LightCraft 改用 CPU 渲染,速度会慢很多。详情见“帮助 → 系统信息”。", + "On NixOS, start it from `nix develop`.": "在 NixOS 上,请从 `nix develop` 启动。" } diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index 0e81c6e92..b097e4a76 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -1951,5 +1951,7 @@ "Adding to Apple Photos…": "正在加入 Apple 照片…", "not added to Apple Photos (cancelled)": "未加入 Apple 照片(已取消)", "The first time, macOS asks whether LightCraft may control Photos.": "第一次使用時,macOS 會詢問是否允許 LightCraft 控制「照片」。", - "Adding to Apple Photos": "正在加入 Apple 照片" + "Adding to Apple Photos": "正在加入 Apple 照片", + "No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.": "找不到圖形處理器:LightCraft 改用 CPU 算繪,速度會慢很多。詳情請見「說明 → 系統資訊」。", + "On NixOS, start it from `nix develop`.": "在 NixOS 上,請從 `nix develop` 啟動。" } diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 9a387c77c..52ebf23a1 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -377,6 +377,9 @@ pub struct LightcraftApp { pub window_is_fullscreen: bool, /// The GPU preference last applied (`app.gpu`), to apply Settings changes once. gpu_applied: Option, + /// Say once, when the GPU device has been tried, that no graphics processor was found + /// ([`panels::notices::gpu_notice`]). The desktop app sets it; headless sessions and tests don't. + pub gpu_notice: bool, /// The memory budget setting last applied (MB, 0 = automatic). memory_applied: Option, /// The display profile setting last applied (`app.displayProfile`). @@ -459,6 +462,7 @@ impl LightcraftApp { hover_preview: None, window_is_fullscreen: false, gpu_applied: None, + gpu_notice: false, memory_applied: None, display_applied: None, display_error: None, diff --git a/crates/ui-egui/src/panels/notices.rs b/crates/ui-egui/src/panels/notices.rs index 619efe1d0..016323e95 100644 --- a/crates/ui-egui/src/panels/notices.rs +++ b/crates/ui-egui/src/panels/notices.rs @@ -8,10 +8,36 @@ use crate::theme::Tokens; use crate::widgets::register; use crate::{LightcraftApp, QuitPrompt}; -/// Collect the library's settings-file warnings (each is shown once). +/// Collect the library's settings-file warnings (each is shown once), and the no-GPU notice once the GPU device has +/// been tried. pub fn logic(app: &mut LightcraftApp) { let new = app.session.take_library_warnings(); app.notices.extend(new); + use lightcraft_engine::gpu; + if app.gpu_notice && app.gpu_applied == Some(true) && gpu::ready() { + app.gpu_notice = false; + if !gpu::available() { + app.notices.extend(gpu_notice(gpu::unavailable_reason().as_deref(), app.ui.settings.gpu)); + } + } +} + +/// What to tell the user when GPU rendering is on (`enabled`) but the GPU could not be used for `reason`: only when no +/// graphics adapter was found at all ("no GPU adapter among …", e.g. no Vulkan loader on Linux), which makes every +/// render much slower without saying so. Nothing when it was turned off (preference, `LIGHTCRAFT_GPU`), a software +/// adapter was skipped, or it failed later; Settings ▸ Performance and Help ▸ System Info show those. +pub fn gpu_notice(reason: Option<&str>, enabled: bool) -> Option { + if !enabled || !reason?.starts_with("no GPU adapter") { + return None; + } + let mut text = + crate::i18n::tr("No graphics processor found: LightCraft renders on the CPU, which is much slower. Details in Help → System Info.") + .to_string(); + if cfg!(target_os = "linux") { + text.push(' '); + text.push_str(crate::i18n::tr("On NixOS, start it from `nix develop`.")); + } + Some(text) } /// The window may close now (`true`), or the quit prompt is shown (`false`). Running tasks that @@ -143,3 +169,27 @@ pub fn show(app: &mut LightcraftApp, ctx: &egui::Context) { } } } + +#[cfg(test)] +mod tests { + use super::gpu_notice; + + #[test] + fn the_gpu_notice_is_only_for_a_missing_adapter() { + let none = "no GPU adapter among Backends(VULKAN | GL) (No suitable graphics adapter found)"; + let text = gpu_notice(Some(none), true).expect("no adapter: say so"); + assert!(text.starts_with("No graphics processor found") && text.contains("System Info"), "{text}"); + assert_eq!(text.contains("nix develop"), cfg!(target_os = "linux"), "{text}"); + assert_eq!(gpu_notice(Some(none), false), None, "the preference is off"); + for reason in [ + "disabled by LIGHTCRAFT_GPU=0", + "disabled by LIGHTCRAFT_GPU_BACKEND=off", + "disabled by the GPU rendering preference (app.gpu)", + "software adapter (llvmpipe (LLVM 19.1.7, 256 bits)) skipped: the CPU pipeline is faster", + "stopped after a GPU failure: device lost", + ] { + assert_eq!(gpu_notice(Some(reason), true), None, "{reason}"); + } + assert_eq!(gpu_notice(None, true), None, "the GPU is in use"); + } +} diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 77ae26e4c..dea72e5db 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -457,7 +457,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts). | LR-BEHAV-BG-TASKS | Background tasks | P0 | ✅ | `cmd:activity.list`, `cmd:activity.cancel`, `crates/engine/src/activity.rs`, `crates/ui-egui/src/panels/activity.rs`, `docs/background-tasks.md`, `crates/preview/src/lib.rs` (`JobPool`) | renders off the UI thread; exports run several photos of a batch side by side (`export_parallelism`, memory-gated; files, names and order as one at a time, #496); one activity stack in the top-left corner under the top bar, as in Lightroom Classic (issue #345): imports, folder scans, exports (and the contact sheet PDF), Synchronize Folder (its scan and its run), Build / Smart Previews, Lightroom catalog inspect / import, Photo Merge, model downloads (SAM 3, face, AI Denoise), the face scan, AI Denoise and Find Missing Photos each show a row (name, progress bar or a sweep while the amount isn't known, count and current item) once 0.5 s old, three rows then "+N more"; ✕ cancels the jobs that can stop ("Stopping…" until they do); quitting asks while a cancellable task runs; agents and `ui.inspect` (`activity`) see the same list. No pause (Lightroom can pause some tasks) | | LR-BEHAV-OFFLINE | Offline editing | P1 | ✅ | | local-first: everything works offline | | LR-BEHAV-WEB-SAFETY | Library safety in the browser build | P1 | 🟡 | `cmd:file.backupLibrary`, `cmd:file.restoreLibrary`, `apps/lightcraft-web/src/safety.rs`, `apps/lightcraft-web/src/backup.rs`, `apps/lightcraft-web/src/files.rs` | web only (experimental): Back Up Library (zip of the catalog and every stored original) and a non-destructive Restore; failed saves show as unsaved and are retried; a photo that can't be stored isn't added; one tab per library (Web Locks); notices for storage that isn't persistent and for a library that can't open; `?reset` asks first; a panic shows a message. Missing: `?safe` start, deleting originals of removed photos, zip64 (backups > 4 GB) | -| LR-BEHAV-GPU | GPU acceleration | P0 | ✅ | `crates/gpu/src/render.rs`, `cmd:app.gpu`, `docs/gpu-pipeline.md` | CPU fallback per render on device limits, out of memory, device errors / loss, incomplete or black results (`perf.gpuReason`, `perf.gpuFallback`; each render reports its own reason — `lightcraft_gpu::try_render`, `gpuFallback` per exported file — issue #675); short submissions for slow iGPUs; backend choice (DX12 only on Windows, `LIGHTCRAFT_GPU_BACKEND` / `WGPU_BACKEND`), device created after the window opens, crash sentinel (issue #136); quitting waits (up to 2 s) for renders in flight and starts no new GPU work, so none is inside the driver when the process exits (`crates/gpu/src/exit.rs`, issue #620; seen crashing only on Linux + NVIDIA, other drivers unverified); no tiling beyond the buffer limit (CPU) | +| LR-BEHAV-GPU | GPU acceleration | P0 | ✅ | `crates/gpu/src/render.rs`, `cmd:app.gpu`, `docs/gpu-pipeline.md`, `crates/ui-egui/src/panels/notices.rs` | CPU fallback per render on device limits, out of memory, device errors / loss, incomplete or black results (`perf.gpuReason`, `perf.gpuFallback`; each render reports its own reason — `lightcraft_gpu::try_render`, `gpuFallback` per exported file — issue #675); short submissions for slow iGPUs; backend choice (DX12 only on Windows, `LIGHTCRAFT_GPU_BACKEND` / `WGPU_BACKEND`), device created after the window opens, crash sentinel (issue #136); quitting waits (up to 2 s) for renders in flight and starts no new GPU work, so none is inside the driver when the process exits (`crates/gpu/src/exit.rs`, issue #620; seen crashing only on Linux + NVIDIA, other drivers unverified); with GPU rendering on and no adapter found at all (e.g. no Vulkan loader on NixOS outside `nix develop`), the desktop app says once per session that it renders on the CPU and points to Help ▸ System Info (`gpu_notice`; not when the GPU is turned off or only a software adapter exists); no tiling beyond the buffer limit (CPU) | | LR-BEHAV-RENDER-FIDELITY | Rendering matches Lightroom | P1 | 🟡 | `crates/pipeline/src/lib.rs`, `crates/pipeline/src/tone.rs` | every slider exists and works, but the character of the result (tone curve shape, highlight recovery, texture / clarity / dehaze, noise reduction, sharpening, default look) is tuned by eye; there is no systematic side-by-side comparison against Lightroom on the same CC0 raws. Needs a fidelity suite: Lightroom reference renders kept only in the local `plan/` (never committed), compared per slider and preset with a perceptual metric. Tuning that changes how existing settings render ships as a new process version (LRC-DEV-PROCESS, `docs/process-versions.md`) | | LR-BEHAV-DRAGDROP | Drag and drop | P1 | ✅ | `crates/ui-egui/src/lib.rs`, `crates/ui-egui/src/panels/grid.rs` (`drag_feedback`), `crates/ui-egui/src/panels/left.rs` (`drop_target`, `album_drag_over`, `top_level_drop_target`, `drag_auto_scroll`) | files → app (import); grid photos → an album row (adds the selection, with a count badge while dragging); sidebar album / folder rows → a folder (moves it; its name follows the pointer); a drag of albums or grid photos near the top or bottom edge of the sidebar scrolls it (faster nearer the edge, only while the pointer is over the sidebar) | | LR-BEHAV-TOAST | Toast notifications | P1 | ✅ | `crates/ui-egui/src/panels/mod.rs` | | diff --git a/docs/whats-new.md b/docs/whats-new.md index fb8b285a3..e56d5efb3 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -1,5 +1,12 @@ # What's new in LightCraft +## 2026-10-13 + +### Told when there is no GPU +- When GPU rendering is on but no graphics processor can be found, LightCraft now says so once at start-up instead + of quietly rendering everything on the CPU, much more slowly. Help ▸ System Info says why. On NixOS this happens + when a `cargo` build runs outside `nix develop` (no Vulkan loader); start it from there. + ## 2026-10-11 ### JPEG XL export