Skip to content

Commit

Permalink
egl: Use EGL_KHR_display_reference
Browse files Browse the repository at this point in the history
This resolves a past issue where glutin would not be able to terminate a display due to risk of two displays being created from the same native display.
  • Loading branch information
i509VCB committed Jun 28, 2023
1 parent f5e08a8 commit 32281af
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- **Breaking:** `GlContext` trait is now a part of the `prelude`.
- Fixed lock on SwapBuffers with some GLX drivers.
- Fixed EGL's `Surface::is_single_buffered` being inversed.
- Use `EGL_KHR_display_reference` if available for EGL.

# Version 0.30.8

Expand Down
47 changes: 37 additions & 10 deletions glutin/src/api/egl/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::collections::HashSet;
use std::ffi::{self, CStr};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::os::raw::c_char;
use std::sync::Arc;
Expand Down Expand Up @@ -126,6 +127,10 @@ impl Display {

let mut attrs = Vec::<EGLint>::with_capacity(2);

if extensions.contains("EGL_KHR_display_reference") {
attrs.push(egl::TRACK_REFERENCES_KHR as _);
}

// TODO: Some extensions exist like EGL_EXT_device_drm which allow specifying
// which DRM master fd to use under the hood by the implementation. This would
// mean there would need to be an unsafe equivalent to this function.
Expand Down Expand Up @@ -192,7 +197,8 @@ impl Display {

let extensions = NO_DISPLAY_EXTENSIONS.get().unwrap();

let mut attrs = Vec::<EGLAttrib>::new();
// Preallocate space for the terminator and to track references.
let mut attrs = Vec::<EGLAttrib>::with_capacity(2);
let (platform, mut display) = match display {
#[cfg(wayland_platform)]
RawDisplayHandle::Wayland(handle)
Expand All @@ -219,6 +225,10 @@ impl Display {
},
};

if extensions.contains("EGL_KHR_display_reference") {
attrs.push(egl::TRACK_REFERENCES_KHR as _);
}

// Be explicit here.
if display.is_null() {
display = egl::DEFAULT_DISPLAY as *mut _;
Expand All @@ -240,7 +250,8 @@ impl Display {

let extensions = NO_DISPLAY_EXTENSIONS.get().unwrap();

let mut attrs = Vec::<EGLint>::new();
// Preallocate space for the terminator and to track references.
let mut attrs = Vec::<EGLint>::with_capacity(2);
let (platform, mut display) = match display {
#[cfg(wayland_platform)]
RawDisplayHandle::Wayland(handle)
Expand Down Expand Up @@ -273,6 +284,10 @@ impl Display {
},
};

if extensions.contains("EGL_KHR_display_reference") {
attrs.push(egl::TRACK_REFERENCES_KHR as _);
}

// Be explicit here.
if display.is_null() {
display = egl::DEFAULT_DISPLAY as *mut _;
Expand Down Expand Up @@ -487,6 +502,26 @@ impl fmt::Debug for DisplayInner {

impl Drop for DisplayInner {
fn drop(&mut self) {
// If the EGL_TRACK_REFERENCES_KHR attribute is true, then EGL will internally
// reference count the display. If that is the case, glutin can
// terminate the display without worry for the instance being
// reused elsewhere.
if self.client_extensions.contains("EGL_KHR_display_reference") {
let mut track_references = MaybeUninit::<u32>::uninit();
unsafe {
self.egl.QueryDisplayAttribEXT(
*self.raw,
egl::TRACK_REFERENCES_KHR as _,
track_references.as_mut_ptr().cast(),
);

if track_references.assume_init() == egl::TRUE {
self.egl.Terminate(*self.raw);
return;
}
}
}

// We cannot call safely call `eglTerminate`.
//
// This may sound confusing, but this is a result of how EGL works:
Expand Down Expand Up @@ -529,14 +564,6 @@ impl Drop for DisplayInner {
// of not dropping the display is negligible because the display will
// probably be destroyed on app termination and we can let the
// operating system deal with tearing down EGL instead.
//
// # Possible future work:
//
// For platform displays, we could track the use of individual raw
// window handles and display attributes (recall the "with the
// same parameters" line) and use that to determine if it is safe to
// terminate the display, but that increases maintenance burden and is
// possibly flaky to implement.

// unsafe { self.egl.Terminate(self.raw) };
}
Expand Down
1 change: 1 addition & 0 deletions glutin_egl_sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ fn main() {
"EGL_EXT_swap_buffers_with_damage",
"EGL_KHR_create_context",
"EGL_KHR_create_context_no_error",
"EGL_KHR_display_reference",
"EGL_KHR_fence_sync",
"EGL_KHR_platform_android",
"EGL_KHR_platform_gbm",
Expand Down

0 comments on commit 32281af

Please sign in to comment.