Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- On GLX, fixed handling of errors not directly requested by glutin.
- Added `GlConfig::hardware_accelerated` to check if the config is hardware accelerated.
- Added `GlContext::context_api` to get the `ContextApi` used by the context.
- Added missing implementations of `Surface::{width,height}` for WGL/CGL
- Fixed crash when accessing context from the off-thread on macOS.
- **Clarified that `make_{,not}_current()`, `GlSurface::width()`, `GlSurface::height()`, and `GlSurface::resize()` could block on macOS.**

# Version 0.30.3

Expand Down
3 changes: 2 additions & 1 deletion glutin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ glutin_egl_sys = { version = "0.3.1", path = "../glutin_egl_sys", optional = tru
glutin_wgl_sys = { version = "0.3.0", path = "../glutin_wgl_sys", optional = true }

[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.36"
version = "0.45"
features = [
"Win32_Foundation",
"Win32_Graphics_Gdi",
Expand All @@ -53,6 +53,7 @@ x11-dl = { version = "2.20.0", optional = true }
cgl = "0.3.2"
core-foundation = "0.9.3"
objc2 = "=0.3.0-beta.3"
dispatch = "0.2.0"

[build-dependencies]
cfg_aliases = "0.1.1"
Expand Down
33 changes: 32 additions & 1 deletion glutin/src/api/cgl/appkit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,46 @@
//! TODO: Move this to another crate.
#![allow(dead_code)]
#![allow(non_snake_case)]

use std::ops::Deref;

use dispatch::Queue;
use objc2::encode::{Encoding, RefEncode};
use objc2::foundation::{NSInteger, NSObject};
use objc2::foundation::{is_main_thread, NSInteger, NSObject};
use objc2::rc::{Id, Shared};
use objc2::{extern_class, extern_methods, msg_send_id, ClassType};

pub type GLint = i32;

pub enum CGLContextObj {}

// XXX borrowed from winit.

// Unsafe wrapper type that allows us to dispatch things that aren't Send.
// This should *only* be used to dispatch to the main queue.
// While it is indeed not guaranteed that these types can safely be sent to
// other threads, we know that they're safe to use on the main thread.
pub(crate) struct MainThreadSafe<T>(pub(crate) T);

unsafe impl<T> Send for MainThreadSafe<T> {}

impl<T> Deref for MainThreadSafe<T> {
type Target = T;

fn deref(&self) -> &T {
&self.0
}
}

/// Run closure on the main thread.
pub(crate) fn run_on_main<R: Send>(f: impl FnOnce() -> R + Send) -> R {
if is_main_thread() {
f()
} else {
Queue::main().exec_sync(f)
}
}

unsafe impl RefEncode for CGLContextObj {
const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Struct("_CGLContextObject", &[]));
}
Expand Down
19 changes: 14 additions & 5 deletions glutin/src/api/cgl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::prelude::*;
use crate::private::Sealed;
use crate::surface::{SurfaceTypeTrait, SwapInterval};

use super::appkit::{NSOpenGLCPSwapInterval, NSOpenGLContext};
use super::appkit::{run_on_main, MainThreadSafe, NSOpenGLCPSwapInterval, NSOpenGLContext};
use super::config::Config;
use super::display::Display;
use super::surface::Surface;
Expand Down Expand Up @@ -218,9 +218,15 @@ impl ContextInner {

fn make_current<T: SurfaceTypeTrait>(&self, surface: &Surface<T>) -> Result<()> {
autoreleasepool(|_| {
self.raw.update();
self.update();
self.raw.makeCurrentContext();
unsafe { self.raw.setView(Some(&surface.ns_view)) };
let raw = MainThreadSafe(&self.raw);
let ns_view = MainThreadSafe(&surface.ns_view);

run_on_main(move || unsafe {
raw.setView(Some(*ns_view));
});

Ok(())
})
}
Expand All @@ -241,7 +247,10 @@ impl ContextInner {
}

pub(crate) fn update(&self) {
self.raw.update();
let raw = MainThreadSafe(&self.raw);
run_on_main(move || {
raw.update();
});
}

pub(crate) fn flush_buffer(&self) -> Result<()> {
Expand All @@ -256,7 +265,7 @@ impl ContextInner {
}

fn make_not_current(&self) -> Result<()> {
self.raw.update();
self.update();
NSOpenGLContext::clearCurrentContext();
Ok(())
}
Expand Down
48 changes: 40 additions & 8 deletions glutin/src/api/cgl/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use std::fmt;
use std::marker::PhantomData;
use std::num::NonZeroU32;

use objc2::foundation::NSObject;
use objc2::foundation::{CGFloat, NSObject, NSRect};
use objc2::msg_send;
use objc2::rc::{Id, Shared};
use raw_window_handle::RawWindowHandle;

Expand All @@ -17,6 +18,7 @@ use crate::surface::{
SurfaceTypeTrait, SwapInterval, WindowSurface,
};

use super::appkit::{run_on_main, MainThreadSafe};
use super::config::Config;
use super::context::PossiblyCurrentContext;
use super::display::Display;
Expand Down Expand Up @@ -52,11 +54,28 @@ impl Display {
},
};

// SAFETY: Validity of the view is ensured by caller
let ns_view =
unsafe { Id::retain(native_window.ns_view.cast()) }.expect("NSView to be non-null");
let surface =
Surface { display: self.clone(), config: config.clone(), ns_view, _ty: PhantomData };
// SAFETY: Validity of the view and window is ensured by caller
let ns_view = if let Some(ns_view) = unsafe { Id::retain(native_window.ns_view.cast()) } {
ns_view
} else {
return Err(ErrorKind::NotSupported("ns_view of provided native window is nil").into());
};

let ns_window = if let Some(ns_window) =
unsafe { Id::retain(native_window.ns_window.cast()) }
{
ns_window
} else {
return Err(ErrorKind::NotSupported("ns_view of provided native window is nil").into());
};

let surface = Surface {
display: self.clone(),
config: config.clone(),
ns_view,
ns_window,
_ty: PhantomData,
};
Ok(surface)
}
}
Expand All @@ -66,6 +85,7 @@ pub struct Surface<T: SurfaceTypeTrait> {
display: Display,
config: Config,
pub(crate) ns_view: Id<NSObject, Shared>,
ns_window: Id<NSObject, Shared>,
_ty: PhantomData<T>,
}

Expand All @@ -78,11 +98,23 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
}

