mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-01 05:57:09 -06:00
PERF-WINDOW: the window queues one frame, not two (eframe's low-latency surface)
window_gpu::base_options() built the window's wgpu options from egui_wgpu::WgpuConfiguration::default(), which is egui-wgpu's HIGH_THROUGHPUT surface (desired_maximum_frame_latency 2; three drawables on Metal), not eframe's default. eframe's NativeOptions::default() uses LOW_LATENCY (latency 1). The window had eframe's default until #136 started building the options by hand to choose the backends. Start from eframe::NativeOptions::default().wgpu_options and change only the backends, the DX12 compiler and the instance flags, as before. The probed Windows configurations are built on the same options. Measured on an M2 Max at 120 Hz (Metal System Trace, heavy develop drag, presents joined to WindowServer's reads of the same IOSurface): the window cycles 2 drawables instead of 3, and a frame reaches the compositor about 8.3 ms (one frame) sooner, 9.5-10.6 ms instead of 17.9-18.9 ms after it is presented, at the same ~119 frames a second. Test: window_gpu::tests::window_surface_keeps_one_frame_in_flight (fails on the old options: latency Some(2) instead of Some(1)). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
31ec62cd03
commit
2dd02f6f97
@@ -142,8 +142,13 @@ fn user_notice(failed: Option<WindowRenderer>, forced: Option<WindowRenderer>, p
|
||||
}
|
||||
|
||||
/// eframe's defaults with the app's backends and DX12 shader compiler (issues #136, #471).
|
||||
///
|
||||
/// Taken from `NativeOptions::default()`, whose surface is egui-wgpu's `LOW_LATENCY` (one frame in
|
||||
/// flight; two drawables on Metal). `WgpuConfiguration::default()` is `HIGH_THROUGHPUT` instead (two
|
||||
/// frames queued, three drawables): every drag, slider and crop handle reached the screen a frame
|
||||
/// later than eframe's default. Live window resizing still gets three drawables from egui-wgpu.
|
||||
pub fn base_options() -> WgpuConfiguration {
|
||||
let mut c = WgpuConfiguration::default();
|
||||
let mut c = eframe::NativeOptions::default().wgpu_options;
|
||||
if let WgpuSetup::CreateNew(n) = &mut c.wgpu_setup {
|
||||
n.instance_descriptor.backends = backend::window_backends();
|
||||
n.instance_descriptor.backend_options = backend::backend_options();
|
||||
@@ -290,6 +295,23 @@ mod tests {
|
||||
assert!(died.contains("last time") && !died.contains("Validation Error"), "{died}");
|
||||
}
|
||||
|
||||
/// The window keeps eframe's low-latency surface: one frame queued (two Metal drawables), not
|
||||
/// the high-throughput `WgpuConfiguration::default()`, which held input a frame longer. The
|
||||
/// probed (Windows) and forced-backend configurations are built on the same options.
|
||||
#[test]
|
||||
fn window_surface_keeps_one_frame_in_flight() {
|
||||
let surface = base_options().surface;
|
||||
assert_eq!(surface, eframe::NativeOptions::default().wgpu_options.surface);
|
||||
assert_eq!(surface, eframe::egui_wgpu::SurfaceConfig::LOW_LATENCY);
|
||||
assert_eq!(surface.desired_maximum_frame_latency, Some(1));
|
||||
assert_eq!(surface.present_mode, wgpu::PresentMode::AutoVsync);
|
||||
assert_ne!(surface, WgpuConfiguration::default().surface, "egui-wgpu's own default is the high-throughput one");
|
||||
// what `main` hands eframe (on Windows `choose` probes the adapters first; not here)
|
||||
if !cfg!(windows) {
|
||||
assert_eq!(choose(&Files::new(None)).wgpu_options.surface, surface);
|
||||
}
|
||||
}
|
||||
|
||||
/// The crash report: a pipeline that fails validation must come back as an error, never as
|
||||
/// wgpu's default panic. Needs an adapter; skipped where there is none (CI without a GPU).
|
||||
#[test]
|
||||
|
||||
@@ -113,6 +113,15 @@ renderer last. `LIGHTCRAFT_GPU_BACKEND=dx12 | vulkan | gl | glow` (or `WGPU_BACK
|
||||
first because a broken Vulkan driver can crash the process uncatchably (#136). Compute keeps its own
|
||||
device and falls back to the CPU as before.
|
||||
|
||||
**The window's surface: one frame in flight.** The window's wgpu options start from eframe's defaults
|
||||
(`NativeOptions::default().wgpu_options`, `window_gpu::base_options`), whose surface is egui-wgpu's
|
||||
`SurfaceConfig::LOW_LATENCY`: vsync, at most one frame queued ahead of the display (two drawables on
|
||||
Metal). egui-wgpu's bare `WgpuConfiguration::default()` is `HIGH_THROUGHPUT` (two frames queued, three
|
||||
drawables), and the window used it from #136 until this change, so a drag reached the screen one frame
|
||||
(8.3 ms at 120 Hz, 16.7 ms at 60 Hz) later. The window's own GPU work is small (egui's meshes and
|
||||
texture uploads; renders run on the compute device), which is what `LOW_LATENCY` is meant for.
|
||||
During a live window resize egui-wgpu still uses three drawables on macOS.
|
||||
|
||||
**Troubleshooting a crash at startup (Windows).** Start LightCraft from a `.cmd` file or a terminal
|
||||
with `set LIGHTCRAFT_GPU_BACKEND=dx12` (the default since #136), or `=off` to keep the GPU out of
|
||||
rendering; `set VK_LOADER_DRIVERS_DISABLE=*igvk64*` (Vulkan loader) hides a specific Vulkan driver
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# What's new in LightCraft
|
||||
|
||||
## 2026-10-25
|
||||
|
||||
### Drags reach the screen a frame sooner
|
||||
- The window queues one frame ahead of the display again instead of two, as eframe does by default (since #136 it
|
||||
used egui-wgpu's high-throughput setting). Sliders, crop handles, brushes and every other drag show up one display
|
||||
frame sooner: 8.3 ms at 120 Hz, 16.7 ms at 60 Hz. On a MacBook Pro at 120 Hz, a heavy develop drag went from
|
||||
about 18 ms to about 10 ms between a frame being handed to macOS and macOS compositing it, with the same 120 frames
|
||||
a second. On a Mac the window also holds one drawable less: its width × height × 4 bytes, 15–22 MB for a
|
||||
1200–1500-point-wide window on a Retina display.
|
||||
|
||||
## 2026-10-24
|
||||
|
||||
### Relative-date filters and smart albums follow the clock
|
||||
|
||||
Reference in New Issue
Block a user