Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Glutin version 0.32.1 #1697

Merged
merged 10 commits into from
Sep 11, 2024
15 changes: 10 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,23 @@ jobs:
name: Check formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: hecrj/setup-rust-action@v1
- uses: taiki-e/checkout-action@v1
- uses: dtolnay/rust-toolchain@nightly
with:
rust-version: nightly
components: rustfmt
- uses: taiki-e/install-action@v2
with:
tool: typos-cli
- name: Check Formatting
run: cargo +nightly fmt --all -- --check
- name: Run Typos
run: cargo fmt --all -- --check
- name: run typos
run: typos
- name: Typos info
if: failure()
run: |
echo 'To fix typos, please run `typos -w`'
echo 'To check for a diff, run `typos`'
echo 'You can find typos here: https://crates.io/crates/typos'

tests:
name: Tests
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Unreleased

# Version 0.32.1

- Fixed EGL's `Device::query_devices()` being too strict about required extensions.
- Fixed crash in `EglGetProcAddress` on Win32-x86 platform due to wrong calling convention.
- Fixed EGL's `Display::device()` always returning an error due to invalid pointer-argument passing inside.
- Fixed EGL's `Display::new()` making an `EGLDisplay::Khr` when the EGL version for the display is 1.4 or lower.
- Added `Device::drm_device_node_path()` and `Device::drm_render_device_node_path()` getters to EGL via `EGL_EXT_device_drm`.
- Added support for `DrmDisplayHandle` in EGL's `Display::with_device()` using `EGL_DRM_MASTER_FD_EXT` from `EGL_EXT_device_drm`.
- Properly set up OpenGL-specific stuff on the `NSView`, instead of relying on Winit to do it.

# Version 0.32.0

