Skip to content

Commit

Permalink
Port to raw-window-handle v0.6
Browse files Browse the repository at this point in the history
Support for GLX

Partial EGL support

Finish out full glutin implementation

Port over aux. crates

Fix doctests

Fix eminent compile errors

Signed-off-by: John Nunley <[email protected]>

Update CHANGELOG.md

Signed-off-by: John Nunley <[email protected]>

Add accessors for display and window

Signed-off-by: John Nunley <[email protected]>
  • Loading branch information
notgull committed Jan 11, 2024
1 parent 719671f commit 967f3f4
Show file tree
Hide file tree
Showing 31 changed files with 1,594 additions and 993 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Unreleased

- **Breaking:** Bump `raw-window-handle` to v0.6.
- **Breaking:** Make `glutin` types generic over the window/display they are wrapping.

# Version 0.31.2

- Fixed EGL not setting context version with EGL versions before 1.5 and missing context ext.
Expand Down
4 changes: 2 additions & 2 deletions glutin-winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ wayland = ["glutin/wayland", "winit/wayland"]

[dependencies]
glutin = { version = "0.31.0", path = "../glutin", default-features = false }
raw-window-handle = "0.5.2"
winit = { version = "0.29.2", default-features = false, features = ["rwh_05"] }
raw-window-handle = { version = "0.6.0", features = ["std"] }
winit = { version = "0.29.2", default-features = false, features = ["rwh_06"] }

[build-dependencies]
cfg_aliases = "0.1.1"
44 changes: 30 additions & 14 deletions glutin-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use glutin::platform::x11::X11GlConfigExt;
use glutin::prelude::*;

#[cfg(wgl_backend)]
use raw_window_handle::HasRawWindowHandle;
use raw_window_handle::HasWindowHandle;
use raw_window_handle::{DisplayHandle, HasDisplayHandle, WindowHandle};

