Issue #2936: build the GPU kernels on parallel threads

Gpu::new built the 27 compute pipelines one after another. On DX12 each one is compiled by FXC
(issue #471), single-threaded, inside create_compute_pipeline, so every process waited ~2.2 s for
them on an Intel Core Ultra 7 165U iGPU (app.gpu 2.4 s median) while the other cores idled.

build_kernels creates the shader modules and layouts on the calling thread and shares the pipelines
out to worker threads (std::thread::scope, an atomic job counter; the calling thread works too, so
every kernel is built even when no thread can be started). wgpu's error scopes are per thread, so
each worker pushes its own validation and internal scopes: a refused kernel or a panicked worker
still means no GPU, never a half-built one. app.gpu: 2.4 s -> 1.2 s median on that machine, exports
pixel-identical. The gpu: info line now reports the kernel count and build time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QWU3BMJMENFqFqxDHzV3b
This commit is contained in:
Ingmar Lübbe
2026-10-25 16:38:12 +01:00
co-authored by Claude Opus 5.5
parent 03c88c166c
commit fa4bccff64
2 changed files with 127 additions and 34 deletions
+8
View File
@@ -302,6 +302,14 @@ compilation: ~0.4 s once per process — the desktop app starts it on a backgrou
(`lightcraft_gpu::warm_up`), so the first loupe render doesn't wait for it; other processes create
the device on their first GPU render. `lightcraft_gpu::ready()` asks without blocking.
On Windows / DX12 the kernels cost more: FXC compiles each pipeline single-threaded inside
`create_compute_pipeline` (issue #471). Built one after another, the 27 took ~2.2 s on an Intel Core
Ultra 7 165U iGPU (`app.gpu` 2.4 s median, up to 7 s on the first run after an install), so
`ctx::build_kernels` shares them out to worker threads (issue #2936): ~1.05 s there (`app.gpu` 1.2 s),
now bounded by the largest kernel (`finish.wgsl`). wgpu's error scopes are per thread, so every worker
opens its own; a refused kernel still means no GPU. The `gpu:` info log line gives the kernel count
and build time.
## Opening a photo (M5.4)
- The loupe shows a stand-in at once (`media::QuickJob`): the photo's cached view render for its
current settings, else (raws with their import look) the embedded camera JPEG, else a