Window resize "jitter" using wgpu-ris and winit

1.2k Views Asked by At

I'm experimenting with some rust code that is a slight re-structuring of the code shown in the Learn WGPU tutorial, including the addition of a uniform transform to draw objects at fixed (pixel) locations and sizes.

I notice that when I resize my window, that my boxes stretch, squash, and jitter drastically.

resize jitter

The stretching/warping follows the magnitude and direction of the delta, and once the resize is completed the boxes always settle at their correct position and size

enter image description here

GifCam's frame diff view shows the extent of the stretching during the move

enter image description here

To rule out any of my changes to the tutorial code, I cloned the repository, built and ran "tutorial6-uniforms", and it shows the same behavior with resizes stretching and squashing the shape as they occur.

enter image description here

Adding println's to my resize and render functions (and disabling redraws on MainEventsCleared) shows even pairs of resize events and redraws

redraw called PhysicalSize { width: 800, height: 600 } // initial draw
resize called PhysicalSize { width: 799, height: 600 } // resize begins
redraw called PhysicalSize { width: 799, height: 600 }
resize called PhysicalSize { width: 774, height: 589 }
redraw called PhysicalSize { width: 774, height: 589 }

This all makes me believe that there is something going on behind the scenes, where perhaps the frame is stretched first to match the window's new size before the redraw is completed? Is there a way to prevent this? When there are a lot of elements on the screen, especially text, this effect becomes pretty jarring. Not to mention most application's do not suffer from this, so it looks unprofessional and ugly.

Here is my event loop, I've omitted other code to keep my post size down but will add more if it helps troubleshoot the issue, or refer to the code here from the tutorial.

event_loop.run(move |event, _, control_flow| {
    match event {
        Event::WindowEvent {
            ref event,
            window_id,
        } if window_id  == window.id() => {
            match event {
                // ...
                WindowEvent::Resized(physical_size) => {
                    renderer.resize(*physical_size);
                },
                _ => {}
            }
        },
        Event::RedrawRequested(_) => {
            match renderer.render() {
                Ok(_) => {},
                Err(e) => eprintln!("{:?}", e),
            }
        },
        // no change in observed resizing behavior with or without
        /*Event::MainEventsCleared => {
            window.request_redraw();
        },*/
        // ...
        _ => {}
    }
})
2

There are 2 best solutions below

0
On

Changing the surface's presentation mode from Fifo to Immediate prevents distortion while resizing (on Windows 10).

// surface: wgpu::Surface, device: wgpu::Device

let config = wgpu::SurfaceConfiguration {
    ...
    present_mode: wgpu::PresentMode::Immediate,
    ...
};

surface.configure(&device, &config);
1
On

I believe this is a winit issue, where it both sets the view to be automatically resized and also not giving the app chance to redraw before OS redraws the resized window. I haven't found a good workaround, so I guess the only path is for someone to dive in to winit code.