use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle};
use winit::error::OsError;
use winit::event_loop::EventLoopWindowTarget;
use winit::window::{Window, WindowBuilder};
Expand Down Expand Up @@ -86,14 +86,20 @@ impl DisplayBuilder {
/// **WGL:** - [`WindowBuilder`] **must** be passed in
/// [`Self::with_window_builder`] if modern OpenGL(ES) is desired,
/// otherwise only builtin functions like `glClear` will be available.
///
/// # Safety
///
/// The `Config` must not outlive the `EventLoop`.
pub fn build<T, Picker>(
mut self,
window_target: &EventLoopWindowTarget<T>,
template_builder: ConfigTemplateBuilder,
template_builder: ConfigTemplateBuilder<WindowHandle<'_>>,
config_picker: Picker,
) -> Result<(Option<Window>, Config), Box<dyn Error>>
) -> Result<(Option<Window>, Config<DisplayHandle<'static>>), Box<dyn Error>>
where
Picker: FnOnce(Box<dyn Iterator<Item = Config> + '_>) -> Config,
Picker: FnOnce(
Box<dyn Iterator<Item = Config<DisplayHandle<'static>>> + '_>,
) -> Config<DisplayHandle<'static>>,
{
// XXX with WGL backend window should be created first.
#[cfg(wgl_backend)]
Expand All @@ -104,11 +110,13 @@ impl DisplayBuilder {
};

#[cfg(wgl_backend)]
let raw_window_handle = window.as_ref().map(|window| window.raw_window_handle());
let raw_window_handle = window.as_ref().map(|w| w.window_handle()).transpose()?;
#[cfg(not(wgl_backend))]
let raw_window_handle = None;

let gl_display = create_display(window_target, self.preference, raw_window_handle)?;
// SAFETY: Will not outlive the event loop.
let gl_display =
unsafe { create_display(window_target, self.preference, raw_window_handle)? };

// XXX the native window must be passed to config picker when WGL is used
// otherwise very limited OpenGL features will be supported.
Expand All @@ -121,7 +129,7 @@ impl DisplayBuilder {

let template = template_builder.build();

let gl_config = unsafe {
let gl_config = {
let configs = gl_display.find_configs(template)?;
config_picker(configs)
};
Expand All @@ -137,11 +145,16 @@ impl DisplayBuilder {
}
}

fn create_display<T>(
/// Create the actual display.
///
/// # Safety
///
/// The `Display` must not outlive the `EventLoop`.
unsafe fn create_display<T>(
window_target: &EventLoopWindowTarget<T>,
_api_preference: ApiPreference,
_raw_window_handle: Option<RawWindowHandle>,
) -> Result<Display, Box<dyn Error>> {
_raw_window_handle: Option<WindowHandle<'_>>,
) -> Result<Display<DisplayHandle<'static>>, Box<dyn Error>> {
#[cfg(egl_backend)]
let _preference = DisplayApiPreference::Egl;

Expand Down Expand Up @@ -170,7 +183,10 @@ fn create_display<T>(
ApiPreference::FallbackEgl => DisplayApiPreference::WglThenEgl(_raw_window_handle),
};

unsafe { Ok(Display::new(window_target.raw_display_handle(), _preference)?) }
// SAFETY: Does not outlive the event loop.
let display_handle =
unsafe { DisplayHandle::borrow_raw(window_target.display_handle()?.as_raw()) };
Ok(Display::new(display_handle, _preference)?)
}

/// Finalize [`Window`] creation by applying the options from the [`Config`], be
Expand All @@ -179,10 +195,10 @@ fn create_display<T>(
///
/// [`Window`]: winit::window::Window
/// [`Config`]: glutin::config::Config
pub fn finalize_window<T>(
pub fn finalize_window<D: HasDisplayHandle, T>(
window_target: &EventLoopWindowTarget<T>,
mut builder: WindowBuilder,
gl_config: &Config,
gl_config: &Config<D>,
) -> Result<Window, OsError> {
// Disable transparency if the end config doesn't support it.
if gl_config.supports_transparency() == Some(false) {
Expand Down
62 changes: 35 additions & 27 deletions glutin-winit/src/window.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use std::num::NonZeroU32;

use glutin::context::PossiblyCurrentContext;
use glutin::surface::{
GlSurface, ResizeableSurface, Surface, SurfaceAttributes, SurfaceAttributesBuilder,
SurfaceTypeTrait, WindowSurface,
};
use raw_window_handle::HasRawWindowHandle;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use std::num::NonZeroU32;
use winit::window::Window;

/// [`Window`] extensions for working with [`glutin`] surfaces.
pub trait GlWindow {
pub trait GlWindow: HasWindowHandle + Sized {
/// Build the surface attributes suitable to create a window surface.
///
/// # Panics
Expand All @@ -23,9 +22,9 @@ pub trait GlWindow {
/// let attrs = winit_window.build_surface_attributes(<_>::default());
/// ```
fn build_surface_attributes(
&self,
builder: SurfaceAttributesBuilder<WindowSurface>,
) -> SurfaceAttributes<WindowSurface>;
self,
builder: SurfaceAttributesBuilder<WindowSurface<Self>>,
) -> SurfaceAttributes<WindowSurface<Self>>;

/// Resize the surface to the window inner size.
///
Expand All @@ -36,37 +35,46 @@ pub trait GlWindow {
/// use glutin_winit::GlWindow;
/// # use glutin::surface::{Surface, WindowSurface};
/// # let winit_window: winit::window::Window = unimplemented!();
/// # let (gl_surface, gl_context): (Surface<WindowSurface>, _) = unimplemented!();
/// # let (gl_surface, gl_context): (Surface<glutin::NoDisplay, WindowSurface<glutin::NoWindow>>, _) = unimplemented!();
///
/// winit_window.resize_surface(&gl_surface, &gl_context);
/// ```
fn resize_surface(
fn resize_surface<D: HasDisplayHandle>(
&self,
surface: &Surface<impl SurfaceTypeTrait + ResizeableSurface>,
context: &PossiblyCurrentContext,
surface: &Surface<D, impl SurfaceTypeTrait + ResizeableSurface>,
context: &PossiblyCurrentContext<D>,
);
}

impl GlWindow for Window {
fn build_surface_attributes(
&self,
builder: SurfaceAttributesBuilder<WindowSurface>,
) -> SurfaceAttributes<WindowSurface> {
let (w, h) = self.inner_size().non_zero().expect("invalid zero inner size");
builder.build(self.raw_window_handle(), w, h)
}
macro_rules! implement_glwindow {
(<$($lt:lifetime)?> $ty:ty) => {
impl<$($lt)?> GlWindow for $ty {
fn build_surface_attributes(
self,
builder: SurfaceAttributesBuilder<WindowSurface<Self>>,
) -> SurfaceAttributes<WindowSurface<Self>> {
let (w, h) = self.inner_size().non_zero().expect("invalid zero inner size");
builder.build(self, w, h)
}

fn resize_surface(
&self,
surface: &Surface<impl SurfaceTypeTrait + ResizeableSurface>,
context: &PossiblyCurrentContext,
) {
if let Some((w, h)) = self.inner_size().non_zero() {
surface.resize(context, w, h)
fn resize_surface<D: HasDisplayHandle>(
&self,
surface: &Surface<D, impl SurfaceTypeTrait + ResizeableSurface>,
context: &PossiblyCurrentContext<D>,
) {
if let Some((w, h)) = self.inner_size().non_zero() {
surface.resize(context, w, h)
}
}
}
}
};
}

implement_glwindow!(<> Window);
implement_glwindow!(<'a> &'a Window);
implement_glwindow!(<> std::rc::Rc<Window>);
implement_glwindow!(<> std::sync::Arc<Window>);

/// [`winit::dpi::PhysicalSize<u32>`] non-zero extensions.
trait NonZeroU32PhysicalSize {
/// Converts to non-zero `(width, height)`.
Expand Down
2 changes: 1 addition & 1 deletion glutin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ wayland = ["wayland-sys", "egl"]
bitflags = "2.2.1"
libloading = { version = "0.8.0", optional = true }
once_cell = "1.13"
raw-window-handle = "0.5.2"
raw-window-handle = "0.6.0"

[target.'cfg(windows)'.dependencies]
glutin_egl_sys = { version = "0.6.0", path = "../glutin_egl_sys", optional = true }
Expand Down
51 changes: 33 additions & 18 deletions glutin/src/api/cgl/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use icrate::AppKit::{
NSOpenGLProfileVersion4_1Core, NSOpenGLProfileVersionLegacy,
};
use objc2::rc::Id;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};

use crate::config::{
Api, AsRawConfig, ColorBufferType, ConfigSurfaceTypes, ConfigTemplate, GlConfig, RawConfig,
Expand All @@ -24,12 +25,12 @@ use crate::private::Sealed;
use super::appkit::NSOpenGLPixelFormat;
use super::display::Display;

impl Display {
impl<D: HasDisplayHandle> Display<D> {
#[allow(deprecated)]
pub(crate) unsafe fn find_configs(
pub(crate) fn find_configs<W: HasWindowHandle>(
&self,
template: ConfigTemplate,
) -> Result<Box<dyn Iterator<Item = Config> + '_>> {
template: ConfigTemplate<W>,
) -> Result<Box<dyn Iterator<Item = Config<D>> + '_>> {
let mut attrs = Vec::<NSOpenGLPixelFormatAttribute>::with_capacity(32);

// We use minimum to follow behavior of other platforms here.
Expand Down Expand Up @@ -129,12 +130,26 @@ impl Display {
}

/// A wrapper around NSOpenGLPixelFormat.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config {
pub(crate) inner: Arc<ConfigInner>,
#[derive(Debug)]
pub struct Config<D> {
pub(crate) inner: Arc<ConfigInner<D>>,
}

impl Config {
impl<D> Clone for Config<D> {
fn clone(&self) -> Self {
Self { inner: self.inner.clone() }
}
}

impl<D> PartialEq for Config<D> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}

impl<D> Eq for Config<D> {}

impl<D: HasDisplayHandle> Config<D> {
fn raw_attribute(&self, attrib: NSOpenGLPixelFormatAttribute) -> i32 {
unsafe {
let mut value = 0;
Expand All @@ -156,7 +171,7 @@ impl Config {
}

#[allow(deprecated)]
impl GlConfig for Config {
impl<D: HasDisplayHandle> GlConfig for Config<D> {
fn color_buffer_type(&self) -> Option<ColorBufferType> {
// On macos all color formats divide by 3 without reminder, except for the RGB
// 565. So we can convert it in a hopefully reliable way. Also we should remove
Expand Down Expand Up @@ -209,37 +224,37 @@ impl GlConfig for Config {
}
}

impl GetGlDisplay for Config {
type Target = Display;
impl<D: HasDisplayHandle> GetGlDisplay for Config<D> {
type Target = Display<D>;

fn display(&self) -> Self::Target {
self.inner.display.clone()
}
}

impl AsRawConfig for Config {
impl<D: HasDisplayHandle> AsRawConfig for Config<D> {
fn raw_config(&self) -> RawConfig {
RawConfig::Cgl(Id::as_ptr(&self.inner.raw).cast())
}
}

impl Sealed for Config {}
impl<D: HasDisplayHandle> Sealed for Config<D> {}

pub(crate) struct ConfigInner {
display: Display,
pub(crate) struct ConfigInner<D> {
display: Display<D>,
pub(crate) transparency: bool,
pub(crate) raw: Id<NSOpenGLPixelFormat>,
}

impl PartialEq for ConfigInner {
impl<D> PartialEq for ConfigInner<D> {
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}

impl Eq for ConfigInner {}
impl<D> Eq for ConfigInner<D> {}

impl fmt::Debug for ConfigInner {
impl<D> fmt::Debug for ConfigInner<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Config").field("id", &self.raw).finish()
}
Expand Down
Loading

0 comments on commit 967f3f4

Please sign in to comment.