mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-14 19:26:51 -04:00
Preferences › Performance › Low-Latency Drawing, on by default: no vsync wait while drawing (#1343)
Testers' traces put the ~50 ms stroke lag in the swap chain's vsync wait. With vsync off it disappears (X11/NVIDIA; Windows/NVIDIA via the driver), and a shorter queue doesn't help. The surface now presents with AutoNoVsync by default: wgpu picks Immediate, else Mailbox, else Fifo by what the driver offers, so no unsupported mode is ever requested. Turning the preference off brings vsync back (smooth, but late). It applies at the next launch, like the other graphics settings. Where only Immediate exists the canvas may tear while it changes; frames render as fast as input arrives during a stroke and stop when idle.
This commit is contained in:
1 parent
34ba17cfd4
commit
9a9eaed068
26 files changed
+65
-4
No files matched your search
@@ -444,6 +444,14 @@ pub fn read_display_server(path: Option<&Path>) -> photocraft_engine::prefs::Lin
|
||||
}
|
||||
|
||||
/// Read the policy leniently at startup, including old settings without renderingMode.
|
||||
/// Preferences › Performance › Low-Latency Drawing (`performance.lowLatencyDrawing`, on unless
|
||||
/// set off), read before the window opens: it picks the surface's present mode.
|
||||
pub fn read_low_latency(path: Option<&Path>) -> bool {
|
||||
let v: Value = path.and_then(|p| std::fs::read_to_string(p).ok()).and_then(|t| serde_json::from_str(&t).ok()).unwrap_or(Value::Null);
|
||||
let default = photocraft_engine::prefs::Preferences::default().performance.low_latency_drawing;
|
||||
v.get("performance").and_then(|p| p.get("lowLatencyDrawing")).and_then(Value::as_bool).unwrap_or(default)
|
||||
}
|
||||
|
||||
pub fn read_rendering_prefs(path: Option<&Path>) -> (GpuBackend, RenderingMode) {
|
||||
let v: Value = path.and_then(|p| std::fs::read_to_string(p).ok()).and_then(|t| serde_json::from_str(&t).ok()).unwrap_or(Value::Null);
|
||||
let perf = v.get("performance");
|
||||
@@ -463,6 +471,23 @@ mod tests {
|
||||
Marker { backend: backend.into(), adapter: "Intel(R) UHD Graphics".into(), adapter_backend: adapter_backend.into(), ..Default::default() }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn low_latency_drawing_is_read_before_the_window_opens_and_defaults_on() {
|
||||
let dir = std::env::temp_dir().join(format!("photocraft-low-latency-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let file = dir.join("preferences.json");
|
||||
let read = |json: &str| {
|
||||
std::fs::write(&file, json).unwrap();
|
||||
read_low_latency(Some(&file))
|
||||
};
|
||||
assert!(read(r#"{"performance":{"lowLatencyDrawing":true}}"#));
|
||||
assert!(!read(r#"{"performance":{"lowLatencyDrawing":false}}"#));
|
||||
assert!(read(r#"{"performance":{"lowLatencyDrawing":"nope"}}"#), "garbage keeps the default");
|
||||
assert!(read("not json"));
|
||||
assert!(read_low_latency(None), "no settings file: the default");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_server_preference_is_read_before_the_window_opens() {
|
||||
use photocraft_engine::prefs::LinuxDisplayServer;
|
||||
|
||||
@@ -363,7 +363,12 @@ fn main() -> eframe::Result {
|
||||
let gpu_note: std::sync::Arc<std::sync::Mutex<Option<String>>> = Default::default();
|
||||
// The adapter's real texture limits (egui asks for 8192 px), so big documents stay on the GPU.
|
||||
gpu_startup::configure(&mut options.wgpu_options.wgpu_setup, &plan, os, sentinel.clone(), gpu_note.clone());
|
||||
// Testers' present mode and frame latency overrides (#1343), after the platform default.
|
||||
// Preferences › Performance › Low-Latency Drawing (#1343): without vsync a stroke shows about
|
||||
// 50 ms sooner; wgpu picks Immediate, else Mailbox, else Fifo by what the driver offers.
|
||||
if gpu_startup::read_low_latency(services::prefs_file().as_deref()) {
|
||||
options.wgpu_options.surface.present_mode = eframe::wgpu::PresentMode::AutoNoVsync;
|
||||
}
|
||||
// Testers' present mode and frame latency overrides (#1343), after the preference.
|
||||
let present = presentation::Overrides::from_env();
|
||||
options.wgpu_options.surface = present.apply(options.wgpu_options.surface);
|
||||
let present_desc = presentation::describe(&options.wgpu_options.surface, &present);
|
||||
|
||||
@@ -529,6 +529,11 @@ pub struct Performance {
|
||||
/// sliders while they drag) render on a reduced copy: fast, but blocky when zoomed in. Off:
|
||||
/// they render at full resolution.
|
||||
pub low_resolution_previews: bool,
|
||||
/// Low-latency drawing (applies at next launch): frames reach the screen without waiting for
|
||||
/// vsync, so a stroke follows the pen about 50 ms sooner (the swap chain's wait, #1343). Where
|
||||
/// the driver can't replace queued frames (Mailbox), the canvas may tear while it changes.
|
||||
/// Off: vsync, smooth but late.
|
||||
pub low_latency_drawing: bool,
|
||||
/// Linux display server (applies at next launch; see [`LinuxDisplayServer`]).
|
||||
pub linux_display_server: LinuxDisplayServer,
|
||||
/// Memory budget of the layer-effect cache, in MB.
|
||||
@@ -560,6 +565,7 @@ impl Default for Performance {
|
||||
rendering_mode: None,
|
||||
gpu_backend: GpuBackend::Auto,
|
||||
low_resolution_previews: true,
|
||||
low_latency_drawing: true,
|
||||
linux_display_server: LinuxDisplayServer::Auto,
|
||||
effect_cache_mb: 768,
|
||||
legacy_compositing: false,
|
||||
|
||||
@@ -3783,3 +3783,4 @@ navigator Zoom Zvětšení
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Upravit vybraná vodítka
|
||||
Clear Selected Guides Vymazat vybraná vodítka
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Kreslení s nízkou latencí (bez vertikální synchronizace, platí po dalším spuštění)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3177,3 +3177,4 @@ curves Smooth Glätten
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Ausgewählte Hilfslinien bearbeiten
|
||||
Clear Selected Guides Ausgewählte Hilfslinien löschen
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Zeichnen mit geringer Latenz (ohne VSync, gilt ab dem nächsten Start)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3875,3 +3875,4 @@ curves Smooth Εξομάλυνση
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Επεξεργασία επιλεγμένων οδηγών
|
||||
Clear Selected Guides Απαλοιφή επιλεγμένων οδηγών
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Σχεδίαση χαμηλής καθυστέρησης (χωρίς vsync, ισχύει στην επόμενη εκκίνηση)
|
||||
|
Can't render this file because it contains an unexpected character in line 1030 and column 18.
|
@@ -4137,3 +4137,4 @@ navigator Zoom Zoom
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Editar guías seleccionadas
|
||||
Clear Selected Guides Borrar guías seleccionadas
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Dibujo de baja latencia (sin sincronización vertical, se aplica al volver a iniciar)
|
||||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
@@ -3179,3 +3179,4 @@ curves Smooth Lisser
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Modifier les repères sélectionnés
|
||||
Clear Selected Guides Effacer les repères sélectionnés
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Dessin à faible latence (sans synchronisation verticale, au prochain lancement)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -4094,3 +4094,4 @@ cameraRaw Yellow Sárga
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Kijelölt segédvonalak szerkesztése
|
||||
Clear Selected Guides Kijelölt segédvonalak törlése
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Kis késleltetésű rajzolás (vsync nélkül, a következő indításkor lép életbe)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3166,3 +3166,4 @@ curves Smooth Haluskan
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Edit Panduan Terpilih
|
||||
Clear Selected Guides Hapus Panduan Terpilih
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Menggambar latensi rendah (tanpa vsync, berlaku saat peluncuran berikutnya)
|
||||
|
Can't render this file because it contains an unexpected character in line 4 and column 47.
|
@@ -4296,3 +4296,4 @@ shape Appearance Aspetto
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Modifica guide selezionate
|
||||
Clear Selected Guides Cancella guide selezionate
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Disegno a bassa latenza (senza vsync, si applica al prossimo avvio)
|
||||
|
Can't render this file because it contains an unexpected character in line 2654 and column 53.
|
@@ -3851,3 +3851,4 @@ curves Smooth スムーズ
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides 選択したガイドを編集
|
||||
Clear Selected Guides 選択したガイドを消去
|
||||
Low-Latency Drawing (vsync off, applies at next launch) 低遅延描画(垂直同期オフ、次回起動時に適用)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3353,3 +3353,4 @@ curves Smooth 매끄럽게
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides 선택한 안내선 편집
|
||||
Clear Selected Guides 선택한 안내선 지우기
|
||||
Low-Latency Drawing (vsync off, applies at next launch) 저지연 그리기(수직 동기화 끔, 다음 실행 시 적용)
|
||||
|
Can't render this file because it contains an unexpected character in line 3166 and column 53.
|
@@ -3935,3 +3935,4 @@ curves Smooth Vloeiend maken
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Geselecteerde hulplijnen bewerken
|
||||
Clear Selected Guides Geselecteerde hulplijnen wissen
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Tekenen met lage latentie (zonder vsync, na de volgende start)
|
||||
|
Can't render this file because it contains an unexpected character in line 8 and column 34.
|
@@ -3773,3 +3773,4 @@ curves Smooth Wygładź
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Edytuj zaznaczone prowadnice
|
||||
Clear Selected Guides Usuń zaznaczone prowadnice
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Rysowanie z małym opóźnieniem (bez synchronizacji pionowej, od następnego uruchomienia)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3965,3 +3965,4 @@ layerLabel No Color Sem cor
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Editar guias selecionadas
|
||||
Clear Selected Guides Limpar guias selecionadas
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Desenho de baixa latência (sem sincronização vertical, aplicado na próxima inicialização)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3144,3 +3144,4 @@ curves Smooth Сгладить
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Изменить выбранные направляющие
|
||||
Clear Selected Guides Удалить выбранные направляющие
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Рисование с малой задержкой (без вертикальной синхронизации, после перезапуска)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -4248,3 +4248,4 @@ shape Appearance Izgled
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Uredi izabrane vodilje
|
||||
Clear Selected Guides Ukloni izabrane vodilje
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Crtanje sa malim kašnjenjem (bez vsync-a, primenjuje se pri sledećem pokretanju)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3905,3 +3905,4 @@ cameraData Lens Lens
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Seçili Kılavuzları Düzenle
|
||||
Clear Selected Guides Seçili Kılavuzları Temizle
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Düşük gecikmeli çizim (dikey eşitleme kapalı, sonraki açılışta geçerli)
|
||||
|
Can't render this file because it contains an unexpected character in line 8 and column 34.
|
@@ -3874,3 +3874,4 @@ curves Smooth Згладити
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Редагувати вибрані напрямні
|
||||
Clear Selected Guides Очистити вибрані напрямні
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Малювання з малою затримкою (без вертикальної синхронізації, після перезапуску)
|
||||
|
Can't render this file because it contains an unexpected character in line 1388 and column 18.
|
@@ -3661,3 +3661,4 @@ curves Smooth Làm mượt
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides Sửa đường căn đã chọn
|
||||
Clear Selected Guides Xóa đường căn đã chọn
|
||||
Low-Latency Drawing (vsync off, applies at next launch) Vẽ độ trễ thấp (tắt vsync, áp dụng ở lần khởi động sau)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -2790,3 +2790,4 @@ curves Smooth 平滑
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides 编辑所选参考线
|
||||
Clear Selected Guides 清除所选参考线
|
||||
Low-Latency Drawing (vsync off, applies at next launch) 低延迟绘画(关闭垂直同步,下次启动时生效)
|
||||
|
Can't render this file because it contains an unexpected character in line 2600 and column 53.
|
@@ -2775,3 +2775,4 @@ curves Smooth 平滑
|
||||
# View › Guides › right-click a guide
|
||||
Edit Selected Guides 編輯所選參考線
|
||||
Clear Selected Guides 清除所選參考線
|
||||
Low-Latency Drawing (vsync off, applies at next launch) 低延遲繪圖(關閉垂直同步,下次啟動時生效)
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1077,6 +1077,11 @@ fn humanize(key: &str) -> String {
|
||||
if key == "nudgeBundlePauseMs" {
|
||||
return "Nudge Bundle Pause (ms)".into();
|
||||
}
|
||||
// Performance: presentation without vsync (#1343); like the other graphics settings, it
|
||||
// takes effect when the window next opens.
|
||||
if key == "lowLatencyDrawing" {
|
||||
return "Low-Latency Drawing (vsync off, applies at next launch)".into();
|
||||
}
|
||||
let mut s = String::new();
|
||||
for (i, ch) in key.chars().enumerate() {
|
||||
if i == 0 {
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ By default PhotoCraft's own crates log at `info` and everything else at `warn`.
|
||||
| `PHOTOCRAFT_LOCALE` | Override Auto's native UI language for this launch; unsupported tags use English. See [system language detection](localization.md#first-launch-and-system-language). |
|
||||
| `PHOTOCRAFT_FX_TRACE=1` | Print the CPU time spent on GPU effect shapes and distance fields per rebuild |
|
||||
| `PHOTOCRAFT_STROKE_TRACE=1` (or `=<file.csv>`) | Time every frame of each brush stroke; print a summary per stroke, and with a path also append each frame to that CSV (see [Stroke latency trace](#stroke-latency-trace)) |
|
||||
| `PHOTOCRAFT_PRESENT_MODE=novsync` | Present mode for this launch: `fifo`, `autovsync`, or `novsync` (also `immediate`, `mailbox`: no vsync, the first of Immediate, Mailbox, Fifo the driver offers). Default: the platform's. For latency comparisons; shown in the stroke trace |
|
||||
| `PHOTOCRAFT_PRESENT_MODE=novsync` | Present mode for this launch: `fifo`, `autovsync`, or `novsync` (also `immediate`, `mailbox`: no vsync, the first of Immediate, Mailbox, Fifo the driver offers). Default: no vsync, or vsync when Preferences › Performance › Low-Latency Drawing is off. For latency comparisons; shown in the stroke trace |
|
||||
| `PHOTOCRAFT_FRAME_LATENCY=1` | Frames the swap chain may queue, 1 to 3 (wgpu's GL backend ignores it). For latency comparisons; shown in the stroke trace |
|
||||
| `PHOTOCRAFT_THEME_FILE=tokens.json` | **Debug builds only:** live design-token overrides, re-read on change |
|
||||
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ Generated by `cargo xtask scorecard` from `perf/budgets.toml`, `perf/baseline.js
|
||||
| [Performance](#performance) | 3 | 22 | 22 | 56 scenarios: 3 within budget, 22 over budget or failing, 9 tracked only, 17 not run, 5 not measurable yet (baseline 2026-10-05) |
|
||||
| [File compatibility](#file-compatibility) | 7 | 13 | 7 | io corpus: oracle ≥ 148/170, round trip ≥ 169/170; psd-tools corpus: oracle ≥ 249/309, round trip ≥ 308/309; photoshop oracles: oracle ≥ 185/256, round trip ≥ 258/256 |
|
||||
| [Tools](#tools) | 33 | 11 | 0 | |
|
||||
| [Workspace and UI](#workspace-and-ui) | 13 | 6 | 4 | settings that do nothing: 26 of 164 (target 0) |
|
||||
| [Workspace and UI](#workspace-and-ui) | 13 | 6 | 4 | settings that do nothing: 26 of 165 (target 0) |
|
||||
| [Type](#type) | 4 | 3 | 2 | |
|
||||
| [Automation](#automation) | 5 | 2 | 4 | 631 of 631 menu items live (100.0%) |
|
||||
| [Reliability](#reliability) | 5 | 2 | 0 | never-crash lints on 28 of 28 crates; panic_hunt present |
|
||||
@@ -177,7 +177,7 @@ Corpus floors (`crates/io/tests/corpus.rs`): the enforced minimums; the corpus t
|
||||
|
||||
## Workspace and UI
|
||||
|
||||
**Settings that do nothing: 26 of 164** (target 0, #204). Counted by the prefs audit (`xtask/src/scorecard.rs`): a `Preferences` field counts as read when code outside the prefs model (`prefs.rs` except its `impl Session` blocks; tests excluded; the schema-driven dialog never names a field) accesses `section.field`, or `.section` and `.field` in the same file, or calls a section method that reads `self.field`. It is a heuristic lower bound: a generic name can look read when it isn't.
|
||||
**Settings that do nothing: 26 of 165** (target 0, #204). Counted by the prefs audit (`xtask/src/scorecard.rs`): a `Preferences` field counts as read when code outside the prefs model (`prefs.rs` except its `impl Session` blocks; tests excluded; the schema-driven dialog never names a field) accesses `section.field`, or `.section` and `.field` in the same file, or calls a section method that reads `self.field`. It is a heuristic lower bound: a generic name can look read when it isn't.
|
||||
|
||||
Unread: `general.color_picker`, `general.animated_zoom`, `general.zoom_resizes_windows`, `workspace.auto_show_hidden_panels`, `workspace.enable_floating_document_window_docking`, `file_handling.save_in_background`, `performance.cache_levels`, `performance.legacy_compositing`, `scratch_disks.disks`, `units_and_rulers.column_width`, `units_and_rulers.gutter`, `plug_ins.show_extension_panels`, `plug_ins.allow_scripts_to_connect`, `plug_ins.generator_enabled`, `type_.text_engine`, `type_.recent_fonts`, `enhanced_controls.scrubby_slider_acceleration`, `enhanced_controls.touch_gestures`, `raw_defaults.color_space`, `raw_defaults.bit_depth`, `raw_defaults.resolution`, `raw_defaults.sharpen_for`, `raw_defaults.open_as_smart_object`, `raw_defaults.apply_auto_tone`, `integrations.allow_agent_control`, `integrations.control_port`.
|
||||
|
||||
|
||||
Reference in new issue
Block a user