diff --git a/glutin/src/api/egl/display.rs b/glutin/src/api/egl/display.rs index 540ddaf9bd..3362d312f4 100644 --- a/glutin/src/api/egl/display.rs +++ b/glutin/src/api/egl/display.rs @@ -203,7 +203,7 @@ impl Display { /// and managed by other libraries. Use this function only when you're /// bringing everything down. pub unsafe fn terminate(self) { - if !CLIENT_EXTENSIONS.get().unwrap().contains("EGL_KHR_display_reference") { + if !self.inner.uses_display_reference() { unsafe { self.inner.egl.Terminate(*self.inner.raw); } @@ -217,50 +217,63 @@ impl Display { let extensions = CLIENT_EXTENSIONS.get().unwrap(); - let mut attrs = Vec::::with_capacity(5); - let (platform, mut display) = match display { - #[cfg(wayland_platform)] - RawDisplayHandle::Wayland(handle) - if extensions.contains("EGL_KHR_platform_wayland") => - { - (egl::PLATFORM_WAYLAND_KHR, handle.display) - }, - #[cfg(x11_platform)] - RawDisplayHandle::Xlib(handle) if extensions.contains("EGL_KHR_platform_x11") => { - attrs.push(egl::PLATFORM_X11_SCREEN_KHR as EGLAttrib); - attrs.push(handle.screen as EGLAttrib); - (egl::PLATFORM_X11_KHR, handle.display) - }, - RawDisplayHandle::Gbm(handle) if extensions.contains("EGL_KHR_platform_gbm") => { - (egl::PLATFORM_GBM_KHR, handle.gbm_device) - }, - RawDisplayHandle::Android(_) if extensions.contains("EGL_KHR_platform_android") => { - (egl::PLATFORM_ANDROID_KHR, egl::DEFAULT_DISPLAY as *mut _) - }, - _ => { - return Err( - ErrorKind::NotSupported("provided display handle is not supported").into() - ) - }, - }; + let mut first_try = true; + loop { + let mut attrs = Vec::::with_capacity(5); + let (platform, mut display) = match display { + #[cfg(wayland_platform)] + RawDisplayHandle::Wayland(handle) + if extensions.contains("EGL_KHR_platform_wayland") => + { + (egl::PLATFORM_WAYLAND_KHR, handle.display) + }, + #[cfg(x11_platform)] + RawDisplayHandle::Xlib(handle) if extensions.contains("EGL_KHR_platform_x11") => { + attrs.push(egl::PLATFORM_X11_SCREEN_KHR as EGLAttrib); + attrs.push(handle.screen as EGLAttrib); + (egl::PLATFORM_X11_KHR, handle.display) + }, + RawDisplayHandle::Gbm(handle) if extensions.contains("EGL_KHR_platform_gbm") => { + (egl::PLATFORM_GBM_KHR, handle.gbm_device) + }, + RawDisplayHandle::Android(_) if extensions.contains("EGL_KHR_platform_android") => { + (egl::PLATFORM_ANDROID_KHR, egl::DEFAULT_DISPLAY as *mut _) + }, + _ => { + return Err( + ErrorKind::NotSupported("provided display handle is not supported").into() + ) + }, + }; + + if extensions.contains("EGL_KHR_display_reference") && first_try { + attrs.push(egl::TRACK_REFERENCES_KHR as _); + attrs.push(egl::TRUE as _); + } else { + first_try = false; + } - if extensions.contains("EGL_KHR_display_reference") { - attrs.push(egl::TRACK_REFERENCES_KHR as _); - attrs.push(egl::TRUE as _); - } + // Be explicit here. + if display.is_null() { + display = egl::DEFAULT_DISPLAY as *mut _; + } - // Be explicit here. - if display.is_null() { - display = egl::DEFAULT_DISPLAY as *mut _; - } + // Push `egl::NONE` to terminate the list. + attrs.push(egl::NONE as EGLAttrib); - // Push `egl::NONE` to terminate the list. - attrs.push(egl::NONE as EGLAttrib); + let display = + unsafe { egl.GetPlatformDisplay(platform, display as *mut _, attrs.as_ptr()) }; + let result = Self::check_display_error(display).map(EglDisplay::Khr); - let display = - unsafe { egl.GetPlatformDisplay(platform, display as *mut _, attrs.as_ptr()) }; + // We can't check for the type of error here because for some reason it doesn't + // always report BadAttribute even though EGL_KHR_display_reference + // was the reason of the failure + if result.is_ok() || result.is_err() && !first_try { + return result; + } - Self::check_display_error(display).map(EglDisplay::Khr) + first_try = false; + } } fn get_platform_display_ext(egl: &Egl, display: RawDisplayHandle) -> Result { @@ -270,72 +283,88 @@ impl Display { let extensions = CLIENT_EXTENSIONS.get().unwrap(); - let mut attrs = Vec::::with_capacity(5); - let mut legacy = false; - let (platform, mut display) = match display { - #[cfg(wayland_platform)] - RawDisplayHandle::Wayland(handle) - if extensions.contains("EGL_EXT_platform_wayland") => - { - (egl::PLATFORM_WAYLAND_EXT, handle.display) - }, - #[cfg(x11_platform)] - RawDisplayHandle::Xlib(handle) if extensions.contains("EGL_EXT_platform_x11") => { - attrs.push(egl::PLATFORM_X11_SCREEN_EXT as EGLint); - attrs.push(handle.screen as EGLint); - (egl::PLATFORM_X11_EXT, handle.display) - }, - #[cfg(x11_platform)] - RawDisplayHandle::Xcb(handle) - if extensions.contains("EGL_MESA_platform_xcb") - || extensions.contains("EGL_EXT_platform_xcb") => - { - attrs.push(egl::PLATFORM_XCB_SCREEN_EXT as EGLint); - attrs.push(handle.screen as EGLint); - (egl::PLATFORM_XCB_EXT, handle.connection) - }, - RawDisplayHandle::Gbm(handle) if extensions.contains("EGL_MESA_platform_gbm") => { - (egl::PLATFORM_GBM_MESA, handle.gbm_device) - }, - RawDisplayHandle::Windows(..) if extensions.contains("EGL_ANGLE_platform_angle") => { - // Only CreateWindowSurface appears to work with Angle. - legacy = true; - (egl::PLATFORM_ANGLE_ANGLE, egl::DEFAULT_DISPLAY as *mut _) - }, - _ => { - return Err( - ErrorKind::NotSupported("provided display handle is not supported").into() - ) - }, - }; + let mut first_try = true; + loop { + let mut attrs = Vec::::with_capacity(5); + let mut legacy = false; + let (platform, mut display) = match display { + #[cfg(wayland_platform)] + RawDisplayHandle::Wayland(handle) + if extensions.contains("EGL_EXT_platform_wayland") => + { + (egl::PLATFORM_WAYLAND_EXT, handle.display) + }, + #[cfg(x11_platform)] + RawDisplayHandle::Xlib(handle) if extensions.contains("EGL_EXT_platform_x11") => { + attrs.push(egl::PLATFORM_X11_SCREEN_EXT as EGLint); + attrs.push(handle.screen as EGLint); + (egl::PLATFORM_X11_EXT, handle.display) + }, + #[cfg(x11_platform)] + RawDisplayHandle::Xcb(handle) + if extensions.contains("EGL_MESA_platform_xcb") + || extensions.contains("EGL_EXT_platform_xcb") => + { + attrs.push(egl::PLATFORM_XCB_SCREEN_EXT as EGLint); + attrs.push(handle.screen as EGLint); + (egl::PLATFORM_XCB_EXT, handle.connection) + }, + RawDisplayHandle::Gbm(handle) if extensions.contains("EGL_MESA_platform_gbm") => { + (egl::PLATFORM_GBM_MESA, handle.gbm_device) + }, + RawDisplayHandle::Windows(..) + if extensions.contains("EGL_ANGLE_platform_angle") => + { + // Only CreateWindowSurface appears to work with Angle. + legacy = true; + (egl::PLATFORM_ANGLE_ANGLE, egl::DEFAULT_DISPLAY as *mut _) + }, + _ => { + return Err( + ErrorKind::NotSupported("provided display handle is not supported").into() + ) + }, + }; + + if extensions.contains("EGL_KHR_display_reference") && first_try { + attrs.push(egl::TRACK_REFERENCES_KHR as _); + attrs.push(egl::TRUE as _); + } else { + first_try = false; + } - if extensions.contains("EGL_KHR_display_reference") { - attrs.push(egl::TRACK_REFERENCES_KHR as _); - attrs.push(egl::TRUE as _); - } + // Be explicit here. + if display.is_null() { + display = egl::DEFAULT_DISPLAY as *mut _; + } - // Be explicit here. - if display.is_null() { - display = egl::DEFAULT_DISPLAY as *mut _; - } + // Push `egl::NONE` to terminate the list. + attrs.push(egl::NONE as EGLint); - // Push `egl::NONE` to terminate the list. - attrs.push(egl::NONE as EGLint); + let display = + unsafe { egl.GetPlatformDisplayEXT(platform, display as *mut _, attrs.as_ptr()) }; - let display = - unsafe { egl.GetPlatformDisplayEXT(platform, display as *mut _, attrs.as_ptr()) }; + let result = Self::check_display_error(display).map(|display| { + if legacy { + // NOTE: For angle we use the Legacy code path, as that uses CreateWindowSurface + // instead of CreatePlatformWindowSurface*. The latter somehow + // doesn't work, only the former does. But Angle's own example also use the + // former: https://github.com/google/angle/blob/main/util/EGLWindow.cpp#L424 + EglDisplay::Legacy(display) + } else { + EglDisplay::Ext(display) + } + }); - Self::check_display_error(display).map(|display| { - if legacy { - // NOTE: For angle we use the Legacy code path, as that uses CreateWindowSurface - // instead of CreatePlatformWindowSurface*. The latter somehow - // doesn't work, only the former does. But Angle's own example also use the - // former: https://github.com/google/angle/blob/main/util/EGLWindow.cpp#L424 - EglDisplay::Legacy(display) - } else { - EglDisplay::Ext(display) + // We can't check for the type of error here because for some reason it doesn't + // always report BadAttribute even though EGL_KHR_display_reference + // was the reason of the failure + if result.is_ok() || result.is_err() && !first_try { + return result; } - }) + + first_try = false; + } } fn get_display(egl: &Egl, display: RawDisplayHandle) -> Result { @@ -525,6 +554,31 @@ pub(crate) struct DisplayInner { pub(crate) _native_display: Option, } +impl DisplayInner { + fn uses_display_reference(&self) -> bool { + if !CLIENT_EXTENSIONS.get().unwrap().contains("EGL_KHR_display_reference") { + return false; + } + + let mut track_references = MaybeUninit::::uninit(); + unsafe { + return match self.raw { + EglDisplay::Khr(khr) => self.egl.QueryDisplayAttribKHR( + khr, + egl::TRACK_REFERENCES_KHR as _, + track_references.as_mut_ptr(), + ), + EglDisplay::Ext(ext) => self.egl.QueryDisplayAttribEXT( + ext, + egl::TRACK_REFERENCES_KHR as _, + track_references.as_mut_ptr(), + ), + EglDisplay::Legacy(_) => egl::FALSE, + } == egl::TRUE; + } + } +} + impl fmt::Debug for DisplayInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Display") @@ -542,25 +596,9 @@ impl Drop for DisplayInner { // reference count the display. If that is the case, glutin can // terminate the display without worry for the instance being // reused elsewhere. - if CLIENT_EXTENSIONS.get().unwrap().contains("EGL_KHR_display_reference") { - let mut track_references = MaybeUninit::::uninit(); + if self.uses_display_reference() { unsafe { - if match self.raw { - EglDisplay::Khr(khr) => self.egl.QueryDisplayAttribKHR( - khr, - egl::TRACK_REFERENCES_KHR as _, - track_references.as_mut_ptr(), - ), - EglDisplay::Ext(ext) => self.egl.QueryDisplayAttribEXT( - ext, - egl::TRACK_REFERENCES_KHR as _, - track_references.as_mut_ptr(), - ), - EglDisplay::Legacy(_) => return, - } == egl::TRUE - { - self.egl.Terminate(*self.raw); - } + self.egl.Terminate(*self.raw); } }