Skip to content

Do not panic when swap_buffer (egl) fails #1320

@philipp-kaiser

Description

@philipp-kaiser

I notices some bug in running on android. When resuming to the app, sometimes the swap_buffer method is throwing an egl error:

... /? E/BufferQueueProducer: [rust.rust_android_example/android.app.NativeActivity#0] queueBuffer: BufferQueue has been abandoned
.../rust.rust_android_example E/Surface: queueBuffer: error queuing buffer to SurfaceTexture, -19
.../? E/BufferQueueProducer: [rust.rust_android_example/android.app.NativeActivity#0] dequeueBuffer: BufferQueue has been abandoned
.../rust.rust_android_example E/EGL_emulation: tid 21300: swapBuffers(552): error 0x300d (EGL_BAD_SURFACE)

The problem is located under glutin/src/api/egl/mod.rs line 663:

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        let egl = EGL.as_ref().unwrap();
        let surface = self.surface.as_ref().unwrap().lock();
        if *surface == ffi::egl::NO_SURFACE {
            return Err(ContextError::ContextLost);
        }

        let ret = unsafe { egl.SwapBuffers(self.display, *surface) };

        if ret == 0 {
            match unsafe { egl.GetError() } as u32 {
                ffi::egl::CONTEXT_LOST => {
                    return Err(ContextError::ContextLost)
                }
                err => panic!(
                    "swap_buffers: eglSwapBuffers failed (eglGetError returned 0x{:x})",
                    err
                ),
            }
        } else {
            Ok(())
        }
    }

Calling the panic! kills the app. There is no chance to recover from this state. I noticed, that this problem can easily be fixed by recreating the graphics context. Therefore we need to have a chance to handle that problem:

My simple hack is following:

    #[inline]
    pub fn swap_buffers(&self) -> Result<(), ContextError> {
        let egl = EGL.as_ref().unwrap();
        let surface = self.surface.as_ref().unwrap().lock();
        if *surface == ffi::egl::NO_SURFACE {
            return Err(ContextError::ContextLost);
        }

        let ret = unsafe { egl.SwapBuffers(self.display, *surface) };

        if ret == 0 {
            Err(ContextError::ContextLost)
        } else {
            Ok(())
        }
    }

This gives me a chance to release all openGL resources, recreate the context, and finally recreate all buffers, and the app keeps running. The user doesn't even notice...

Maybe the problem is lies somewhere else, but calling panic! takes away all possibilities.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions