diff --git a/crates/algo/src/camera_raw.rs b/crates/algo/src/camera_raw.rs index 7a9dec0fb2..5cf7a241a9 100644 --- a/crates/algo/src/camera_raw.rs +++ b/crates/algo/src/camera_raw.rs @@ -1257,6 +1257,21 @@ mod tests { assert!(v[0][0] < 0.35 && (v[(h / 2) * w + w / 2][0] - 0.5).abs() < 0.01, "{:?}", v[0]); } + #[test] + fn calibration_keeps_the_develop_off_the_per_pixel_gpu_stages() { + // The per-pixel stages (the Camera Raw dialog's GPU preview) don't run Calibration, so + // settings with it must fall back to the CPU develop instead of previewing without it. + for p in [ + CameraRaw { shadow_tint: 40.0, ..Default::default() }, + CameraRaw { calibration_hue: [0.0, 0.0, 30.0], whites: 20.0, ..Default::default() }, + CameraRaw { calibration_sat: [-50.0, 0.0, 0.0], exposure: 0.5, ..Default::default() }, + ] { + assert!(!p.spatial()); + assert!(per_pixel(&p, 2, 2, false, Some((0.0, 1.0))).is_none(), "{p:?}"); + } + assert!(per_pixel(&CameraRaw { exposure: 0.5, ..Default::default() }, 2, 2, false, None).is_some()); + } + #[test] fn calibration_turns_primaries_keeps_neutrals_and_tints_shadows() { let w = calibration_weights(0.0); diff --git a/crates/algo/src/camera_raw/per_pixel.rs b/crates/algo/src/camera_raw/per_pixel.rs index 88bfc9a006..6400db8a25 100644 --- a/crates/algo/src/camera_raw/per_pixel.rs +++ b/crates/algo/src/camera_raw/per_pixel.rs @@ -202,10 +202,11 @@ pub fn white_black_points(px: &[[f32; 4]], w: usize, h: usize, p: &CameraRaw) -> } /// Develop's stages for settings without spatial stages, on a `w × h` image; `points` are the -/// image's [`white_black_points`]. `None` when `p` needs a spatial stage, or Whites or Blacks is -/// set without `points`. +/// image's [`white_black_points`]. `None` when `p` needs a spatial stage or Calibration (these +/// stages don't run it), or Whites or Blacks is set without `points`. The points themselves +/// leave Calibration out, so a caller may cache them across Calibration changes. pub fn per_pixel(p: &CameraRaw, w: usize, h: usize, float: bool, points: Option<(f32, f32)>) -> Option { - if p.spatial() { + if p.spatial() || !p.calibration_neutral() { return None; } let identity = p.is_identity(); diff --git a/docs/hardware-parity.md b/docs/hardware-parity.md index 59b6c01119..e8f6a6da1b 100644 --- a/docs/hardware-parity.md +++ b/docs/hardware-parity.md @@ -19,7 +19,7 @@ HDR display to verify. |---|---|---|---| | GPU canvas, zoom/pan, rotate view | Metal (macOS), DirectX/OpenCL (Windows) | wgpu 30: Metal, Vulkan, DX12, GL; backend selectable | done | | GPU compositing of layers, blend modes, effects | partial (Photoshop composites mostly on CPU) | wgpu compositor, ≤ 1/255 vs CPU oracle; Multichannel and > texture-limit regions fall back to CPU | done (ahead in places) | -| GPU filters (Blur Gallery, Liquify, Smart Sharpen, Camera Raw) | yes | CPU (rayon) for filters; GPU for compose and effects. Camera Raw's preview runs its per-pixel stages (white balance to grain) in one wgpu pass, about 2-3 ms vs 11-28 ms on the CPU for the 858×572 proxy, depending on the machine; spatial stages and OK still develop on the CPU (#6916) | partial | +| GPU filters (Blur Gallery, Liquify, Smart Sharpen, Camera Raw) | yes | CPU (rayon) for filters; GPU for compose and effects. Camera Raw's preview runs its per-pixel stages (white balance to grain) in one wgpu pass, about 2-3 ms vs 11-28 ms on the CPU for the 858×572 proxy, depending on the machine; spatial stages, Calibration and OK still develop on the CPU (#6916) | partial | | Documents larger than the GPU texture limit | yes (tiled) | CPU fallback; tiling in progress (#49) | partial | | CPU-only fallback when no GPU | yes, reduced | `cpu` canvas preference; fails to start without an adapter on some Linux systems (#2519, #2412) | partial | | Choosing the GPU on a multi-GPU machine | Preferences › Performance › Use Graphics Processor | Linux only: Preferences › Performance › Advanced › GPU adapter and `PHOTOCRAFT_GPU_ADAPTER` (#1885); ignored on Windows and macOS | partial | diff --git a/docs/scorecard.md b/docs/scorecard.md index f4260584b9..dbe8c59799 100644 --- a/docs/scorecard.md +++ b/docs/scorecard.md @@ -292,7 +292,7 @@ Never-crash attribute on 30 of 30 crate roots. | BUG-203-6 | Failure-injection tests: mid-write, rename and read-only dir errors keep original bytes | done | [#203](https://github.com/storytold/photocraft/issues/203) | format/src/atomic/tests.rs: Faulty AtomicFs injects mid-write StorageFull, rename failure and a read-only dir; locked-target retries, symlink and file-mode preservation covered too | | BUG-204-1 | Interface prefs (UI scale, font size, channels in colour, sliders, tooltips) wired or hidden | done | [#204](https://github.com/storytold/photocraft/issues/204) | prefs_ui.rs tick reads ui_scale (sync_display_scale), ui_font_size (theme::set_ui_font_size) and show_tooltips (sync_tooltips); show_channels_in_color is wired in channel_thumbs and the canvas channel view (#2385); dynamic_color_sliders is in prefs::HIDDEN_UNTIL_IMPLEMENTED | | BUG-204-2 | workspace.large_tabs, animated_zoom, auto_show_home_screen wired or hidden | done | [#204](https://github.com/storytold/photocraft/issues/204) | workspace.large_tabs controls document tab height in canvas.rs; auto_show_home_screen drives the Home screen; general.animated_zoom gates discrete canvas zoom transitions and continuous held Zoom tool presses (zoom_hold.rs, #6210), and is exposed in General preferences | -| BUG-204-3 | RAW prefs and ask_before_saving_layered_tiff read, or hidden | done | [#204](https://github.com/storytold/photocraft/issues/204) | ask_before_saving_layered_tiff drives the TIFF Options prompt (ui-egui tiff_options_ui.rs); raw_defaults.open_in_camera_raw drives the Camera Raw dialog (camera_raw_ui.rs); the other raw_defaults fields are in prefs::HIDDEN_UNTIL_IMPLEMENTED | +| BUG-204-3 | RAW prefs and ask_before_saving_layered_tiff read, or hidden | done | [#204](https://github.com/storytold/photocraft/issues/204) | ask_before_saving_layered_tiff drives the TIFF Options prompt (ui-egui tiff_options_ui.rs); raw_defaults.open_in_camera_raw drives the Camera Raw dialog (camera_raw_ui.rs); the other raw_defaults fields drive the raw open and Camera Raw (#5128) | | BUG-204-4 | Recent files persisted through prefs across restarts | done | [#204](https://github.com/storytold/photocraft/issues/204) | crates/ui-egui/src/lib.rs::push_recent stores the list in preferences; prefs_ui::load restores it and recent_files_survive_a_restart_and_honour_the_count verifies reload | | BUG-204-5 | Recent-files list honours recent_file_count (default 20) | done | [#204](https://github.com/storytold/photocraft/issues/204) | lib.rs push_recent caps the list with recent_cap (recent_file_count); menus.rs covers default and custom limits | | BUG-204-6 | Test: every Prefs field is read somewhere or on a hidden allowlist | done | [#204](https://github.com/storytold/photocraft/issues/204) | crates/engine/tests/it/prefs_usage.rs every_preference_is_read_or_hidden: each field is read outside prefs.rs or listed in prefs::HIDDEN_UNTIL_IMPLEMENTED, never both | diff --git a/scorecard/bugs.toml b/scorecard/bugs.toml index 6b7e9a3ee2..f997437ae6 100644 --- a/scorecard/bugs.toml +++ b/scorecard/bugs.toml @@ -67,7 +67,7 @@ id = "BUG-204-3" target = "RAW prefs and ask_before_saving_layered_tiff read, or hidden" status = "done" issue = 204 -note = "ask_before_saving_layered_tiff drives the TIFF Options prompt (ui-egui tiff_options_ui.rs); raw_defaults.open_in_camera_raw drives the Camera Raw dialog (camera_raw_ui.rs); the other raw_defaults fields are in prefs::HIDDEN_UNTIL_IMPLEMENTED" +note = "ask_before_saving_layered_tiff drives the TIFF Options prompt (ui-egui tiff_options_ui.rs); raw_defaults.open_in_camera_raw drives the Camera Raw dialog (camera_raw_ui.rs); the other raw_defaults fields drive the raw open and Camera Raw (#5128)" [[item]] id = "BUG-204-4"