fn width(&self) -> Option<u32> {
None
let ns_window = MainThreadSafe(&self.ns_window);
let ns_view = MainThreadSafe(&self.ns_view);
run_on_main(move || unsafe {
let scale_factor: CGFloat = msg_send![*ns_window, backingScaleFactor];
let frame: NSRect = msg_send![*ns_view, frame];
Some((frame.size.width * scale_factor) as u32)
})
}

fn height(&self) -> Option<u32> {
None
let ns_window = MainThreadSafe(&self.ns_window);
let ns_view = MainThreadSafe(&self.ns_view);
run_on_main(move || unsafe {
let scale_factor: CGFloat = msg_send![*ns_window, backingScaleFactor];
let frame: NSRect = msg_send![*ns_view, frame];
Some((frame.size.height * scale_factor) as u32)
})
}

fn is_single_buffered(&self) -> bool {
Expand Down
19 changes: 15 additions & 4 deletions glutin/src/api/wgl/surface.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! A wrapper around `HWND` used for GL operations.

use std::fmt;
use std::io::Error as IoError;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::{fmt, mem};

use raw_window_handle::RawWindowHandle;
use windows_sys::Win32::Foundation::HWND;
use windows_sys::Win32::Foundation::{HWND, RECT};
use windows_sys::Win32::Graphics::Gdi::HDC;
use windows_sys::Win32::Graphics::{Gdi as gdi, OpenGL as gl};
use windows_sys::Win32::UI::WindowsAndMessaging::GetClientRect;

use crate::config::GetGlConfig;
use crate::display::{DisplayFeatures, GetGlDisplay};
Expand Down Expand Up @@ -93,11 +94,21 @@ impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
}

fn width(&self) -> Option<u32> {
None
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(self.hwnd, &mut rect) } == false.into() {
None
} else {
Some((rect.right - rect.left) as u32)
}
}

fn height(&self) -> Option<u32> {
None
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { GetClientRect(self.hwnd, &mut rect) } == false.into() {
None
} else {
Some((rect.bottom - rect.top) as u32)
}
}

fn is_single_buffered(&self) -> bool {
Expand Down
12 changes: 12 additions & 0 deletions glutin/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ pub trait NotCurrentGlContextSurfaceAccessor<T: SurfaceTypeTrait>: Sealed {
/// Make [`Self::Surface`] on the calling thread producing the
/// [`Self::PossiblyCurrentContext`] indicating that the context could
/// be current on the theard.
///
/// # Platform specific
///
/// **macOS:** - **This will block if your main thread is blocked.**
fn make_current(self, surface: &Self::Surface) -> Result<Self::PossiblyCurrentContext>;

/// The same as [`Self::make_current`], but provides a way to set read and
Expand All @@ -85,6 +89,10 @@ pub trait PossiblyCurrentGlContext: Sealed {
/// Make the context not current to the current thread and returns a
/// [`Self::NotCurrentContext`] to indicate that the context is a not
/// current to allow sending it to the different thread.
///
/// # Platform specific
///
/// **macOS:** - **This will block if your main thread is blocked.**
fn make_not_current(self) -> Result<Self::NotCurrentContext>;
}

Expand All @@ -94,6 +102,10 @@ pub trait PossiblyCurrentContextGlSurfaceAccessor<T: SurfaceTypeTrait>: Sealed {
type Surface: GlSurface<T>;

/// Make [`Self::Surface`] current on the calling thread.
///
/// # Platform specific
///
/// **macOS:** - **This will block if your main thread is blocked.**
fn make_current(&self, surface: &Self::Surface) -> Result<()>;

/// The same as [`Self::make_current`] but provides a way to set read and
Expand Down
14 changes: 11 additions & 3 deletions glutin/src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,21 @@ pub trait GlSurface<T: SurfaceTypeTrait>: Sealed {
/// its age. In both cases you must redraw the entire buffer.
fn buffer_age(&self) -> u32;

/// The width of the underlying surface.
/// The **physical** width of the underlying surface.
fn width(&self) -> Option<u32>;

/// The height of the underlying surface.
/// The **physical** height of the underlying surface.
///
/// # Platform specific
///
/// **macOS:** - **This will block if your main thread is blocked.**
fn height(&self) -> Option<u32>;

/// Check whether the surface is single buffered.
///
/// # Platform specific
///
/// **macOS:** - **This will block if your main thread is blocked.**
fn is_single_buffered(&self) -> bool;

/// Swaps the underlying back buffers when the surface is not single
Expand Down Expand Up @@ -68,7 +76,7 @@ pub trait GlSurface<T: SurfaceTypeTrait>: Sealed {
/// # Platform specific
///
/// **Wayland:** - resizes the surface.
/// **macOS:** - resizes the context to fit the surface.
/// **macOS:** - **This will block if your main thread is blocked.**
/// **Other:** - no op.
fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32)
where
Expand Down
2 changes: 1 addition & 1 deletion glutin_egl_sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ edition = "2021"
gl_generator = "0.14"

[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.36"
version = "0.45"
features = [
"Win32_Foundation",
]