- **Breaking:** updated `raw-window-handle` dependency to `0.6`.
Expand Down
4 changes: 3 additions & 1 deletion glutin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "glutin"
version = "0.32.0"
version = "0.32.1"
authors = ["Kirill Chibisov <[email protected]>"]
description = "Cross-platform OpenGL context provider."
keywords = ["windowing", "opengl", "egl"]
Expand Down Expand Up @@ -66,10 +66,12 @@ features = [
[target.'cfg(any(target_os = "macos"))'.dependencies.objc2-app-kit]
version = "0.2.0"
features = [
"NSApplication",
"NSResponder",
"NSView",
"NSWindow",
"NSOpenGL",
"NSOpenGLView",
]

[build-dependencies]
Expand Down
21 changes: 19 additions & 2 deletions glutin/src/api/cgl/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::marker::PhantomData;
use std::num::NonZeroU32;

use objc2::rc::Id;
use objc2_app_kit::NSView;
use objc2_app_kit::{NSAppKitVersionNumber, NSAppKitVersionNumber10_12, NSView};
use objc2_foundation::{run_on_main, MainThreadBound, MainThreadMarker};
use raw_window_handle::RawWindowHandle;

Expand Down Expand Up @@ -60,12 +60,29 @@ impl Display {
// SAFETY: Validity of the view and window is ensured by caller
// This function makes sure the window is non null.
let ns_view = if let Some(ns_view) =
unsafe { Id::retain(native_window.ns_view.as_ptr().cast()) }
unsafe { Id::retain(native_window.ns_view.as_ptr().cast::<NSView>()) }
{
ns_view
} else {
return Err(ErrorKind::NotSupported("ns_view of provided native window is nil").into());
};

// The default value of `wantsBestResolutionOpenGLSurface` is `false` when
// linked with the macOS 10.14 SDK and `true` if linked with a macOS 10.15 SDK
// or newer. We always set it to `true` because we want High DPI surfaces, and
// we want to avoid this confusing default system value.
#[allow(deprecated)]
ns_view.setWantsBestResolutionOpenGLSurface(true);

// On Mojave, views apparently automatically become layer-backed shortly after
// being added to a window. Changing the layer-backedness of a view breaks the
// association between the view and its associated OpenGL context. To work
// around this, we explicitly make the view layer-backed up front so that AppKit
// doesn't do it itself and break the association with its context.
if unsafe { NSAppKitVersionNumber }.floor() > NSAppKitVersionNumber10_12 {
ns_view.setWantsLayer(true);
}

let ns_view = MainThreadBound::new(ns_view, mtm);

let surface = Surface {
Expand Down
118 changes: 89 additions & 29 deletions glutin/src/api/egl/device.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Everything related to `EGLDevice`.

use std::collections::HashSet;
use std::ffi::{c_void, CStr};
use std::ffi::CStr;
use std::path::Path;
use std::ptr;

use glutin_egl_sys::egl;
Expand All @@ -17,10 +18,15 @@ use super::{Egl, EGL};
pub struct Device {
inner: EGLDeviceEXT,
extensions: HashSet<&'static str>,
name: Option<String>,
vendor: Option<String>,
name: Option<&'static str>,
vendor: Option<&'static str>,
}

// SAFETY: An EGLDevice is immutable and valid for the lifetime of the EGL
// library.
unsafe impl Send for Device {}
unsafe impl Sync for Device {}

impl Device {
/// Query the available devices.
///
Expand All @@ -33,19 +39,25 @@ impl Device {
None => return Err(ErrorKind::NotFound.into()),
};

let no_display_extensions =
let client_extensions =
CLIENT_EXTENSIONS.get_or_init(|| get_extensions(egl, egl::NO_DISPLAY));

// Querying devices requires EGL_EXT_device_enumeration and
// EGL_EXT_device_query.
//
// Or we can check for the EGL_EXT_device_base extension since it contains both
// extensions.
if (!no_display_extensions.contains("EGL_EXT_device_enumeration")
&& !no_display_extensions.contains("EGL_EXT_device_query"))
|| !no_display_extensions.contains("EGL_EXT_device_base")
{
return Err(ErrorKind::NotSupported("EGL does not support EGL_EXT_device_base").into());
// Querying devices requires EGL_EXT_device_enumeration or EGL_EXT_device_base.
if !client_extensions.contains("EGL_EXT_device_base") {
if !client_extensions.contains("EGL_EXT_device_enumeration") {
return Err(ErrorKind::NotSupported(
"Enumerating devices is not supported by the EGL instance",
)
.into());
}
// EGL_EXT_device_enumeration depends on EGL_EXT_device_query,
// so also check that just in case.
if !client_extensions.contains("EGL_EXT_device_query") {
return Err(ErrorKind::NotSupported(
"EGL_EXT_device_enumeration without EGL_EXT_device_query, buggy driver?",
)
.into());
}
}

let mut device_count = 0;
Expand Down Expand Up @@ -87,39 +99,87 @@ impl Device {
///
/// These extensions are distinct from the display extensions and should not
/// be used interchangeably.
pub fn extensions(&self) -> &HashSet<&str> {
pub fn extensions(&self) -> &HashSet<&'static str> {
&self.extensions
}

/// Get the name of the device.
///
/// This function will return [`None`] if the `EGL_EXT_device_query_name`
/// device extension is not available.
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
pub fn name(&self) -> Option<&'static str> {
self.name
}

/// Get the vendor of the device.
///
/// This function will return [`None`] if the `EGL_EXT_device_query_name`
/// device extension is not available.
pub fn vendor(&self) -> Option<&str> {
self.vendor.as_deref()
pub fn vendor(&self) -> Option<&'static str> {
self.vendor
}

/// Get a raw handle to the `EGLDevice`.
pub fn raw_device(&self) -> *const c_void {
pub fn raw_device(&self) -> EGLDeviceEXT {
self.inner
}
}

// SAFETY: An EGLDevice is immutable and valid for the lifetime of the EGL
// library.
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
/// Get the DRM primary or render device node path for this
/// [`EGLDeviceEXT`].
///
/// Requires the [`EGL_EXT_device_drm`] extension.
///
/// If the [`EGL_EXT_device_drm_render_node`] extension is supported, this
/// is guaranteed to return the **primary** device node path, or [`None`].
/// Consult [`Self::drm_render_device_node_path()`] to retrieve the
/// **render** device node path.
///
/// [`EGL_EXT_device_drm`]: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_device_drm.txt
/// [`EGL_EXT_device_drm_render_node`]: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_device_drm_render_node.txt
pub fn drm_device_node_path(&self) -> Option<&'static Path> {
if !self.extensions.contains("EGL_EXT_device_drm") {
return None;
}

impl Device {
unsafe fn query_string(egl_device: *const c_void, name: egl::types::EGLenum) -> Option<String> {
// SAFETY: We pass a valid EGLDevice pointer, and validated that the enum name
// is valid because the extension is present.
unsafe { Self::query_string(self.raw_device(), egl::DRM_DEVICE_FILE_EXT) }.map(Path::new)
}

/// Get the DRM render device node path for this [`EGLDeviceEXT`].
///
/// Requires the [`EGL_EXT_device_drm_render_node`] extension.
///
/// If the [`EGL_EXT_device_drm`] extension is supported in addition to
/// [`EGL_EXT_device_drm_render_node`],
/// consult [`Self::drm_device_node_path()`] to retrieve the **primary**
/// device node path.
///
/// [`EGL_EXT_device_drm`]: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_device_drm.txt
/// [`EGL_EXT_device_drm_render_node`]: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_device_drm_render_node.txt
pub fn drm_render_device_node_path(&self) -> Option<&'static Path> {
if !self.extensions.contains("EGL_EXT_device_drm_render_node") {
return None;
}

const EGL_DRM_RENDER_NODE_PATH_EXT: egl::types::EGLenum = 0x3377;
// SAFETY: We pass a valid EGLDevice pointer, and validated that the enum name
// is valid because the extension is present.
unsafe { Self::query_string(self.raw_device(), EGL_DRM_RENDER_NODE_PATH_EXT) }
.map(Path::new)
}

/// # Safety
/// The caller must pass a valid `egl_device` pointer and must ensure that
/// `name` is valid for this device, i.e. by guaranteeing that the
/// extension that introduces it is present.
///
/// The returned string is `'static` for the lifetime of the globally loaded
/// EGL library in [`EGL`].
unsafe fn query_string(
egl_device: EGLDeviceEXT,
name: egl::types::EGLenum,
) -> Option<&'static str> {
let egl = super::EGL.as_ref().unwrap();

// SAFETY: The caller has ensured the name is valid.
Expand All @@ -129,10 +189,10 @@ impl Device {
return None;
}

unsafe { CStr::from_ptr(ptr) }.to_str().ok().map(String::from)
unsafe { CStr::from_ptr(ptr) }.to_str().ok()
}

pub(crate) fn from_ptr(egl: &Egl, ptr: *const c_void) -> Result<Self> {
pub(crate) fn from_ptr(egl: &Egl, ptr: EGLDeviceEXT) -> Result<Self> {
// SAFETY: The EGL specification guarantees the returned string is
// static and null terminated:
//
Expand Down
Loading
Loading