parasyte/pixels

pixels.render() fails randomly

Closed this issue · 7 comments

pixels: 0.11.0

OS: Arch Linux x86_64
WM: kwin (Wayland)
CPU: 12th Gen Intel i7-12700KF
GPU: AMD ATI Radeon RX 6800

I was trying to use pixels for the first time, but I got some strange behavior when running the examples:

When running some examples, such as minimal_winit, sometimes it opens the window to show the first frame and then closes immediately giving the following error:

pixels.render() failed: The GPU failed to acquire a surface frame.

Using cargo run on minimal_winit it gives the error about 50% of the time, and works fine the other 50%.
When using cargo run --release it always gives the error.

I also tried with the conway example, and both with and without the release parameter it sometimes gives the same error.

Is this on the latest head of the main branch? Do you have the same issue with the wgpu examples? https://github.com/gfx-rs/wgpu/tree/master/wgpu/examples#readme

Is this on the latest head of the main branch?

It happens both on the 0.11 release and the most recent commit, although with different probability to give error. In the latest commit the conway example almost never gives error with cargo run, but it happens almost always with cargo run --release, meanwhile in the 0.11 pixels release is 50/50.

Do you have the same issue with the wgpu examples? https://github.com/gfx-rs/wgpu/tree/master/wgpu/examples#readme

Nope, I have tried all the examples, both on the 0.15.2 wgpu release and the latest commit, but they never gave me any sort of error, they all worked fine.

Can you please run with RUST_LOG=trace? I know the output may seem bloated but most likely the error is hidden there.

I'm pretty surprised that the wgpu examples don't exhibit the same issue. They might be doing something specific that our examples are not. But I'm not sure what it would be.

The "GPU failed to acquire a surface frame" error is equivalent to wgpu::SurfaceError, and you can get more information about the error with the error-iter crate like this:

use error_iter::ErrorIter as _;

// ...

if let Err(err) = pixels.render() {
    error!("pixels.render() failed: {err}");

    for source in err.sources().skip(1) {
        error!("  Caused by: {source}");
    }

    *control_flow = ControlFlow::Exit;
    return;
}

The wgpu examples always reconfigure the surface on any error: https://github.com/gfx-rs/wgpu/blob/46cfeec27b2b46740a58ec6c69ff5e57a4e51cf7/wgpu/examples/framework.rs#L363-L371

In contrast, pixels only handles the SurfaceError::Outdated variant:

pixels/src/lib.rs

Lines 472 to 482 in 295139a

.surface
.get_current_texture()
.or_else(|err| match err {
wgpu::SurfaceError::Outdated => {
// Reconfigure the surface to mitigate race condition on window resize.
// See https://github.com/parasyte/pixels/issues/121
self.reconfigure_surface();
self.context.surface.get_current_texture()
}
err => Err(err),
})?;

@Yoppez Please try the PR in #348.

Can you please run with RUST_LOG=trace?

I don't know if I have to edit the source code, but with the RUST_LOG=trace environment variable doesn't print anything more than the usual error.

you can get more information about the error with the error-iter crate

I tried what you suggested and got the following error:

pixels.render() failed: The GPU failed to acquire a surface frame.
Caused by: A timeout was encountered while trying to acquire the next frame

Please try the PR in #348.

With these fixes now it works flawlessly, thank you!

Thank you for the additional testing! This bug is really important to get fixed, so I'll be releasing 0.12 within a day or two to make sure this is properly addressed.