mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 04:57:54 -06:00
Window: start the wgpu surface from eframe's default, one frame in flight instead of two
`wgpu_options` built the window's configuration from `WgpuConfiguration::default()`, whose surface is `SurfaceConfig::HIGH_THROUGHPUT` (two frames in flight); eframe's own `NativeOptions::default()` wraps it with `LOW_LATENCY` (one), and replacing `wgpu_options` wholesale silently lost that. On Metal, wgpu-hal sets `maximumDrawableCount = latency + 1`: three drawables instead of two, one more frame between the pointer and the screen on every drag, scrub and slider (8 ms at 120 Hz, 17 ms at 60 Hz). Start from `.with_surface_config(eframe::SurfaceConfig::LOW_LATENCY)`; everything else in `wgpu_options` is unchanged. Measured on an M2 Max (release, `footprint -p`): IOSurface 61 MB → 41 MB (three 21 MB drawables → two). Interface frame rate during 10 s of playback of a 1080p comp whose frames cost 164–279 ms on the GPU stays at 120 fps either way (median 120.1 vs 120.0, p10 116–119.5 vs 117–119.4), so one frame in flight does not starve this comp at 120 Hz. Test: `the_window_surface_is_low_latency` asserts `LOW_LATENCY`, `desired_maximum_frame_latency == Some(1)` and `AutoVsync` for every backend choice, and equality with eframe's default surface. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
1400cf7c78
commit
cb46d69e44
@@ -359,9 +359,15 @@ fn main() -> eframe::Result {
|
||||
/// instead of eframe's fixed set: an older GPU that can't meet those (Intel HD Graphics 5500,
|
||||
/// #198) still opens the app, and the compositor then checks what it needs and falls back to
|
||||
/// the CPU when the device can't run it. `backends`: Window Graphics' choice, when it makes one.
|
||||
///
|
||||
/// The surface is eframe's own default, [`eframe::SurfaceConfig::LOW_LATENCY`]: vsync with one
|
||||
/// frame in flight, so a drag or a scrub shows one frame sooner. The bare
|
||||
/// `WgpuConfiguration::default()` is `HIGH_THROUGHPUT` instead (two frames in flight, three
|
||||
/// drawables on Metal): one more frame of pointer-to-screen lag on every interaction, about 8 ms
|
||||
/// at 120 Hz and 17 ms at 60 Hz, and a third 15 MB drawable held for the window.
|
||||
fn wgpu_options(backends: Option<eframe::wgpu::Backends>) -> eframe::WgpuConfiguration {
|
||||
use eframe::egui_wgpu::WgpuSetup;
|
||||
let mut config = eframe::WgpuConfiguration::default();
|
||||
let mut config = eframe::WgpuConfiguration::default().with_surface_config(eframe::SurfaceConfig::LOW_LATENCY);
|
||||
if let WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
|
||||
if let Some(b) = backends {
|
||||
setup.instance_descriptor.backends = b;
|
||||
@@ -533,6 +539,19 @@ mod tests {
|
||||
assert!(!setup.instance_descriptor.flags.contains(eframe::wgpu::InstanceFlags::VALIDATION_INDIRECT_CALL));
|
||||
}
|
||||
|
||||
/// The window's surface keeps one frame in flight, like eframe's own default, not the two
|
||||
/// of the bare `WgpuConfiguration::default()` (one extra frame of lag on every drag).
|
||||
#[test]
|
||||
fn the_window_surface_is_low_latency() {
|
||||
for backends in [None, Some(eframe::wgpu::Backends::METAL), Some(eframe::wgpu::Backends::GL)] {
|
||||
let surface = super::wgpu_options(backends).surface;
|
||||
assert_eq!(surface, eframe::SurfaceConfig::LOW_LATENCY, "{backends:?}");
|
||||
assert_eq!(surface.desired_maximum_frame_latency, Some(1));
|
||||
assert_eq!(surface.present_mode, eframe::wgpu::PresentMode::AutoVsync);
|
||||
}
|
||||
assert_eq!(super::wgpu_options(None).surface, eframe::NativeOptions::default().wgpu_options.surface, "eframe's default surface");
|
||||
}
|
||||
|
||||
/// The window's device never asks for more than the adapter offers (#198).
|
||||
#[test]
|
||||
fn device_limits_fit_the_adapter() {
|
||||
|
||||
Reference in New Issue
Block a user