From 967f3f4872d73ebbd2582dbe9f02266c42a7f3bb Mon Sep 17 00:00:00 2001 From: John Nunley Date: Fri, 14 Jul 2023 22:10:09 -0700 Subject: [PATCH] Port to raw-window-handle v0.6 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 Update CHANGELOG.md Signed-off-by: John Nunley Add accessors for display and window Signed-off-by: John Nunley --- CHANGELOG.md | 3 + glutin-winit/Cargo.toml | 4 +- glutin-winit/src/lib.rs | 44 ++-- glutin-winit/src/window.rs | 62 +++--- glutin/Cargo.toml | 2 +- glutin/src/api/cgl/config.rs | 51 +++-- glutin/src/api/cgl/context.rs | 96 +++++---- glutin/src/api/cgl/display.rs | 92 +++++--- glutin/src/api/cgl/surface.rs | 96 +++++---- glutin/src/api/egl/config.rs | 82 ++++--- glutin/src/api/egl/context.rs | 104 ++++----- glutin/src/api/egl/display.rs | 171 +++++++++------ glutin/src/api/egl/surface.rs | 149 +++++++------ glutin/src/api/glx/config.rs | 58 +++-- glutin/src/api/glx/context.rs | 111 +++++----- glutin/src/api/glx/display.rs | 142 ++++++++----- glutin/src/api/glx/surface.rs | 92 +++++--- glutin/src/api/wgl/config.rs | 79 ++++--- glutin/src/api/wgl/context.rs | 122 ++++++----- glutin/src/api/wgl/display.rs | 161 +++++++++----- glutin/src/api/wgl/mod.rs | 6 +- glutin/src/api/wgl/surface.rs | 96 +++++---- glutin/src/config.rs | 183 ++++++++++++---- glutin/src/context.rs | 86 ++++---- glutin/src/display.rs | 283 +++++++++++++++---------- glutin/src/error.rs | 25 +++ glutin/src/lib.rs | 26 +++ glutin/src/surface.rs | 118 +++++++---- glutin_examples/Cargo.toml | 2 +- glutin_examples/examples/egl_device.rs | 16 +- glutin_examples/src/lib.rs | 25 ++- 31 files changed, 1594 insertions(+), 993 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9a5cccb40..d89f76c19c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/glutin-winit/Cargo.toml b/glutin-winit/Cargo.toml index a633df2426..e26b688264 100644 --- a/glutin-winit/Cargo.toml +++ b/glutin-winit/Cargo.toml @@ -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" diff --git a/glutin-winit/src/lib.rs b/glutin-winit/src/lib.rs index d0af719047..282b4ac449 100644 --- a/glutin-winit/src/lib.rs +++ b/glutin-winit/src/lib.rs @@ -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}; @@ -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( mut self, window_target: &EventLoopWindowTarget, - template_builder: ConfigTemplateBuilder, + template_builder: ConfigTemplateBuilder>, config_picker: Picker, - ) -> Result<(Option, Config), Box> + ) -> Result<(Option, Config>), Box> where - Picker: FnOnce(Box + '_>) -> Config, + Picker: FnOnce( + Box>> + '_>, + ) -> Config>, { // XXX with WGL backend window should be created first. #[cfg(wgl_backend)] @@ -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. @@ -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) }; @@ -137,11 +145,16 @@ impl DisplayBuilder { } } -fn create_display( +/// Create the actual display. +/// +/// # Safety +/// +/// The `Display` must not outlive the `EventLoop`. +unsafe fn create_display( window_target: &EventLoopWindowTarget, _api_preference: ApiPreference, - _raw_window_handle: Option, -) -> Result> { + _raw_window_handle: Option>, +) -> Result>, Box> { #[cfg(egl_backend)] let _preference = DisplayApiPreference::Egl; @@ -170,7 +183,10 @@ fn create_display( 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 @@ -179,10 +195,10 @@ fn create_display( /// /// [`Window`]: winit::window::Window /// [`Config`]: glutin::config::Config -pub fn finalize_window( +pub fn finalize_window( window_target: &EventLoopWindowTarget, mut builder: WindowBuilder, - gl_config: &Config, + gl_config: &Config, ) -> Result { // Disable transparency if the end config doesn't support it. if gl_config.supports_transparency() == Some(false) { diff --git a/glutin-winit/src/window.rs b/glutin-winit/src/window.rs index 09d1717f01..594dc3e9c8 100644 --- a/glutin-winit/src/window.rs +++ b/glutin-winit/src/window.rs @@ -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 @@ -23,9 +22,9 @@ pub trait GlWindow { /// let attrs = winit_window.build_surface_attributes(<_>::default()); /// ``` fn build_surface_attributes( - &self, - builder: SurfaceAttributesBuilder, - ) -> SurfaceAttributes; + self, + builder: SurfaceAttributesBuilder>, + ) -> SurfaceAttributes>; /// Resize the surface to the window inner size. /// @@ -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, _) = unimplemented!(); + /// # let (gl_surface, gl_context): (Surface>, _) = unimplemented!(); /// /// winit_window.resize_surface(&gl_surface, &gl_context); /// ``` - fn resize_surface( + fn resize_surface( &self, - surface: &Surface, - context: &PossiblyCurrentContext, + surface: &Surface, + context: &PossiblyCurrentContext, ); } -impl GlWindow for Window { - fn build_surface_attributes( - &self, - builder: SurfaceAttributesBuilder, - ) -> SurfaceAttributes { - 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>, + ) -> SurfaceAttributes> { + let (w, h) = self.inner_size().non_zero().expect("invalid zero inner size"); + builder.build(self, w, h) + } - fn resize_surface( - &self, - surface: &Surface, - context: &PossiblyCurrentContext, - ) { - if let Some((w, h)) = self.inner_size().non_zero() { - surface.resize(context, w, h) + fn resize_surface( + &self, + surface: &Surface, + context: &PossiblyCurrentContext, + ) { + 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); +implement_glwindow!(<> std::sync::Arc); + /// [`winit::dpi::PhysicalSize`] non-zero extensions. trait NonZeroU32PhysicalSize { /// Converts to non-zero `(width, height)`. diff --git a/glutin/Cargo.toml b/glutin/Cargo.toml index 4e8e6f2417..1648025454 100644 --- a/glutin/Cargo.toml +++ b/glutin/Cargo.toml @@ -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 } diff --git a/glutin/src/api/cgl/config.rs b/glutin/src/api/cgl/config.rs index f1377039fa..24cf7550e5 100644 --- a/glutin/src/api/cgl/config.rs +++ b/glutin/src/api/cgl/config.rs @@ -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, @@ -24,12 +25,12 @@ use crate::private::Sealed; use super::appkit::NSOpenGLPixelFormat; use super::display::Display; -impl Display { +impl Display { #[allow(deprecated)] - pub(crate) unsafe fn find_configs( + pub(crate) fn find_configs( &self, - template: ConfigTemplate, - ) -> Result + '_>> { + template: ConfigTemplate, + ) -> Result> + '_>> { let mut attrs = Vec::::with_capacity(32); // We use minimum to follow behavior of other platforms here. @@ -129,12 +130,26 @@ impl Display { } /// A wrapper around NSOpenGLPixelFormat. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Config { - pub(crate) inner: Arc, +#[derive(Debug)] +pub struct Config { + pub(crate) inner: Arc>, } -impl Config { +impl Clone for Config { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for Config {} + +impl Config { fn raw_attribute(&self, attrib: NSOpenGLPixelFormatAttribute) -> i32 { unsafe { let mut value = 0; @@ -156,7 +171,7 @@ impl Config { } #[allow(deprecated)] -impl GlConfig for Config { +impl GlConfig for Config { fn color_buffer_type(&self) -> Option { // 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 @@ -209,37 +224,37 @@ impl GlConfig for Config { } } -impl GetGlDisplay for Config { - type Target = Display; +impl GetGlDisplay for Config { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawConfig for Config { +impl AsRawConfig for Config { fn raw_config(&self) -> RawConfig { RawConfig::Cgl(Id::as_ptr(&self.inner.raw).cast()) } } -impl Sealed for Config {} +impl Sealed for Config {} -pub(crate) struct ConfigInner { - display: Display, +pub(crate) struct ConfigInner { + display: Display, pub(crate) transparency: bool, pub(crate) raw: Id, } -impl PartialEq for ConfigInner { +impl PartialEq for ConfigInner { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } -impl Eq for ConfigInner {} +impl Eq for ConfigInner {} -impl fmt::Debug for ConfigInner { +impl fmt::Debug for ConfigInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Config").field("id", &self.raw).finish() } diff --git a/glutin/src/api/cgl/context.rs b/glutin/src/api/cgl/context.rs index 301ea00d8c..6fde39bf9c 100644 --- a/glutin/src/api/cgl/context.rs +++ b/glutin/src/api/cgl/context.rs @@ -8,6 +8,7 @@ use icrate::AppKit::{NSOpenGLCPSwapInterval, NSView}; use icrate::Foundation::{MainThreadBound, MainThreadMarker}; use objc2::rc::{autoreleasepool, Id}; use objc2::ClassType; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use crate::config::GetGlConfig; use crate::context::{AsRawContext, ContextApi, ContextAttributes, RawContext, Robustness}; @@ -22,24 +23,24 @@ use super::config::Config; use super::display::Display; use super::surface::Surface; -impl Display { - pub(crate) unsafe fn create_context( +impl Display { + pub(crate) fn create_context( &self, - config: &Config, - context_attributes: &ContextAttributes, - ) -> Result { - let share_context = match context_attributes.shared_context.as_ref() { + config: &Config, + context_attributes: &ContextAttributes, + ) -> Result> { + let share_context = match context_attributes.inner.shared_context.as_ref() { Some(RawContext::Cgl(share_context)) => unsafe { share_context.cast::().as_ref() }, _ => None, }; - if matches!(context_attributes.api, Some(ContextApi::Gles(_))) { + if matches!(context_attributes.inner.api, Some(ContextApi::Gles(_))) { return Err(ErrorKind::NotSupported("gles is not supported with CGL").into()); } - if context_attributes.robustness != Robustness::NotRobust { + if context_attributes.inner.robustness != Robustness::NotRobust { return Err(ErrorKind::NotSupported("robustness is not supported with CGL").into()); } @@ -68,22 +69,22 @@ impl Display { /// A wrapper arounh `NSOpenGLContext` that is known to be not current on the /// current thread. #[derive(Debug)] -pub struct NotCurrentContext { - pub(crate) inner: ContextInner, +pub struct NotCurrentContext { + pub(crate) inner: ContextInner, _nosync: PhantomData>, } -impl NotCurrentContext { - fn new(inner: ContextInner) -> Self { +impl NotCurrentContext { + fn new(inner: ContextInner) -> Self { Self { inner, _nosync: PhantomData } } } -impl NotCurrentGlContext for NotCurrentContext { - type PossiblyCurrentContext = PossiblyCurrentContext; - type Surface = Surface; +impl NotCurrentGlContext for NotCurrentContext { + type PossiblyCurrentContext = PossiblyCurrentContext; + type Surface = Surface; - fn treat_as_possibly_current(self) -> PossiblyCurrentContext { + fn treat_as_possibly_current(self) -> PossiblyCurrentContext { PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData } } @@ -104,48 +105,48 @@ impl NotCurrentGlContext for NotCurrentContext { } } -impl GlContext for NotCurrentContext { +impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlConfig for NotCurrentContext { - type Target = Config; +impl GetGlConfig for NotCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GetGlDisplay for NotCurrentContext { - type Target = Display; +impl GetGlDisplay for NotCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawContext for NotCurrentContext { +impl AsRawContext for NotCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Cgl(Id::as_ptr(&self.inner.raw).cast()) } } -impl Sealed for NotCurrentContext {} +impl Sealed for NotCurrentContext {} /// A wrapper around `NSOpenGLContext` that could be curront on the current /// thread. #[derive(Debug)] -pub struct PossiblyCurrentContext { - pub(crate) inner: ContextInner, +pub struct PossiblyCurrentContext { + pub(crate) inner: ContextInner, // The context could be current only on the one thread. _nosendsync: PhantomData<*mut ()>, } -impl PossiblyCurrentGlContext for PossiblyCurrentContext { - type NotCurrentContext = NotCurrentContext; - type Surface = Surface; +impl PossiblyCurrentGlContext for PossiblyCurrentContext { + type NotCurrentContext = NotCurrentContext; + type Surface = Surface; fn make_not_current(self) -> Result { self.inner.make_not_current()?; @@ -173,59 +174,60 @@ impl PossiblyCurrentGlContext for PossiblyCurrentContext { } } -impl GlContext for PossiblyCurrentContext { +impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlConfig for PossiblyCurrentContext { - type Target = Config; +impl GetGlConfig for PossiblyCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GetGlDisplay for PossiblyCurrentContext { - type Target = Display; +impl GetGlDisplay for PossiblyCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawContext for PossiblyCurrentContext { +impl AsRawContext for PossiblyCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Cgl(Id::as_ptr(&self.inner.raw).cast()) } } -impl Sealed for PossiblyCurrentContext {} +impl Sealed for PossiblyCurrentContext {} -pub(crate) struct ContextInner { - display: Display, - config: Config, +pub(crate) struct ContextInner { + display: Display, + config: Config, pub(crate) raw: Id, } -impl ContextInner { +impl ContextInner { fn make_current_draw_read( &self, - _surface_draw: &Surface, - _surface_read: &Surface, + _surface_draw: &Surface, + _surface_read: &Surface, ) -> ErrorKind { ErrorKind::NotSupported("make current draw read isn't supported with CGL") } - fn make_current(&self, surface: &Surface) -> Result<()> { + fn make_current(&self, surface: &Surface) -> Result<()> { autoreleasepool(|_| { self.update(); self.raw.makeCurrentContext(); let view = &surface.ns_view; + let raw = &self.raw; MainThreadMarker::run_on_main(|mtm| unsafe { - self.raw.setView(Some(view.get(mtm))); + raw.setView(Some(view.get(mtm))); }); Ok(()) @@ -248,7 +250,8 @@ impl ContextInner { } pub(crate) fn update(&self) { - MainThreadMarker::run_on_main(|_| self.raw.update()); + let raw = &self.raw; + MainThreadMarker::run_on_main(|_| raw.update()); } pub(crate) fn flush_buffer(&self) -> Result<()> { @@ -259,8 +262,9 @@ impl ContextInner { } pub(crate) fn is_view_current(&self, view: &MainThreadBound>) -> bool { + let raw = &self.raw; MainThreadMarker::run_on_main(|mtm| { - self.raw.view(mtm).expect("context to have a current view") == *view.get(mtm) + raw.view(mtm).expect("context to have a current view") == *view.get(mtm) }) } @@ -271,7 +275,7 @@ impl ContextInner { } } -impl fmt::Debug for ContextInner { +impl fmt::Debug for ContextInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Context") .field("config", &self.config.inner.raw) diff --git a/glutin/src/api/cgl/display.rs b/glutin/src/api/cgl/display.rs index 40ff0f5697..0e8e945819 100644 --- a/glutin/src/api/cgl/display.rs +++ b/glutin/src/api/cgl/display.rs @@ -1,12 +1,12 @@ //! A CGL display. use std::ffi::{self, CStr}; -use std::marker::PhantomData; +use std::sync::Arc; use core_foundation::base::TCFType; use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; use core_foundation::string::CFString; -use raw_window_handle::RawDisplayHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle}; use crate::config::ConfigTemplate; use crate::display::{AsRawDisplay, DisplayFeatures, RawDisplay}; @@ -20,68 +20,92 @@ use super::context::NotCurrentContext; use super::surface::Surface; /// The CGL display. -#[derive(Debug, Clone)] -pub struct Display { - // Prevent building of it without constructor. - _marker: PhantomData<()>, +#[derive(Debug)] +pub struct Display { + /// The inner display object to keep alive. + display: Arc, } -impl Display { +impl Clone for Display { + fn clone(&self) -> Self { + Self { display: self.display.clone() } + } +} + +impl AsRef for Display { + #[inline] + fn as_ref(&self) -> &D { + self.display() + } +} + +impl HasDisplayHandle for Display { + #[inline] + fn display_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.display().display_handle() + } +} + +impl Display { /// Create CGL display. - /// - /// # Safety - /// - /// The function is unsafe for consistency. - pub unsafe fn new(display: RawDisplayHandle) -> Result { - match display { - RawDisplayHandle::AppKit(..) => Ok(Display { _marker: PhantomData }), + pub fn new(display: D) -> Result { + match display.display_handle()?.as_raw() { + RawDisplayHandle::AppKit(..) => Ok(Display { display: Arc::new(display) }), _ => Err(ErrorKind::NotSupported("provided native display is not supported").into()), } } + + /// Get the underlying display implementation + pub fn display(&self) -> &D { + &self.display + } } -impl GlDisplay for Display { - type Config = Config; - type NotCurrentContext = NotCurrentContext; - type PbufferSurface = Surface; - type PixmapSurface = Surface; - type WindowSurface = Surface; +impl GlDisplay for Display { + type Config = Config; + type NotCurrentContext = NotCurrentContext; + type PbufferSurface = Surface; + type PixmapSurface = Surface; + type WindowSurface = Surface>; - unsafe fn find_configs( + fn find_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, ) -> Result + '_>> { - unsafe { Self::find_configs(self, template) } + Self::find_configs(self, template) } - unsafe fn create_window_surface( + fn create_window_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, - ) -> Result { - unsafe { Self::create_window_surface(self, config, surface_attributes) } + surface_attributes: SurfaceAttributes>, + ) -> Result> { + Self::create_window_surface(self, config, surface_attributes) } unsafe fn create_pbuffer_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pbuffer_surface(self, config, surface_attributes) } } - unsafe fn create_context( + fn create_context( &self, config: &Self::Config, - context_attributes: &crate::context::ContextAttributes, + context_attributes: &crate::context::ContextAttributes, ) -> Result { - unsafe { Self::create_context(self, config, context_attributes) } + Self::create_context(self, config, context_attributes) } unsafe fn create_pixmap_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pixmap_surface(self, config, surface_attributes) } } @@ -107,10 +131,10 @@ impl GlDisplay for Display { } } -impl AsRawDisplay for Display { +impl AsRawDisplay for Display { fn raw_display(&self) -> RawDisplay { RawDisplay::Cgl } } -impl Sealed for Display {} +impl Sealed for Display {} diff --git a/glutin/src/api/cgl/surface.rs b/glutin/src/api/cgl/surface.rs index 31d1b6d2d5..d26f759668 100644 --- a/glutin/src/api/cgl/surface.rs +++ b/glutin/src/api/cgl/surface.rs @@ -7,7 +7,7 @@ use std::num::NonZeroU32; use icrate::AppKit::{NSView, NSWindow}; use icrate::Foundation::{MainThreadBound, MainThreadMarker}; use objc2::rc::Id; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use crate::config::GetGlConfig; use crate::display::GetGlDisplay; @@ -22,29 +22,29 @@ use super::config::Config; use super::context::PossiblyCurrentContext; use super::display::Display; -impl Display { +impl Display { pub(crate) unsafe fn create_pixmap_surface( &self, - _config: &Config, - _surface_attributes: &SurfaceAttributes, - ) -> Result> { + _config: &Config, + _surface_attributes: SurfaceAttributes, + ) -> Result> { Err(ErrorKind::NotSupported("pixmaps are not supported with CGL").into()) } pub(crate) unsafe fn create_pbuffer_surface( &self, - _config: &Config, - _surface_attributes: &SurfaceAttributes, - ) -> Result> { + _config: &Config, + _surface_attributes: SurfaceAttributes, + ) -> Result> { Err(ErrorKind::NotSupported("pbuffers are not supported with CGL").into()) } - pub(crate) unsafe fn create_window_surface( + pub(crate) fn create_window_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let native_window = match surface_attributes.raw_window_handle.unwrap() { + config: &Config, + surface_attributes: SurfaceAttributes>, + ) -> Result>> { + let native_window = match surface_attributes.ty.0.window_handle()?.as_raw() { RawWindowHandle::AppKit(window) => window, _ => { return Err( @@ -59,21 +59,23 @@ 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.cast()) } { + let ns_view: Id = if let Some(ns_view) = + unsafe { Id::retain(native_window.ns_view.as_ptr().cast()) } + { ns_view } else { return Err(ErrorKind::NotSupported("ns_view of provided native window is nil").into()); }; - let ns_view = MainThreadBound::new(ns_view, mtm); - - let ns_window = - if let Some(ns_window) = unsafe { Id::retain(native_window.ns_window.cast()) } { - ns_window - } else { + let ns_window = match unsafe { ns_view.window() } { + Some(window) => window, + None => { return Err( ErrorKind::NotSupported("ns_window of provided native window is nil").into() - ); - }; + ) + }, + }; + + let ns_view = MainThreadBound::new(ns_view, mtm); let ns_window = MainThreadBound::new(ns_window, mtm); let surface = Surface { @@ -82,24 +84,46 @@ impl Display { ns_view, ns_window, _nosendsync: PhantomData, - _ty: PhantomData, + ty: surface_attributes.ty, }; Ok(surface) } } /// A wrapper aroud `NSView`. -pub struct Surface { - display: Display, - config: Config, +pub struct Surface { + display: Display, + config: Config, pub(crate) ns_view: MainThreadBound>, ns_window: MainThreadBound>, _nosendsync: PhantomData<*const std::ffi::c_void>, - _ty: PhantomData, + ty: T, +} + +impl Surface> { + /// Get a reference to the underlying window. + pub fn window(&self) -> &W { + &self.ty.0 + } +} + +impl AsRef for Surface> { + fn as_ref(&self) -> &W { + self.window() + } +} + +impl HasWindowHandle for Surface> { + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.window().window_handle() + } } -impl GlSurface for Surface { - type Context = PossiblyCurrentContext; +impl GlSurface for Surface { + type Context = PossiblyCurrentContext; type SurfaceType = T; fn buffer_age(&self) -> u32 { @@ -156,23 +180,23 @@ impl GlSurface for Surface { } } -impl GetGlConfig for Surface { - type Target = Config; +impl GetGlConfig for Surface { + type Target = Config; fn config(&self) -> Self::Target { self.config.clone() } } -impl GetGlDisplay for Surface { - type Target = Display; +impl GetGlDisplay for Surface { + type Target = Display; fn display(&self) -> Self::Target { self.display.clone() } } -impl AsRawSurface for Surface { +impl AsRawSurface for Surface { fn raw_surface(&self) -> RawSurface { // SAFETY: We only use the thread marker to get the pointer value of the view let mtm = unsafe { MainThreadMarker::new_unchecked() }; @@ -180,7 +204,7 @@ impl AsRawSurface for Surface { } } -impl fmt::Debug for Surface { +impl fmt::Debug for Surface { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Surface") .field("config", &self.config.inner.raw) @@ -190,4 +214,4 @@ impl fmt::Debug for Surface { } } -impl Sealed for Surface {} +impl Sealed for Surface {} diff --git a/glutin/src/api/egl/config.rs b/glutin/src/api/egl/config.rs index e400736cc8..ebf812620e 100644 --- a/glutin/src/api/egl/config.rs +++ b/glutin/src/api/egl/config.rs @@ -5,7 +5,7 @@ use std::ops::Deref; use std::sync::Arc; use std::{fmt, mem}; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use glutin_egl_sys::egl; use glutin_egl_sys::egl::types::{EGLConfig, EGLint}; @@ -23,11 +23,13 @@ use crate::platform::x11::{X11GlConfigExt, X11VisualInfo}; use super::display::Display; -impl Display { - pub(crate) unsafe fn find_configs( +impl Display { + pub(crate) fn find_configs( &self, - template: ConfigTemplate, - ) -> Result + '_>> { + template: ConfigTemplate, + ) -> Result> + '_>> { + use raw_window_handle::{XcbWindowHandle, XlibWindowHandle}; + let mut config_attributes = Vec::::new(); // Add color buffer type. @@ -183,6 +185,8 @@ impl Display { found_configs.set_len(configs_number as usize); } + let raw_handle = + template._native_window.map(|w| w.window_handle().map(|w| w.as_raw())).transpose()?; let configs = found_configs .into_iter() .map(move |raw| { @@ -195,12 +199,15 @@ impl Display { // // XXX This can't be done by passing visual in the EGL attributes // when calling `eglChooseConfig` since the visual is ignored. - match template.native_window { - Some(RawWindowHandle::Xcb(xcb)) if xcb.visual_id > 0 => { - xcb.visual_id as u32 == config.native_visual() - }, - Some(RawWindowHandle::Xlib(xlib)) if xlib.visual_id > 0 => { - xlib.visual_id as u32 == config.native_visual() + match raw_handle { + Some(RawWindowHandle::Xcb(XcbWindowHandle { + visual_id: Some(visual_id), + .. + })) => visual_id.get() == config.native_visual(), + Some(RawWindowHandle::Xlib(XlibWindowHandle { visual_id, .. })) + if visual_id > 0 => + { + visual_id as u32 == config.native_visual() }, _ => true, } @@ -223,12 +230,26 @@ impl Display { /// A simple wrapper around `EGLConfig` that could be used with `EGLContext` /// and `EGLSurface`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Config { - pub(crate) inner: Arc, +#[derive(Debug)] +pub struct Config { + pub(crate) inner: Arc>, +} + +impl Clone for Config { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } } -impl Config { +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for Config {} + +impl Config { /// The native visual identifier. /// /// The interpretation of this value is platform dependant. Consult @@ -254,7 +275,7 @@ impl Config { } } -impl GlConfig for Config { +impl GlConfig for Config { fn color_buffer_type(&self) -> Option { unsafe { match self.raw_attribute(egl::COLOR_BUFFER_TYPE as EGLint) as _ { @@ -335,7 +356,7 @@ impl GlConfig for Config { #[cfg(any(wayland_platform, x11_platform))] fn supports_transparency(&self) -> Option { use raw_window_handle::RawDisplayHandle; - match *self.inner.display.inner._native_display? { + match self.inner.display.inner.native_display.as_ref()?.display_handle().ok()?.as_raw() { #[cfg(x11_platform)] RawDisplayHandle::Xlib(_) | RawDisplayHandle::Xcb(_) => { self.x11_visual().map(|visual| visual.supports_transparency()) @@ -366,49 +387,52 @@ impl GlConfig for Config { } } -impl GetGlDisplay for Config { - type Target = Display; +impl GetGlDisplay for Config { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawConfig for Config { +impl AsRawConfig for Config { fn raw_config(&self) -> RawConfig { RawConfig::Egl(*self.inner.raw) } } #[cfg(x11_platform)] -impl X11GlConfigExt for Config { +impl X11GlConfigExt for Config { fn x11_visual(&self) -> Option { - match *self.inner.display.inner._native_display? { + match self.inner.display.inner.native_display.as_ref()?.display_handle().ok()?.as_raw() { raw_window_handle::RawDisplayHandle::Xlib(display_handle) => unsafe { let xid = self.native_visual(); - X11VisualInfo::from_xid(display_handle.display as *mut _, xid as _) + X11VisualInfo::from_xid( + display_handle.display.map_or(std::ptr::null_mut(), |d| d.as_ptr() as *mut _), + xid as _, + ) }, _ => None, } } } -impl Sealed for Config {} +impl Sealed for Config {} -pub(crate) struct ConfigInner { - display: Display, +pub(crate) struct ConfigInner { + display: Display, pub(crate) raw: EglConfig, } -impl PartialEq for ConfigInner { +impl PartialEq for ConfigInner { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } -impl Eq for ConfigInner {} +impl Eq for ConfigInner {} -impl fmt::Debug for ConfigInner { +impl fmt::Debug for ConfigInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Config") .field("raw", &self.raw) diff --git a/glutin/src/api/egl/context.rs b/glutin/src/api/egl/context.rs index 7647e43347..6c7e1971ee 100644 --- a/glutin/src/api/egl/context.rs +++ b/glutin/src/api/egl/context.rs @@ -7,6 +7,8 @@ use std::ops::Deref; use glutin_egl_sys::egl::types::{EGLenum, EGLint}; use glutin_egl_sys::{egl, EGLContext}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; + use crate::config::{Api, GetGlConfig}; use crate::context::{ self, AsRawContext, ContextApi, ContextAttributes, GlProfile, RawContext, Robustness, Version, @@ -21,18 +23,18 @@ use super::config::Config; use super::display::Display; use super::surface::Surface; -impl Display { - pub(crate) unsafe fn create_context( +impl Display { + pub(crate) fn create_context( &self, - config: &Config, - context_attributes: &ContextAttributes, - ) -> Result { + config: &Config, + context_attributes: &ContextAttributes, + ) -> Result> { let mut attrs = Vec::::new(); let supports_opengl = self.inner.version > Version::new(1, 3); let config_api = config.api(); - let (api, mut version) = match context_attributes.api { + let (api, mut version) = match context_attributes.inner.api { api @ Some(ContextApi::OpenGl(_)) | api @ None if supports_opengl && config_api.contains(Api::OPENGL) => { @@ -61,7 +63,7 @@ impl Display { // Add profile for the OpenGL Api. if api == egl::OPENGL_API { let (profile, new_version) = - context::pick_profile(context_attributes.profile, version); + context::pick_profile(context_attributes.inner.profile, version); version = Some(new_version); let profile = match profile { GlProfile::Core => egl::CONTEXT_OPENGL_CORE_PROFILE_BIT, @@ -82,7 +84,7 @@ impl Display { let has_robustsess = self.inner.features.contains(DisplayFeatures::CONTEXT_ROBUSTNESS); let mut requested_no_error = false; - match context_attributes.robustness { + match context_attributes.inner.robustness { Robustness::NotRobust => (), Robustness::NoError if self.inner.features.contains(DisplayFeatures::CONTEXT_NO_ERROR) => @@ -108,7 +110,7 @@ impl Display { }, } - if context_attributes.debug && is_one_five && !requested_no_error { + if context_attributes.inner.debug && is_one_five && !requested_no_error { attrs.push(egl::CONTEXT_OPENGL_DEBUG as EGLint); attrs.push(egl::TRUE as EGLint); } @@ -129,7 +131,7 @@ impl Display { attrs.push(egl::NONE as EGLint); let shared_context = if let Some(shared_context) = - context_attributes.shared_context.as_ref() + context_attributes.inner.shared_context.as_ref() { match shared_context { RawContext::Egl(shared_context) => *shared_context, @@ -167,26 +169,26 @@ impl Display { /// A wrapper around `EGLContext` that is known to be not current. #[derive(Debug)] -pub struct NotCurrentContext { - inner: ContextInner, +pub struct NotCurrentContext { + inner: ContextInner, } -impl NotCurrentContext { +impl NotCurrentContext { /// Make a [`Self::PossiblyCurrentContext`] indicating that the context /// could be current on the thread. - pub fn make_current_surfaceless(self) -> Result { + pub fn make_current_surfaceless(self) -> Result> { self.inner.make_current_surfaceless()?; Ok(PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData }) } - fn new(inner: ContextInner) -> Self { + fn new(inner: ContextInner) -> Self { Self { inner } } } -impl NotCurrentGlContext for NotCurrentContext { - type PossiblyCurrentContext = PossiblyCurrentContext; - type Surface = Surface; +impl NotCurrentGlContext for NotCurrentContext { + type PossiblyCurrentContext = PossiblyCurrentContext; + type Surface = Surface; fn treat_as_possibly_current(self) -> Self::PossiblyCurrentContext { PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData } @@ -194,69 +196,69 @@ impl NotCurrentGlContext for NotCurrentContext { fn make_current( self, - surface: &Surface, - ) -> Result { + surface: &Surface, + ) -> Result> { self.inner.make_current_draw_read(surface, surface)?; Ok(PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData }) } fn make_current_draw_read( self, - surface_draw: &Surface, - surface_read: &Surface, - ) -> Result { + surface_draw: &Surface, + surface_read: &Surface, + ) -> Result> { self.inner.make_current_draw_read(surface_draw, surface_read)?; Ok(PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData }) } } -impl GlContext for NotCurrentContext { +impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlConfig for NotCurrentContext { - type Target = Config; +impl GetGlConfig for NotCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GetGlDisplay for NotCurrentContext { - type Target = Display; +impl GetGlDisplay for NotCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawContext for NotCurrentContext { +impl AsRawContext for NotCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Egl(*self.inner.raw) } } -impl Sealed for NotCurrentContext {} +impl Sealed for NotCurrentContext {} /// A wrapper around `EGLContext` that could be current for the current thread. #[derive(Debug)] -pub struct PossiblyCurrentContext { - pub(crate) inner: ContextInner, +pub struct PossiblyCurrentContext { + pub(crate) inner: ContextInner, _nosendsync: PhantomData, } -impl PossiblyCurrentContext { +impl PossiblyCurrentContext { /// Make this context current on the calling thread. pub fn make_current_surfaceless(&self) -> Result<()> { self.inner.make_current_surfaceless() } } -impl PossiblyCurrentGlContext for PossiblyCurrentContext { - type NotCurrentContext = NotCurrentContext; - type Surface = Surface; +impl PossiblyCurrentGlContext for PossiblyCurrentContext { + type NotCurrentContext = NotCurrentContext; + type Surface = Surface; fn make_not_current(self) -> Result { self.inner.make_not_current()?; @@ -283,44 +285,44 @@ impl PossiblyCurrentGlContext for PossiblyCurrentContext { } } -impl GlContext for PossiblyCurrentContext { +impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlConfig for PossiblyCurrentContext { - type Target = Config; +impl GetGlConfig for PossiblyCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GetGlDisplay for PossiblyCurrentContext { - type Target = Display; +impl GetGlDisplay for PossiblyCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawContext for PossiblyCurrentContext { +impl AsRawContext for PossiblyCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Egl(*self.inner.raw) } } -impl Sealed for PossiblyCurrentContext {} +impl Sealed for PossiblyCurrentContext {} -pub(crate) struct ContextInner { - display: Display, - config: Config, +pub(crate) struct ContextInner { + display: Display, + config: Config, raw: EglContext, api: egl::types::EGLenum, } -impl ContextInner { +impl ContextInner { fn make_current_surfaceless(&self) -> Result<()> { unsafe { if self.display.inner.egl.MakeCurrent( @@ -339,8 +341,8 @@ impl ContextInner { fn make_current_draw_read( &self, - surface_draw: &Surface, - surface_read: &Surface, + surface_draw: &Surface, + surface_read: &Surface, ) -> Result<()> { unsafe { let draw = surface_draw.raw; @@ -418,7 +420,7 @@ impl ContextInner { } } -impl Drop for ContextInner { +impl Drop for ContextInner { fn drop(&mut self) { unsafe { self.display.inner.egl.DestroyContext(*self.display.inner.raw, *self.raw); @@ -426,7 +428,7 @@ impl Drop for ContextInner { } } -impl fmt::Debug for ContextInner { +impl fmt::Debug for ContextInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Context") .field("display", &self.display.inner.raw) diff --git a/glutin/src/api/egl/display.rs b/glutin/src/api/egl/display.rs index ea64ba66b2..80f7b4b99d 100644 --- a/glutin/src/api/egl/display.rs +++ b/glutin/src/api/egl/display.rs @@ -13,11 +13,13 @@ use glutin_egl_sys::egl::types::{EGLAttrib, EGLDisplay, EGLint}; use once_cell::sync::OnceCell; -use raw_window_handle::RawDisplayHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle}; use crate::config::ConfigTemplate; use crate::context::Version; -use crate::display::{AsRawDisplay, DisplayFeatures, GetDisplayExtensions, RawDisplay}; +use crate::display::{ + AsRawDisplay, DisplayFeatures, DisplayResult, GetDisplayExtensions, RawDisplay, +}; use crate::error::{ErrorKind, Result}; use crate::prelude::*; use crate::private::Sealed; @@ -34,13 +36,35 @@ use super::{Egl, EGL}; pub(crate) static CLIENT_EXTENSIONS: OnceCell> = OnceCell::new(); /// A wrapper for the `EGLDisplay` and its supported extensions. -#[derive(Debug, Clone)] -pub struct Display { +#[derive(Debug)] +pub struct Display { // Inner display to simplify passing it around. - pub(crate) inner: Arc, + pub(crate) inner: Arc>, +} + +impl Clone for Display { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl AsRef for Display { + #[inline] + fn as_ref(&self) -> &D { + self.display() + } } -impl Display { +impl HasDisplayHandle for Display { + fn display_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.display().display_handle() + } +} + +impl Display { /// Create EGL display with the native display. /// /// # Safety @@ -49,33 +73,45 @@ impl Display { /// [`std::ptr::null()`] for the display will result in using /// `EGL_DEFAULT_DISPLAY`, which is not recommended or will /// work on a platform with a concept of native display, like Wayland. - pub unsafe fn new(raw_display: RawDisplayHandle) -> Result { + pub fn new(raw_display: D) -> Result { + Self::new_with_display(raw_display).map_err(Into::into) + } + + /// Get the handle to the underlying raw display. + pub fn display(&self) -> &D { + self.inner.native_display.as_ref().unwrap() + } + + pub(crate) fn new_with_display(raw_display: D) -> DisplayResult { let egl = match EGL.as_ref() { Some(egl) => egl, - None => return Err(ErrorKind::NotFound.into()), + None => return Err((ErrorKind::NotFound, raw_display).into()), }; CLIENT_EXTENSIONS.get_or_init(|| get_extensions(egl, egl::NO_DISPLAY)); // Create a EGL display by chaining all display creation functions aborting on // `EGL_BAD_ATTRIBUTE`. - let display = Self::get_platform_display(egl, raw_display) + let display = match Self::get_platform_display(egl, &raw_display) .or_else(|err| { if err.error_kind() == ErrorKind::BadAttribute { Err(err) } else { - Self::get_platform_display_ext(egl, raw_display) + Self::get_platform_display_ext(egl, &raw_display) } }) .or_else(|err| { if err.error_kind() == ErrorKind::BadAttribute { Err(err) } else { - Self::get_display(egl, raw_display) + Self::get_display(egl, &raw_display) } - })?; + }) { + Ok(display) => display, + Err(err) => return Err((err, raw_display).into()), + }; - Self::initialize_display(egl, display, Some(raw_display)) + Self::initialize_display(egl, display, Some(raw_display)).map_err(|e| e.unwrap()) } /// Create an EGL display using the specified device. @@ -91,10 +127,7 @@ impl Display { /// /// If `raw_display` is [`Some`], `raw_display` must point to a valid system /// display. - pub unsafe fn with_device( - device: &Device, - raw_display: Option, - ) -> Result { + pub unsafe fn with_device(device: &Device, raw_display: Option) -> Result { let egl = match EGL.as_ref() { Some(egl) => egl, None => return Err(ErrorKind::NotFound.into()), @@ -169,7 +202,7 @@ impl Display { } .map(EglDisplay::Ext)?; - Self::initialize_display(egl, platform_display, None) + Self::initialize_display(egl, platform_display, None).map_err(Into::into) } /// Get the [`Device`] the display is using. @@ -231,7 +264,7 @@ impl Display { } } - fn get_platform_display(egl: &Egl, display: RawDisplayHandle) -> Result { + fn get_platform_display(egl: &Egl, display: &D) -> Result { if !egl.GetPlatformDisplay.is_loaded() { return Err(ErrorKind::NotSupported("eglGetPlatformDisplay is not supported").into()); } @@ -239,12 +272,12 @@ impl Display { let extensions = CLIENT_EXTENSIONS.get().unwrap(); let mut attrs = Vec::::with_capacity(5); - let (platform, mut display) = match display { + let (platform, display) = match display.display_handle()?.as_raw() { #[cfg(wayland_platform)] RawDisplayHandle::Wayland(handle) if extensions.contains("EGL_KHR_platform_wayland") => { - (egl::PLATFORM_WAYLAND_KHR, handle.display) + (egl::PLATFORM_WAYLAND_KHR, Some(handle.display)) }, #[cfg(x11_platform)] RawDisplayHandle::Xlib(handle) if extensions.contains("EGL_KHR_platform_x11") => { @@ -253,10 +286,10 @@ impl Display { (egl::PLATFORM_X11_KHR, handle.display) }, RawDisplayHandle::Gbm(handle) if extensions.contains("EGL_KHR_platform_gbm") => { - (egl::PLATFORM_GBM_KHR, handle.gbm_device) + (egl::PLATFORM_GBM_KHR, Some(handle.gbm_device)) }, RawDisplayHandle::Android(_) if extensions.contains("EGL_KHR_platform_android") => { - (egl::PLATFORM_ANDROID_KHR, egl::DEFAULT_DISPLAY as *mut _) + (egl::PLATFORM_ANDROID_KHR, None) }, _ => { return Err( @@ -266,9 +299,7 @@ impl Display { }; // Be explicit here. - if display.is_null() { - display = egl::DEFAULT_DISPLAY as *mut _; - } + let display = display.map_or(egl::DEFAULT_DISPLAY as *mut _, |x| x.as_ptr()); // Push at the end so we can pop it on failure let mut has_display_reference = extensions.contains("EGL_KHR_display_reference"); @@ -306,7 +337,7 @@ impl Display { platform_display.map(EglDisplay::Khr) } - fn get_platform_display_ext(egl: &Egl, display: RawDisplayHandle) -> Result { + fn get_platform_display_ext(egl: &Egl, display: &D) -> Result { if !egl.GetPlatformDisplayEXT.is_loaded() { return Err(ErrorKind::NotSupported("eglGetPlatformDisplayEXT is not supported").into()); } @@ -315,12 +346,12 @@ impl Display { let mut attrs = Vec::::with_capacity(5); let mut legacy = false; - let (platform, mut display) = match display { + let (platform, display) = match display.display_handle()?.as_raw() { #[cfg(wayland_platform)] RawDisplayHandle::Wayland(handle) if extensions.contains("EGL_EXT_platform_wayland") => { - (egl::PLATFORM_WAYLAND_EXT, handle.display) + (egl::PLATFORM_WAYLAND_EXT, Some(handle.display)) }, #[cfg(x11_platform)] RawDisplayHandle::Xlib(handle) if extensions.contains("EGL_EXT_platform_x11") => { @@ -338,12 +369,12 @@ impl Display { (egl::PLATFORM_XCB_EXT, handle.connection) }, RawDisplayHandle::Gbm(handle) if extensions.contains("EGL_MESA_platform_gbm") => { - (egl::PLATFORM_GBM_MESA, handle.gbm_device) + (egl::PLATFORM_GBM_MESA, Some(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 _) + (egl::PLATFORM_ANGLE_ANGLE, None) }, _ => { return Err( @@ -353,9 +384,7 @@ impl Display { }; // Be explicit here. - if display.is_null() { - display = egl::DEFAULT_DISPLAY as *mut _; - } + let display = display.map_or(egl::DEFAULT_DISPLAY as *mut _, |x| x.as_ptr()); // Push at the end so we can pop it on failure let mut has_display_reference = extensions.contains("EGL_KHR_display_reference"); @@ -403,11 +432,13 @@ impl Display { }) } - fn get_display(egl: &Egl, display: RawDisplayHandle) -> Result { - let mut display = match display { - RawDisplayHandle::Gbm(handle) => handle.gbm_device, + fn get_display(egl: &Egl, display: &D) -> Result { + let mut display = match display.display_handle()?.as_raw() { + RawDisplayHandle::Gbm(handle) => handle.gbm_device.as_ptr(), #[cfg(x11_platform)] - RawDisplayHandle::Xlib(handle) => handle.display, + RawDisplayHandle::Xlib(handle) => { + handle.display.map_or(egl::DEFAULT_DISPLAY as *mut _, |x| x.as_ptr()) + }, RawDisplayHandle::Android(_) => egl::DEFAULT_DISPLAY as *mut _, _ => { return Err( @@ -470,12 +501,16 @@ impl Display { fn initialize_display( egl: &'static Egl, display: EglDisplay, - raw_display_handle: Option, - ) -> Result { + handle: Option, + ) -> DisplayResult> { let version = unsafe { let (mut major, mut minor) = (0, 0); if egl.Initialize(*display, &mut major, &mut minor) == egl::FALSE { - return Err(super::check_error().expect_err("eglInit failed without a reason")); + return Err(( + super::check_error().expect_err("eglInit failed without a reason"), + handle, + ) + .into()); } Version::new(major as u8, minor as u8) @@ -488,7 +523,7 @@ impl Display { let inner = Arc::new(DisplayInner { egl, raw: display, - _native_display: raw_display_handle.map(NativeDisplay), + native_display: handle, version, display_extensions, features, @@ -497,48 +532,48 @@ impl Display { } } -impl GlDisplay for Display { - type Config = Config; - type NotCurrentContext = NotCurrentContext; - type PbufferSurface = Surface; - type PixmapSurface = Surface; - type WindowSurface = Surface; +impl GlDisplay for Display { + type Config = Config; + type NotCurrentContext = NotCurrentContext; + type PbufferSurface = Surface; + type PixmapSurface = Surface; + type WindowSurface = Surface>; - unsafe fn find_configs( + fn find_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, ) -> Result + '_>> { - unsafe { Self::find_configs(self, template) } + Self::find_configs(self, template) } - unsafe fn create_window_surface( + fn create_window_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, - ) -> Result { - unsafe { Self::create_window_surface(self, config, surface_attributes) } + surface_attributes: SurfaceAttributes>, + ) -> Result> { + Self::create_window_surface(self, config, surface_attributes) } unsafe fn create_pbuffer_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pbuffer_surface(self, config, surface_attributes) } } - unsafe fn create_context( + fn create_context( &self, config: &Self::Config, - context_attributes: &crate::context::ContextAttributes, + context_attributes: &crate::context::ContextAttributes, ) -> Result { - unsafe { Self::create_context(self, config, context_attributes) } + Self::create_context(self, config, context_attributes) } unsafe fn create_pixmap_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pixmap_surface(self, config, surface_attributes) } } @@ -556,21 +591,21 @@ impl GlDisplay for Display { } } -impl GetDisplayExtensions for Display { +impl GetDisplayExtensions for Display { fn extensions(&self) -> &HashSet<&'static str> { &self.inner.display_extensions } } -impl AsRawDisplay for Display { +impl AsRawDisplay for Display { fn raw_display(&self) -> RawDisplay { RawDisplay::Egl(*self.inner.raw) } } -impl Sealed for Display {} +impl Sealed for Display {} -pub(crate) struct DisplayInner { +pub(crate) struct DisplayInner { /// Pointer to the EGL handler to simplify API calls. pub(crate) egl: &'static Egl, @@ -587,10 +622,10 @@ pub(crate) struct DisplayInner { pub(crate) features: DisplayFeatures, /// The raw display used to create EGL display. - pub(crate) _native_display: Option, + pub(crate) native_display: Option, } -impl DisplayInner { +impl DisplayInner { fn uses_display_reference(&self) -> bool { if !CLIENT_EXTENSIONS.get().unwrap().contains("EGL_KHR_display_reference") { return false; @@ -621,7 +656,7 @@ impl DisplayInner { } } -impl fmt::Debug for DisplayInner { +impl fmt::Debug for DisplayInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Display") .field("raw", &self.raw) @@ -632,7 +667,7 @@ impl fmt::Debug for DisplayInner { } } -impl Drop for DisplayInner { +impl Drop for DisplayInner { fn drop(&mut self) { if self.uses_display_reference() { unsafe { diff --git a/glutin/src/api/egl/surface.rs b/glutin/src/api/egl/surface.rs index 102c74077e..4525764dfd 100644 --- a/glutin/src/api/egl/surface.rs +++ b/glutin/src/api/egl/surface.rs @@ -1,12 +1,11 @@ //! Everything related to `EGLSurface`. -use std::marker::PhantomData; use std::num::NonZeroU32; use std::{ffi, fmt}; use glutin_egl_sys::egl; use glutin_egl_sys::egl::types::{EGLAttrib, EGLSurface, EGLint}; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; #[cfg(wayland_platform)] use wayland_sys::{egl::*, ffi_dispatch}; @@ -28,14 +27,14 @@ use super::display::Display; /// Hint for the attribute list size. const ATTR_SIZE_HINT: usize = 8; -impl Display { +impl Display { pub(crate) unsafe fn create_pbuffer_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let width = surface_attributes.width.unwrap(); - let height = surface_attributes.height.unwrap(); + config: &Config, + surface_attributes: SurfaceAttributes, + ) -> Result> { + let width = surface_attributes.inner.width.unwrap(); + let height = surface_attributes.inner.height.unwrap(); // XXX Window surface is using `EGLAttrib` and not `EGLint`. let mut attrs = Vec::::with_capacity(ATTR_SIZE_HINT); @@ -64,22 +63,22 @@ impl Display { native_window: None, config, raw: surface, - _ty: PhantomData, + ty: surface_attributes.ty, }) } pub(crate) unsafe fn create_pixmap_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let native_pixmap = surface_attributes.native_pixmap.as_ref().unwrap(); + config: &Config, + surface_attributes: SurfaceAttributes, + ) -> Result> { + let native_pixmap = surface_attributes.inner.native_pixmap.as_ref().unwrap(); let mut attrs = Vec::::with_capacity(ATTR_SIZE_HINT); - if surface_attributes.srgb.is_some() && config.srgb_capable() { + if surface_attributes.inner.srgb.is_some() && config.srgb_capable() { attrs.push(egl::GL_COLORSPACE as EGLAttrib); - let colorspace = match surface_attributes.srgb { + let colorspace = match surface_attributes.inner.srgb { Some(true) => egl::GL_COLORSPACE_SRGB as EGLAttrib, _ => egl::GL_COLORSPACE_LINEAR as EGLAttrib, }; @@ -153,20 +152,20 @@ impl Display { config, native_window: None, raw: surface, - _ty: PhantomData, + ty: surface_attributes.ty, }) } - pub(crate) unsafe fn create_window_surface( + pub(crate) fn create_window_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { + config: &Config, + surface_attributes: SurfaceAttributes>, + ) -> Result>> { // Create native window. let native_window = NativeWindow::new( - surface_attributes.width.unwrap(), - surface_attributes.height.unwrap(), - surface_attributes.raw_window_handle.as_ref().unwrap(), + surface_attributes.inner.width.unwrap(), + surface_attributes.inner.height.unwrap(), + &surface_attributes.ty.0.window_handle()?.as_raw(), )?; // XXX Window surface is using `EGLAttrib` and not `EGLint`. @@ -174,15 +173,17 @@ impl Display { // Add information about render buffer. attrs.push(egl::RENDER_BUFFER as EGLAttrib); - let buffer = - if surface_attributes.single_buffer { egl::SINGLE_BUFFER } else { egl::BACK_BUFFER } - as EGLAttrib; + let buffer = if surface_attributes.inner.single_buffer { + egl::SINGLE_BUFFER + } else { + egl::BACK_BUFFER + } as EGLAttrib; attrs.push(buffer); // // Add colorspace if the extension is present. - if surface_attributes.srgb.is_some() && config.srgb_capable() { + if surface_attributes.inner.srgb.is_some() && config.srgb_capable() { attrs.push(egl::GL_COLORSPACE as EGLAttrib); - let colorspace = match surface_attributes.srgb { + let colorspace = match surface_attributes.inner.srgb { Some(true) => egl::GL_COLORSPACE_SRGB as EGLAttrib, _ => egl::GL_COLORSPACE_LINEAR as EGLAttrib, }; @@ -230,7 +231,7 @@ impl Display { config, native_window: Some(native_window), raw: surface, - _ty: PhantomData, + ty: surface_attributes.ty, }) } @@ -244,15 +245,15 @@ impl Display { } /// A wrapper around `EGLSurface`. -pub struct Surface { - display: Display, - config: Config, +pub struct Surface { + display: Display, + config: Config, pub(crate) raw: EGLSurface, native_window: Option, - _ty: PhantomData, + ty: T, } -impl Surface { +impl Surface { /// Swaps the underlying back buffers when the surface is not single /// buffered and pass the [`Rect`] information to the system /// compositor. Providing empty slice will damage the entire surface. @@ -264,7 +265,7 @@ impl Surface { /// the system compositor. pub fn swap_buffers_with_damage( &self, - context: &PossiblyCurrentContext, + context: &PossiblyCurrentContext, rects: &[Rect], ) -> Result<()> { context.inner.bind_api(); @@ -318,7 +319,29 @@ impl Surface { } } -impl Drop for Surface { +impl Surface> { + /// Get a reference to the underlying window. + pub fn window(&self) -> &W { + &self.ty.0 + } +} + +impl AsRef for Surface> { + fn as_ref(&self) -> &W { + self.window() + } +} + +impl HasWindowHandle for Surface> { + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.window().window_handle() + } +} + +impl Drop for Surface { fn drop(&mut self) { unsafe { self.display.inner.egl.DestroySurface(*self.display.inner.raw, self.raw); @@ -326,8 +349,8 @@ impl Drop for Surface { } } -impl GlSurface for Surface { - type Context = PossiblyCurrentContext; +impl GlSurface for Surface { + type Context = PossiblyCurrentContext; type SurfaceType = T; fn buffer_age(&self) -> u32 { @@ -403,29 +426,29 @@ impl GlSurface for Surface { } } -impl GetGlConfig for Surface { - type Target = Config; +impl GetGlConfig for Surface { + type Target = Config; fn config(&self) -> Self::Target { self.config.clone() } } -impl GetGlDisplay for Surface { - type Target = Display; +impl GetGlDisplay for Surface { + type Target = Display; fn display(&self) -> Self::Target { self.display.clone() } } -impl AsRawSurface for Surface { +impl AsRawSurface for Surface { fn raw_surface(&self) -> RawSurface { RawSurface::Egl(self.raw) } } -impl fmt::Debug for Surface { +impl fmt::Debug for Surface { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Surface") .field("display", &self.display.inner.raw) @@ -437,7 +460,7 @@ impl fmt::Debug for Surface { } } -impl Sealed for Surface {} +impl Sealed for Surface {} #[derive(Debug)] enum NativeWindow { @@ -469,14 +492,10 @@ impl NativeWindow { let native_window = match raw_window_handle { #[cfg(wayland_platform)] RawWindowHandle::Wayland(window_handle) => unsafe { - if window_handle.surface.is_null() { - return Err(ErrorKind::BadNativeWindow.into()); - } - let ptr = ffi_dispatch!( wayland_egl_handle(), wl_egl_window_create, - window_handle.surface.cast(), + window_handle.surface.as_ptr().cast(), _width.get() as _, _height.get() as _ ); @@ -494,37 +513,15 @@ impl NativeWindow { Self::Xlib(window_handle.window as _) }, #[cfg(x11_platform)] - RawWindowHandle::Xcb(window_handle) => { - if window_handle.window == 0 { - return Err(ErrorKind::BadNativeWindow.into()); - } - - Self::Xcb(window_handle.window as _) - }, + RawWindowHandle::Xcb(window_handle) => Self::Xcb(window_handle.window.get() as _), #[cfg(android_platform)] RawWindowHandle::AndroidNdk(window_handle) => { - if window_handle.a_native_window.is_null() { - return Err(ErrorKind::BadNativeWindow.into()); - } - - Self::Android(window_handle.a_native_window) + Self::Android(window_handle.a_native_window.as_ptr()) }, #[cfg(windows)] - RawWindowHandle::Win32(window_handle) => { - if window_handle.hwnd.is_null() { - return Err(ErrorKind::BadNativeWindow.into()); - } - - Self::Win32(window_handle.hwnd as _) - }, + RawWindowHandle::Win32(window_handle) => Self::Win32(window_handle.hwnd.get() as _), #[cfg(free_unix)] - RawWindowHandle::Gbm(window_handle) => { - if window_handle.gbm_surface.is_null() { - return Err(ErrorKind::BadNativeWindow.into()); - } - - Self::Gbm(window_handle.gbm_surface) - }, + RawWindowHandle::Gbm(window_handle) => Self::Gbm(window_handle.gbm_surface.as_ptr()), _ => { return Err( ErrorKind::NotSupported("provided native window is not supported").into() diff --git a/glutin/src/api/glx/config.rs b/glutin/src/api/glx/config.rs index 6950ce7b4b..562b9dc4e3 100644 --- a/glutin/src/api/glx/config.rs +++ b/glutin/src/api/glx/config.rs @@ -7,7 +7,7 @@ use std::{fmt, slice}; use glutin_glx_sys::glx::types::GLXFBConfig; use glutin_glx_sys::{glx, glx_extra}; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use crate::config::{ Api, AsRawConfig, ColorBufferType, ConfigSurfaceTypes, ConfigTemplate, GlConfig, RawConfig, @@ -19,11 +19,11 @@ use crate::private::Sealed; use super::display::Display; -impl Display { - pub(crate) unsafe fn find_configs( +impl Display { + pub(crate) fn find_configs( &self, - template: ConfigTemplate, - ) -> Result + '_>> { + template: ConfigTemplate, + ) -> Result> + '_>> { let mut config_attributes = Vec::::new(); // Add color buffer type. @@ -96,7 +96,9 @@ impl Display { config_attributes.push(template.stencil_size as c_int); // Add visual if was provided. - if let Some(RawWindowHandle::Xlib(window)) = template.native_window { + if let Some(RawWindowHandle::Xlib(window)) = + template._native_window.map(|w| w.window_handle().map(|w| w.as_raw())).transpose()? + { if window.visual_id > 0 { config_attributes.push(glx::VISUAL_ID as c_int); config_attributes.push(window.visual_id as c_int); @@ -183,12 +185,26 @@ impl Display { } /// A wrapper around `GLXFBConfig`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Config { - pub(crate) inner: Arc, +#[derive(Debug)] +pub struct Config { + pub(crate) inner: Arc>, +} + +impl Clone for Config { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } } -impl Config { +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for Config {} + +impl Config { /// # Safety /// /// The caller must ensure that the attribute could be present. @@ -210,7 +226,7 @@ impl Config { } } -impl GlConfig for Config { +impl GlConfig for Config { fn color_buffer_type(&self) -> Option { unsafe { match self.raw_attribute(glx::X_VISUAL_TYPE as c_int) as _ { @@ -300,7 +316,7 @@ impl GlConfig for Config { } } -impl X11GlConfigExt for Config { +impl X11GlConfigExt for Config { fn x11_visual(&self) -> Option { unsafe { let raw_visual = self @@ -321,36 +337,36 @@ impl X11GlConfigExt for Config { } } -impl GetGlDisplay for Config { - type Target = Display; +impl GetGlDisplay for Config { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawConfig for Config { +impl AsRawConfig for Config { fn raw_config(&self) -> RawConfig { RawConfig::Glx(*self.inner.raw) } } -impl Sealed for Config {} +impl Sealed for Config {} -pub(crate) struct ConfigInner { - display: Display, +pub(crate) struct ConfigInner { + display: Display, pub(crate) raw: GlxConfig, } -impl PartialEq for ConfigInner { +impl PartialEq for ConfigInner { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } -impl Eq for ConfigInner {} +impl Eq for ConfigInner {} -impl fmt::Debug for ConfigInner { +impl fmt::Debug for ConfigInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Config") .field("raw", &self.raw) diff --git a/glutin/src/api/glx/context.rs b/glutin/src/api/glx/context.rs index af77728a0a..c58417d118 100644 --- a/glutin/src/api/glx/context.rs +++ b/glutin/src/api/glx/context.rs @@ -8,6 +8,8 @@ use std::os::raw::c_int; use glutin_glx_sys::glx::types::GLXContext; use glutin_glx_sys::{glx, glx_extra}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; + use crate::config::GetGlConfig; use crate::context::{ self, AsRawContext, ContextApi, ContextAttributes, GlProfile, RawContext, ReleaseBehavior, @@ -23,14 +25,14 @@ use super::config::Config; use super::display::Display; use super::surface::Surface; -impl Display { - pub(crate) unsafe fn create_context( +impl Display { + pub(crate) fn create_context( &self, - config: &Config, - context_attributes: &ContextAttributes, - ) -> Result { + config: &Config, + context_attributes: &ContextAttributes, + ) -> Result> { let shared_context = if let Some(shared_context) = - context_attributes.shared_context.as_ref() + context_attributes.inner.shared_context.as_ref() { match shared_context { RawContext::Glx(shared_context) => *shared_context, @@ -55,17 +57,17 @@ impl Display { } let config = config.clone(); - let is_gles = matches!(context_attributes.api, Some(ContextApi::Gles(_))); + let is_gles = matches!(context_attributes.inner.api, Some(ContextApi::Gles(_))); let inner = ContextInner { display: self.clone(), config, raw: GlxContext(context), is_gles }; Ok(NotCurrentContext::new(inner)) } - fn create_context_arb( + fn create_context_arb( &self, - config: &Config, - context_attributes: &ContextAttributes, + config: &Config, + context_attributes: &ContextAttributes, shared_context: GLXContext, ) -> Result { let extra = self.inner.glx_extra.as_ref().unwrap(); @@ -74,10 +76,11 @@ impl Display { // Check whether the ES context creation is supported. let supports_es = self.inner.features.contains(DisplayFeatures::CREATE_ES_CONTEXT); - let (profile, version) = match context_attributes.api { + let (profile, version) = match context_attributes.inner.api { api @ Some(ContextApi::OpenGl(_)) | api @ None => { let version = api.and_then(|api| api.version()); - let (profile, version) = context::pick_profile(context_attributes.profile, version); + let (profile, version) = + context::pick_profile(context_attributes.inner.profile, version); let profile = match profile { GlProfile::Core => glx_extra::CONTEXT_CORE_PROFILE_BIT_ARB, GlProfile::Compatibility => glx_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, @@ -111,7 +114,7 @@ impl Display { attrs.push(version.minor as c_int); } - if let Some(profile) = context_attributes.profile { + if let Some(profile) = context_attributes.inner.profile { let profile = match profile { GlProfile::Core => glx_extra::CONTEXT_CORE_PROFILE_BIT_ARB, GlProfile::Compatibility => glx_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, @@ -124,7 +127,7 @@ impl Display { let mut flags: c_int = 0; let mut requested_no_error = false; if self.inner.features.contains(DisplayFeatures::CONTEXT_ROBUSTNESS) { - match context_attributes.robustness { + match context_attributes.inner.robustness { Robustness::NotRobust => (), Robustness::RobustNoResetNotification => { attrs.push(glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int); @@ -149,7 +152,7 @@ impl Display { requested_no_error = true; }, } - } else if context_attributes.robustness != Robustness::NotRobust { + } else if context_attributes.inner.robustness != Robustness::NotRobust { return Err(ErrorKind::NotSupported( "GLX_ARB_create_context_robustness is not supported", ) @@ -157,7 +160,7 @@ impl Display { } // Debug flag. - if context_attributes.debug && !requested_no_error { + if context_attributes.inner.debug && !requested_no_error { flags |= glx_extra::CONTEXT_DEBUG_BIT_ARB as c_int; } @@ -168,7 +171,7 @@ impl Display { // Flush control. if self.inner.features.contains(DisplayFeatures::CONTEXT_RELEASE_BEHAVIOR) { - match context_attributes.release_behavior { + match context_attributes.inner.release_behavior { // This is the default behavior in specification. // // XXX passing it explicitly causing issues with older mesa versions. @@ -178,7 +181,7 @@ impl Display { attrs.push(glx_extra::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); }, } - } else if context_attributes.release_behavior != ReleaseBehavior::Flush { + } else if context_attributes.inner.release_behavior != ReleaseBehavior::Flush { return Err(ErrorKind::NotSupported( "flush control behavior GLX_ARB_context_flush_control", ) @@ -202,7 +205,7 @@ impl Display { fn create_context_legacy( &self, - config: &Config, + config: &Config, shared_context: GLXContext, ) -> Result { let render_type = @@ -223,21 +226,21 @@ impl Display { /// A wrapper around `GLXContext` that is known to be not current. #[derive(Debug)] -pub struct NotCurrentContext { - inner: ContextInner, +pub struct NotCurrentContext { + inner: ContextInner, } -impl NotCurrentContext { - fn new(inner: ContextInner) -> Self { +impl NotCurrentContext { + fn new(inner: ContextInner) -> Self { Self { inner } } } -impl NotCurrentGlContext for NotCurrentContext { - type PossiblyCurrentContext = PossiblyCurrentContext; - type Surface = Surface; +impl NotCurrentGlContext for NotCurrentContext { + type PossiblyCurrentContext = PossiblyCurrentContext; + type Surface = Surface; - fn treat_as_possibly_current(self) -> PossiblyCurrentContext { + fn treat_as_possibly_current(self) -> PossiblyCurrentContext { PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData } } @@ -259,47 +262,47 @@ impl NotCurrentGlContext for NotCurrentContext { } } -impl GlContext for NotCurrentContext { +impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlConfig for NotCurrentContext { - type Target = Config; +impl GetGlConfig for NotCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GetGlDisplay for NotCurrentContext { - type Target = Display; +impl GetGlDisplay for NotCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawContext for NotCurrentContext { +impl AsRawContext for NotCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Glx(*self.inner.raw) } } -impl Sealed for NotCurrentContext {} +impl Sealed for NotCurrentContext {} /// A wrapper around `GLXContext` that could be current for the current thread. #[derive(Debug)] -pub struct PossiblyCurrentContext { - inner: ContextInner, +pub struct PossiblyCurrentContext { + inner: ContextInner, // The context could be current only on the one thread. _nosendsync: PhantomData, } -impl PossiblyCurrentGlContext for PossiblyCurrentContext { - type NotCurrentContext = NotCurrentContext; - type Surface = Surface; +impl PossiblyCurrentGlContext for PossiblyCurrentContext { + type NotCurrentContext = NotCurrentContext; + type Surface = Surface; fn make_not_current(self) -> Result { self.inner.make_not_current()?; @@ -323,48 +326,48 @@ impl PossiblyCurrentGlContext for PossiblyCurrentContext { } } -impl GlContext for PossiblyCurrentContext { +impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlConfig for PossiblyCurrentContext { - type Target = Config; +impl GetGlConfig for PossiblyCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GetGlDisplay for PossiblyCurrentContext { - type Target = Display; +impl GetGlDisplay for PossiblyCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawContext for PossiblyCurrentContext { +impl AsRawContext for PossiblyCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Glx(*self.inner.raw) } } -impl Sealed for PossiblyCurrentContext {} +impl Sealed for PossiblyCurrentContext {} -struct ContextInner { - display: Display, - config: Config, +struct ContextInner { + display: Display, + config: Config, raw: GlxContext, is_gles: bool, } -impl ContextInner { +impl ContextInner { fn make_current_draw_read( &self, - surface_draw: &Surface, - surface_read: &Surface, + surface_draw: &Surface, + surface_read: &Surface, ) -> Result<()> { super::last_glx_error(|| unsafe { self.display.inner.glx.MakeContextCurrent( @@ -396,7 +399,7 @@ impl ContextInner { } } -impl Drop for ContextInner { +impl Drop for ContextInner { fn drop(&mut self) { let _ = super::last_glx_error(|| unsafe { self.display.inner.glx.DestroyContext(self.display.inner.raw.cast(), *self.raw); @@ -404,7 +407,7 @@ impl Drop for ContextInner { } } -impl fmt::Debug for ContextInner { +impl fmt::Debug for ContextInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Context") .field("display", &self.display.inner.raw) diff --git a/glutin/src/api/glx/display.rs b/glutin/src/api/glx/display.rs index 1cdf96d191..b31e7bb762 100644 --- a/glutin/src/api/glx/display.rs +++ b/glutin/src/api/glx/display.rs @@ -9,11 +9,13 @@ use std::sync::Arc; use glutin_glx_sys::glx; use glutin_glx_sys::glx::types::Display as GLXDisplay; -use raw_window_handle::RawDisplayHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle}; use crate::config::ConfigTemplate; use crate::context::Version; -use crate::display::{AsRawDisplay, DisplayFeatures, GetDisplayExtensions, RawDisplay}; +use crate::display::{ + AsRawDisplay, DisplayFeatures, DisplayResult, GetDisplayExtensions, RawDisplay, +}; use crate::error::{ErrorKind, Result}; use crate::prelude::*; use crate::private::Sealed; @@ -25,42 +27,70 @@ use super::surface::Surface; use super::{Glx, GlxExtra, XlibErrorHookRegistrar, GLX, GLX_BASE_ERROR, GLX_EXTRA}; /// A wrapper for the `GLXDisplay`, which is basically an `XDisplay`. -#[derive(Debug, Clone)] -pub struct Display { - pub(crate) inner: Arc, +#[derive(Debug)] +pub struct Display { + pub(crate) inner: Arc>, } -impl Display { +impl Clone for Display { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl AsRef for Display { + fn as_ref(&self) -> &D { + self.display() + } +} + +impl HasDisplayHandle for Display { + fn display_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.display().display_handle() + } +} + +impl Display { /// Create GLX display. - /// - /// # Safety - /// - /// The `display` must point to the valid Xlib display and - /// `error_hook_registrar` must be registered in your Xlib error handling - /// callback. - pub unsafe fn new( - display: RawDisplayHandle, + pub fn new(display_handle: D, error_hook_registrar: XlibErrorHookRegistrar) -> Result { + Self::new_with_display(display_handle, error_hook_registrar).map_err(Into::into) + } + + /// Get a reference to the inner display. + pub fn display(&self) -> &D { + &self.inner.display + } + + pub(crate) fn new_with_display( + display_handle: D, error_hook_registrar: XlibErrorHookRegistrar, - ) -> Result { + ) -> DisplayResult { // Don't load GLX when unsupported platform was requested. - let (display, screen) = match display { - RawDisplayHandle::Xlib(handle) => { - if handle.display.is_null() { - return Err(ErrorKind::BadDisplay.into()); - } - - (GlxDisplay(handle.display as *mut _), handle.screen as i32) + let (display, screen) = match display_handle.display_handle().map(|w| w.as_raw()) { + Ok(RawDisplayHandle::Xlib(handle)) => { + let display = match handle.display { + Some(display) => display.as_ptr(), + None => return Err((ErrorKind::BadDisplay, display_handle).into()), + }; + + (GlxDisplay(display as *mut _), handle.screen as i32) }, - _ => { - return Err( - ErrorKind::NotSupported("provided native display isn't supported").into() + Ok(_) => { + return Err(( + ErrorKind::NotSupported("provided native display isn't supported"), + display_handle, ) + .into()) }, + Err(e) => return Err((crate::error::Error::from(e), display_handle).into()), }; let glx = match GLX.as_ref() { Some(glx) => glx, - None => return Err(ErrorKind::NotFound.into()), + None => return Err((ErrorKind::NotFound, display_handle).into()), }; // Set the base for errors coming from GLX. @@ -69,7 +99,7 @@ impl Display { let mut event_base = 0; if glx.QueryExtension(display.0, &mut error_base, &mut event_base) == 0 { // The glx extension isn't present. - return Err(ErrorKind::InitializationFailed.into()); + return Err((ErrorKind::InitializationFailed, display_handle).into()); } GLX_BASE_ERROR.store(error_base, Ordering::Relaxed); } @@ -85,13 +115,17 @@ impl Display { let version = unsafe { let (mut major, mut minor) = (0, 0); if glx.QueryVersion(display.0, &mut major, &mut minor) == 0 { - return Err(ErrorKind::InitializationFailed.into()); + return Err((ErrorKind::InitializationFailed, display_handle).into()); } Version::new(major as u8, minor as u8) }; if version < Version::new(1, 3) { - return Err(ErrorKind::NotSupported("the glx below 1.3 isn't supported").into()); + return Err(( + ErrorKind::NotSupported("the glx below 1.3 isn't supported"), + display_handle, + ) + .into()); } // Register the error handling hook. @@ -108,6 +142,7 @@ impl Display { screen, features, client_extensions, + display: display_handle, }); Ok(Self { inner }) @@ -167,48 +202,48 @@ impl Display { } } -impl GlDisplay for Display { - type Config = Config; - type NotCurrentContext = NotCurrentContext; - type PbufferSurface = Surface; - type PixmapSurface = Surface; - type WindowSurface = Surface; +impl GlDisplay for Display { + type Config = Config; + type NotCurrentContext = NotCurrentContext; + type PbufferSurface = Surface; + type PixmapSurface = Surface; + type WindowSurface = Surface>; - unsafe fn find_configs( + fn find_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, ) -> Result + '_>> { - unsafe { Self::find_configs(self, template) } + Self::find_configs(self, template) } - unsafe fn create_window_surface( + fn create_window_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, - ) -> Result { - unsafe { Self::create_window_surface(self, config, surface_attributes) } + surface_attributes: SurfaceAttributes>, + ) -> Result> { + Self::create_window_surface(self, config, surface_attributes) } unsafe fn create_pbuffer_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pbuffer_surface(self, config, surface_attributes) } } - unsafe fn create_context( + fn create_context( &self, config: &Self::Config, - context_attributes: &crate::context::ContextAttributes, + context_attributes: &crate::context::ContextAttributes, ) -> Result { - unsafe { Self::create_context(self, config, context_attributes) } + Self::create_context(self, config, context_attributes) } unsafe fn create_pixmap_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pixmap_surface(self, config, surface_attributes) } } @@ -226,21 +261,21 @@ impl GlDisplay for Display { } } -impl GetDisplayExtensions for Display { +impl GetDisplayExtensions for Display { fn extensions(&self) -> &HashSet<&'static str> { &self.inner.client_extensions } } -impl AsRawDisplay for Display { +impl AsRawDisplay for Display { fn raw_display(&self) -> RawDisplay { RawDisplay::Glx(self.inner.raw.cast()) } } -impl Sealed for Display {} +impl Sealed for Display {} -pub(crate) struct DisplayInner { +pub(crate) struct DisplayInner { pub(crate) glx: &'static Glx, pub(crate) glx_extra: Option<&'static GlxExtra>, pub(crate) raw: GlxDisplay, @@ -249,9 +284,12 @@ pub(crate) struct DisplayInner { pub(crate) features: DisplayFeatures, /// Client GLX extensions. pub(crate) client_extensions: HashSet<&'static str>, + + /// Keep around a display reference so everything stays valid. + display: D, } -impl fmt::Debug for DisplayInner { +impl fmt::Debug for DisplayInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Display") .field("raw", &self.raw) diff --git a/glutin/src/api/glx/surface.rs b/glutin/src/api/glx/surface.rs index aeaa42386d..2f9de89163 100644 --- a/glutin/src/api/glx/surface.rs +++ b/glutin/src/api/glx/surface.rs @@ -7,7 +7,7 @@ use std::os::raw::{c_int, c_uint}; use glutin_glx_sys::glx::types::GLXWindow; use glutin_glx_sys::{glx, glx_extra}; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use crate::config::GetGlConfig; use crate::display::{DisplayFeatures, GetGlDisplay}; @@ -25,13 +25,13 @@ use super::display::Display; /// Hint for the attributes array. const ATTR_SIZE_HINT: usize = 8; -impl Display { +impl Display { pub(crate) unsafe fn create_pixmap_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let native_pixmap = surface_attributes.native_pixmap.as_ref().unwrap(); + config: &Config, + surface_attributes: SurfaceAttributes, + ) -> Result> { + let native_pixmap = surface_attributes.inner.native_pixmap.as_ref().unwrap(); let xid = match native_pixmap { NativePixmap::XlibPixmap(xid) => { if *xid == 0 { @@ -67,17 +67,17 @@ impl Display { config, raw: surface, _nosendsync: PhantomData, - _ty: PhantomData, + ty: surface_attributes.ty, }) } pub(crate) unsafe fn create_pbuffer_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let width = surface_attributes.width.unwrap(); - let height = surface_attributes.height.unwrap(); + config: &Config, + surface_attributes: SurfaceAttributes, + ) -> Result> { + let width = surface_attributes.inner.width.unwrap(); + let height = surface_attributes.inner.height.unwrap(); let mut attrs = Vec::::with_capacity(ATTR_SIZE_HINT); @@ -86,7 +86,7 @@ impl Display { attrs.push(glx::PBUFFER_HEIGHT as c_int); attrs.push(height.get() as c_int); attrs.push(glx::LARGEST_PBUFFER as c_int); - attrs.push(surface_attributes.largest_pbuffer as c_int); + attrs.push(surface_attributes.inner.largest_pbuffer as c_int); // Push X11 `None` to terminate the list. attrs.push(0); @@ -101,16 +101,16 @@ impl Display { config, raw: surface, _nosendsync: PhantomData, - _ty: PhantomData, + ty: surface_attributes.ty, }) } - pub(crate) unsafe fn create_window_surface( + pub(crate) fn create_window_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let window = match surface_attributes.raw_window_handle.unwrap() { + config: &Config, + surface_attributes: SurfaceAttributes>, + ) -> Result>> { + let window = match surface_attributes.ty.0.window_handle()?.as_raw() { RawWindowHandle::Xlib(window_handle) => { if window_handle.window == 0 { return Err(ErrorKind::BadNativeWindow.into()); @@ -145,21 +145,21 @@ impl Display { config, raw: surface, _nosendsync: PhantomData, - _ty: PhantomData, + ty: surface_attributes.ty, }) } } /// A wrapper around the `GLXWindow`. -pub struct Surface { - display: Display, - config: Config, +pub struct Surface { + display: Display, + config: Config, pub(crate) raw: GLXWindow, _nosendsync: PhantomData<*const std::ffi::c_void>, - _ty: PhantomData, + ty: T, } -impl Surface { +impl Surface { /// # Safety /// /// The caller must ensure that the attribute could be present. @@ -179,7 +179,29 @@ impl Surface { } } -impl Drop for Surface { +impl Surface> { + /// Get a reference to the underlying window. + pub fn window(&self) -> &W { + &self.ty.0 + } +} + +impl AsRef for Surface> { + fn as_ref(&self) -> &W { + self.window() + } +} + +impl HasWindowHandle for Surface> { + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.window().window_handle() + } +} + +impl Drop for Surface { fn drop(&mut self) { let _ = super::last_glx_error(|| unsafe { match T::surface_type() { @@ -197,8 +219,8 @@ impl Drop for Surface { } } -impl GlSurface for Surface { - type Context = PossiblyCurrentContext; +impl GlSurface for Surface { + type Context = PossiblyCurrentContext; type SurfaceType = T; fn buffer_age(&self) -> u32 { @@ -292,23 +314,23 @@ impl GlSurface for Surface { } } -impl GetGlConfig for Surface { - type Target = Config; +impl GetGlConfig for Surface { + type Target = Config; fn config(&self) -> Self::Target { self.config.clone() } } -impl GetGlDisplay for Surface { - type Target = Display; +impl GetGlDisplay for Surface { + type Target = Display; fn display(&self) -> Self::Target { self.display.clone() } } -impl fmt::Debug for Surface { +impl fmt::Debug for Surface { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Surface") .field("display", &self.display.inner.raw) @@ -319,10 +341,10 @@ impl fmt::Debug for Surface { } } -impl AsRawSurface for Surface { +impl AsRawSurface for Surface { fn raw_surface(&self) -> RawSurface { RawSurface::Glx(self.raw as u64) } } -impl Sealed for Surface {} +impl Sealed for Surface {} diff --git a/glutin/src/api/wgl/config.rs b/glutin/src/api/wgl/config.rs index ad5fabbe8d..9f02032e73 100644 --- a/glutin/src/api/wgl/config.rs +++ b/glutin/src/api/wgl/config.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use std::{fmt, iter}; use glutin_wgl_sys::wgl_extra; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use windows_sys::Win32::Graphics::Gdi::{self as gdi, HDC}; use windows_sys::Win32::Graphics::OpenGL::{self as gl, PIXELFORMATDESCRIPTOR}; @@ -27,13 +27,18 @@ const MAX_QUERY_CONFIGS: usize = 256; const SRGB_ARB: &str = "WGL_ARB_framebuffer_sRGB"; const SRGB_EXT: &str = "WGL_EXT_framebuffer_sRGB"; -impl Display { - pub(crate) unsafe fn find_configs( +impl Display { + pub(crate) fn find_configs( &self, - template: ConfigTemplate, - ) -> Result + '_>> { - let hwnd = match template.native_window { - Some(RawWindowHandle::Win32(window_handle)) => window_handle.hwnd as _, + template: ConfigTemplate, + ) -> Result> + '_>> { + let hwnd = match template + ._native_window + .as_ref() + .map(|w| w.window_handle().map(|w| w.as_raw())) + .transpose()? + { + Some(RawWindowHandle::Win32(window_handle)) => window_handle.hwnd.get() as _, _ => 0, }; let hdc = unsafe { gdi::GetDC(hwnd) }; @@ -47,11 +52,11 @@ impl Display { } } - fn find_normal_configs( + fn find_normal_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, hdc: HDC, - ) -> Result + '_>> { + ) -> Result> + '_>> { let (r_size, g_size, b_size) = match template.color_buffer_type { ColorBufferType::Rgb { r_size, g_size, b_size } => (r_size, g_size, b_size), _ => { @@ -152,11 +157,11 @@ impl Display { } } - fn find_configs_arb( + fn find_configs_arb( &self, - template: ConfigTemplate, + template: ConfigTemplate, hdc: HDC, - ) -> Result + '_>> { + ) -> Result> + '_>> { let wgl_extra = self.inner.wgl_extra.unwrap(); let mut attrs = Vec::::with_capacity(32); @@ -276,20 +281,34 @@ impl Display { } /// A wrapper around `PIXELFORMAT`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Config { - pub(crate) inner: Arc, +#[derive(Debug)] +pub struct Config { + pub(crate) inner: Arc>, } -impl Config { +impl Clone for Config { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + +impl Eq for Config {} + +impl Config { /// Set the pixel format on the native window. /// /// # Safety /// /// The `raw_window_handle` should point to a valid value. - pub unsafe fn apply_on_native_window(&self, raw_window_handle: &RawWindowHandle) -> Result<()> { - let hdc = match raw_window_handle { - RawWindowHandle::Win32(window) => unsafe { gdi::GetDC(window.hwnd as _) }, + pub fn apply_on_native_window(&self, raw_window_handle: impl HasWindowHandle) -> Result<()> { + let hdc = match raw_window_handle.window_handle()?.as_raw() { + RawWindowHandle::Win32(window) => unsafe { gdi::GetDC(window.hwnd.get() as _) }, _ => return Err(ErrorKind::BadNativeWindow.into()), }; @@ -332,7 +351,7 @@ impl Config { } } -impl GlConfig for Config { +impl GlConfig for Config { fn color_buffer_type(&self) -> Option { let (r_size, g_size, b_size) = match self.inner.descriptor.as_ref() { Some(descriptor) => (descriptor.cRedBits, descriptor.cGreenBits, descriptor.cBlueBits), @@ -452,38 +471,38 @@ impl GlConfig for Config { } } -impl GetGlDisplay for Config { - type Target = Display; +impl GetGlDisplay for Config { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl AsRawConfig for Config { +impl AsRawConfig for Config { fn raw_config(&self) -> RawConfig { RawConfig::Wgl(self.inner.pixel_format_index) } } -impl Sealed for Config {} +impl Sealed for Config {} -pub(crate) struct ConfigInner { - pub(crate) display: Display, +pub(crate) struct ConfigInner { + pub(crate) display: Display, pub(crate) hdc: HDC, pub(crate) pixel_format_index: i32, pub(crate) descriptor: Option, } -impl PartialEq for ConfigInner { +impl PartialEq for ConfigInner { fn eq(&self, other: &Self) -> bool { self.pixel_format_index == other.pixel_format_index } } -impl Eq for ConfigInner {} +impl Eq for ConfigInner {} -impl fmt::Debug for ConfigInner { +impl fmt::Debug for ConfigInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Config") .field("hdc", &self.hdc) diff --git a/glutin/src/api/wgl/context.rs b/glutin/src/api/wgl/context.rs index 4ba8fd42eb..67ab6f396b 100644 --- a/glutin/src/api/wgl/context.rs +++ b/glutin/src/api/wgl/context.rs @@ -8,7 +8,7 @@ use std::os::raw::c_int; use glutin_wgl_sys::wgl::types::HGLRC; use glutin_wgl_sys::{wgl, wgl_extra}; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; use windows_sys::Win32::Graphics::Gdi::{self as gdi, HDC}; use crate::config::GetGlConfig; @@ -26,21 +26,26 @@ use super::config::Config; use super::display::Display; use super::surface::Surface; -impl Display { - pub(crate) unsafe fn create_context( +impl Display { + pub(crate) fn create_context( &self, - config: &Config, - context_attributes: &ContextAttributes, - ) -> Result { - let hdc = match context_attributes.raw_window_handle.as_ref() { - handle @ Some(RawWindowHandle::Win32(window)) => unsafe { - let _ = config.apply_on_native_window(handle.unwrap()); - gdi::GetDC(window.hwnd as _) + config: &Config, + context_attributes: &ContextAttributes, + ) -> Result> { + let hdc = match context_attributes + ._window + .as_ref() + .map(|w| w.window_handle().map(|w| w.as_raw())) + .transpose()? + { + Some(RawWindowHandle::Win32(window)) => unsafe { + let _ = config.apply_on_native_window(context_attributes._window.as_ref().unwrap()); + gdi::GetDC(window.hwnd.get() as _) }, _ => config.inner.hdc, }; - let share_ctx = match context_attributes.shared_context { + let share_ctx = match context_attributes.inner.shared_context { Some(RawContext::Wgl(share)) => share, _ => std::ptr::null(), }; @@ -64,16 +69,16 @@ impl Display { }; let config = config.clone(); - let is_gles = matches!(context_attributes.api, Some(ContextApi::Gles(_))); + let is_gles = matches!(context_attributes.inner.api, Some(ContextApi::Gles(_))); let inner = ContextInner { display: self.clone(), config, raw: context, is_gles }; Ok(NotCurrentContext { inner }) } - fn create_context_arb( + fn create_context_arb( &self, hdc: HDC, share_context: HGLRC, - context_attributes: &ContextAttributes, + context_attributes: &ContextAttributes, ) -> Result { let extra = self.inner.wgl_extra.as_ref().unwrap(); let mut attrs = Vec::::with_capacity(16); @@ -81,10 +86,11 @@ impl Display { // Check whether the ES context creation is supported. let supports_es = self.inner.features.contains(DisplayFeatures::CREATE_ES_CONTEXT); - let (profile, version) = match context_attributes.api { + let (profile, version) = match context_attributes.inner.api { api @ Some(ContextApi::OpenGl(_)) | api @ None => { let version = api.and_then(|api| api.version()); - let (profile, version) = context::pick_profile(context_attributes.profile, version); + let (profile, version) = + context::pick_profile(context_attributes.inner.profile, version); let profile = match profile { GlProfile::Core => wgl_extra::CONTEXT_CORE_PROFILE_BIT_ARB, GlProfile::Compatibility => wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, @@ -118,7 +124,7 @@ impl Display { attrs.push(version.minor as c_int); } - if let Some(profile) = context_attributes.profile { + if let Some(profile) = context_attributes.inner.profile { let profile = match profile { GlProfile::Core => wgl_extra::CONTEXT_CORE_PROFILE_BIT_ARB, GlProfile::Compatibility => wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, @@ -131,7 +137,7 @@ impl Display { let mut flags: c_int = 0; let mut requested_no_error = false; if self.inner.features.contains(DisplayFeatures::CONTEXT_ROBUSTNESS) { - match context_attributes.robustness { + match context_attributes.inner.robustness { Robustness::NotRobust => (), Robustness::RobustNoResetNotification => { attrs.push(wgl_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as c_int); @@ -156,7 +162,7 @@ impl Display { requested_no_error = true; }, } - } else if context_attributes.robustness != Robustness::NotRobust { + } else if context_attributes.inner.robustness != Robustness::NotRobust { return Err(ErrorKind::NotSupported( "WGL_ARB_create_context_robustness is not supported", ) @@ -164,7 +170,7 @@ impl Display { } // Debug flag. - if context_attributes.debug && !requested_no_error { + if context_attributes.inner.debug && !requested_no_error { flags |= wgl_extra::CONTEXT_DEBUG_BIT_ARB as c_int; } @@ -175,7 +181,7 @@ impl Display { // Flush control. if self.inner.features.contains(DisplayFeatures::CONTEXT_RELEASE_BEHAVIOR) { - match context_attributes.release_behavior { + match context_attributes.inner.release_behavior { // This is the default behavior in specification. // // XXX even though we check for extensions don't pass it because it could cause @@ -186,7 +192,7 @@ impl Display { attrs.push(wgl_extra::CONTEXT_RELEASE_BEHAVIOR_NONE_ARB as c_int); }, } - } else if context_attributes.release_behavior != ReleaseBehavior::Flush { + } else if context_attributes.inner.release_behavior != ReleaseBehavior::Flush { return Err(ErrorKind::NotSupported( "flush control behavior WGL_ARB_context_flush_control", ) @@ -210,23 +216,23 @@ impl Display { /// A wrapper around the WGL context that is known to be not current to the /// calling thread. #[derive(Debug)] -pub struct NotCurrentContext { - inner: ContextInner, +pub struct NotCurrentContext { + inner: ContextInner, } -impl Sealed for NotCurrentContext {} +impl Sealed for NotCurrentContext {} -impl NotCurrentContext { - fn new(inner: ContextInner) -> Self { +impl NotCurrentContext { + fn new(inner: ContextInner) -> Self { Self { inner } } } -impl NotCurrentGlContext for NotCurrentContext { - type PossiblyCurrentContext = PossiblyCurrentContext; - type Surface = Surface; +impl NotCurrentGlContext for NotCurrentContext { + type PossiblyCurrentContext = PossiblyCurrentContext; + type Surface = Surface; - fn treat_as_possibly_current(self) -> PossiblyCurrentContext { + fn treat_as_possibly_current(self) -> PossiblyCurrentContext { PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData } } @@ -247,29 +253,29 @@ impl NotCurrentGlContext for NotCurrentContext { } } -impl GlContext for NotCurrentContext { +impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl GetGlDisplay for NotCurrentContext { - type Target = Display; +impl GetGlDisplay for NotCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl GetGlConfig for NotCurrentContext { - type Target = Config; +impl GetGlConfig for NotCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl AsRawContext for NotCurrentContext { +impl AsRawContext for NotCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Wgl(*self.inner.raw) } @@ -277,15 +283,15 @@ impl AsRawContext for NotCurrentContext { /// A wrapper around WGL context that could be current to the calling thread. #[derive(Debug)] -pub struct PossiblyCurrentContext { - inner: ContextInner, +pub struct PossiblyCurrentContext { + inner: ContextInner, // The context could be current only on the one thread. _nosendsync: PhantomData, } -impl PossiblyCurrentGlContext for PossiblyCurrentContext { - type NotCurrentContext = NotCurrentContext; - type Surface = Surface; +impl PossiblyCurrentGlContext for PossiblyCurrentContext { + type NotCurrentContext = NotCurrentContext; + type Surface = Surface; fn make_not_current(self) -> Result { unsafe { @@ -317,44 +323,44 @@ impl PossiblyCurrentGlContext for PossiblyCurrentContext { } } -impl Sealed for PossiblyCurrentContext {} +impl Sealed for PossiblyCurrentContext {} -impl GetGlDisplay for PossiblyCurrentContext { - type Target = Display; +impl GetGlDisplay for PossiblyCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { self.inner.display.clone() } } -impl GetGlConfig for PossiblyCurrentContext { - type Target = Config; +impl GetGlConfig for PossiblyCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { self.inner.config.clone() } } -impl GlContext for PossiblyCurrentContext { +impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } } -impl AsRawContext for PossiblyCurrentContext { +impl AsRawContext for PossiblyCurrentContext { fn raw_context(&self) -> RawContext { RawContext::Wgl(*self.inner.raw) } } -struct ContextInner { - display: Display, - config: Config, +struct ContextInner { + display: Display, + config: Config, raw: WglContext, is_gles: bool, } -impl fmt::Debug for ContextInner { +impl fmt::Debug for ContextInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Context") .field("config", &self.config.inner.pixel_format_index) @@ -376,16 +382,16 @@ impl Deref for WglContext { unsafe impl Send for WglContext {} -impl ContextInner { +impl ContextInner { fn make_current_draw_read( &self, - _surface_draw: &Surface, - _surface_read: &Surface, + _surface_draw: &Surface, + _surface_read: &Surface, ) -> ErrorKind { ErrorKind::NotSupported("make_current_draw_read is not supported by WGL") } - fn make_current(&self, surface: &Surface) -> Result<()> { + fn make_current(&self, surface: &Surface) -> Result<()> { unsafe { if wgl::MakeCurrent(surface.hdc as _, self.raw.cast()) == 0 { Err(IoError::last_os_error().into()) @@ -404,7 +410,7 @@ impl ContextInner { } } -impl Drop for ContextInner { +impl Drop for ContextInner { fn drop(&mut self) { unsafe { wgl::DeleteContext(*self.raw); diff --git a/glutin/src/api/wgl/display.rs b/glutin/src/api/wgl/display.rs index 62c1309bf5..11a8df901c 100644 --- a/glutin/src/api/wgl/display.rs +++ b/glutin/src/api/wgl/display.rs @@ -7,13 +7,15 @@ use std::os::windows::ffi::OsStrExt; use std::sync::Arc; use glutin_wgl_sys::wgl; -use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; use windows_sys::Win32::Foundation::HMODULE; use windows_sys::Win32::Graphics::Gdi::HDC; use windows_sys::Win32::System::LibraryLoader as dll_loader; use crate::config::ConfigTemplate; -use crate::display::{AsRawDisplay, DisplayFeatures, GetDisplayExtensions, RawDisplay}; +use crate::display::{ + AsRawDisplay, DisplayFeatures, DisplayResult, GetDisplayExtensions, RawDisplay, +}; use crate::error::{ErrorKind, Result}; use crate::prelude::*; use crate::private::Sealed; @@ -25,52 +27,106 @@ use super::surface::Surface; use super::WglExtra; /// A WGL display. -#[derive(Debug, Clone)] -pub struct Display { - pub(crate) inner: Arc, +#[derive(Debug)] +pub struct Display { + pub(crate) inner: Arc>, } -impl Display { +impl Clone for Display { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +impl AsRef for Display { + fn as_ref(&self) -> &D { + self.display() + } +} + +impl HasDisplayHandle for Display { + #[inline] + fn display_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.display().display_handle() + } +} + +impl Display { /// Create WGL display. /// /// The `native_window` is used to perform extension loading. If it's not /// passed the OpenGL will be limited to what it can do, though, basic /// operations could still be performed. - /// - /// # Safety - /// - /// The `native_window` must point to the valid platform window and have - /// valid `hinstance`. - pub unsafe fn new( - display: RawDisplayHandle, - native_window: Option, - ) -> Result { - if !matches!(display, RawDisplayHandle::Windows(..)) { - return Err(ErrorKind::NotSupported("provided native display is not supported").into()); + pub fn new(display: D, native_window: Option) -> Result { + Self::new_with_display(display, native_window).map_err(Into::into) + } + + /// Get the underlying display. + pub fn display(&self) -> &D { + &self.inner.display + } + + pub(crate) fn new_with_display( + display: D, + native_window: Option, + ) -> DisplayResult { + macro_rules! leap { + ($res:expr) => {{ + match ($res) { + Ok(x) => x, + Err(e) => { + let error = crate::error::Error::from(e); + return Err((error, display).into()); + }, + } + }}; } - let name = - OsStr::new("opengl32.dll").encode_wide().chain(Some(0).into_iter()).collect::>(); + match leap!(display.display_handle().and_then(|r| r.display_handle().map(|r| r.as_raw()))) { + RawDisplayHandle::Windows(..) => {}, + _ => { + return Err(( + ErrorKind::NotSupported("provided native display is not supported"), + display, + ) + .into()) + }, + }; + + let name = OsStr::new("opengl32.dll").encode_wide().chain(Some(0)).collect::>(); let lib_opengl32 = unsafe { dll_loader::LoadLibraryW(name.as_ptr()) }; if lib_opengl32 == 0 { - return Err(ErrorKind::NotFound.into()); + return Err((ErrorKind::NotFound, display).into()); } // In case native window was provided init extra functions. let (wgl_extra, client_extensions) = - if let Some(RawWindowHandle::Win32(window)) = native_window { - unsafe { - let (wgl_extra, client_extensions) = - super::load_extra_functions(window.hinstance as _, window.hwnd as _)?; + match leap!(native_window.map(|w| w.window_handle().map(|w| w.as_raw())).transpose()) { + Some(RawWindowHandle::Win32(window)) => unsafe { + let (wgl_extra, client_extensions) = match super::load_extra_functions( + window.hinstance.map_or(0, |i| i.get()), + window.hwnd.get() as _, + ) { + Ok(x) => x, + Err(e) => return Err((e, display).into()), + }; (Some(wgl_extra), client_extensions) - } - } else { - (None, HashSet::new()) + }, + _ => (None, HashSet::new()), }; let features = Self::extract_display_features(&client_extensions); - let inner = Arc::new(DisplayInner { lib_opengl32, wgl_extra, features, client_extensions }); + let inner = Arc::new(DisplayInner { + lib_opengl32, + wgl_extra, + features, + client_extensions, + display, + }); Ok(Display { inner }) } @@ -122,48 +178,48 @@ impl Display { } } -impl GlDisplay for Display { - type Config = Config; - type NotCurrentContext = NotCurrentContext; - type PbufferSurface = Surface; - type PixmapSurface = Surface; - type WindowSurface = Surface; +impl GlDisplay for Display { + type Config = Config; + type NotCurrentContext = NotCurrentContext; + type PbufferSurface = Surface; + type PixmapSurface = Surface; + type WindowSurface = Surface>; - unsafe fn find_configs( + fn find_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, ) -> Result + '_>> { - unsafe { Self::find_configs(self, template) } + Self::find_configs(self, template) } - unsafe fn create_window_surface( + fn create_window_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, - ) -> Result { - unsafe { Self::create_window_surface(self, config, surface_attributes) } + surface_attributes: SurfaceAttributes>, + ) -> Result> { + Self::create_window_surface(self, config, surface_attributes) } unsafe fn create_pbuffer_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pbuffer_surface(self, config, surface_attributes) } } - unsafe fn create_context( + fn create_context( &self, config: &Self::Config, - context_attributes: &crate::context::ContextAttributes, + context_attributes: &crate::context::ContextAttributes, ) -> Result { - unsafe { Self::create_context(self, config, context_attributes) } + Self::create_context(self, config, context_attributes) } unsafe fn create_pixmap_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { unsafe { Self::create_pixmap_surface(self, config, surface_attributes) } } @@ -190,21 +246,21 @@ impl GlDisplay for Display { } } -impl GetDisplayExtensions for Display { +impl GetDisplayExtensions for Display { fn extensions(&self) -> &HashSet<&'static str> { &self.inner.client_extensions } } -impl AsRawDisplay for Display { +impl AsRawDisplay for Display { fn raw_display(&self) -> RawDisplay { RawDisplay::Wgl } } -impl Sealed for Display {} +impl Sealed for Display {} -pub(crate) struct DisplayInner { +pub(crate) struct DisplayInner { /// Client WGL extensions. pub(crate) lib_opengl32: HMODULE, @@ -214,9 +270,12 @@ pub(crate) struct DisplayInner { pub(crate) features: DisplayFeatures, pub(crate) client_extensions: HashSet<&'static str>, + + /// Hold onto the display reference to keep it valid. + pub(crate) display: D, } -impl fmt::Debug for DisplayInner { +impl fmt::Debug for DisplayInner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Display") .field("features", &self.features) diff --git a/glutin/src/api/wgl/mod.rs b/glutin/src/api/wgl/mod.rs index 1d4de18eba..3839a1904a 100644 --- a/glutin/src/api/wgl/mod.rs +++ b/glutin/src/api/wgl/mod.rs @@ -74,8 +74,7 @@ unsafe fn load_extra_functions( class }; - let class_name = - OsStr::new("WglDummy Window").encode_wide().chain(Some(0).into_iter()).collect::>(); + let class_name = OsStr::new("WglDummy Window").encode_wide().chain(Some(0)).collect::>(); class.cbSize = mem::size_of::() as _; class.lpszClassName = class_name.as_ptr(); @@ -89,8 +88,7 @@ unsafe fn load_extra_functions( // This dummy wnidow should match the real one enough to get the same OpenGL // driver. - let title = - OsStr::new("dummy window").encode_wide().chain(Some(0).into_iter()).collect::>(); + let title = OsStr::new("dummy window").encode_wide().chain(Some(0)).collect::>(); let ex_style = wm::WS_EX_APPWINDOW; let style = wm::WS_POPUP | wm::WS_CLIPSIBLINGS | wm::WS_CLIPCHILDREN; diff --git a/glutin/src/api/wgl/surface.rs b/glutin/src/api/wgl/surface.rs index fb3c204666..3b823775d9 100644 --- a/glutin/src/api/wgl/surface.rs +++ b/glutin/src/api/wgl/surface.rs @@ -1,11 +1,10 @@ //! A wrapper around `HWND` used for GL operations. use std::io::Error as IoError; -use std::marker::PhantomData; use std::num::NonZeroU32; use std::{fmt, mem}; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; 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}; @@ -25,36 +24,32 @@ use super::config::Config; use super::context::PossiblyCurrentContext; use super::display::Display; -impl Display { +impl Display { pub(crate) unsafe fn create_pixmap_surface( &self, - _config: &Config, - _surface_attributes: &SurfaceAttributes, - ) -> Result> { + _config: &Config, + _surface_attributes: SurfaceAttributes, + ) -> Result> { Err(ErrorKind::NotSupported("pixmaps are not implemented with WGL").into()) } pub(crate) unsafe fn create_pbuffer_surface( &self, - _config: &Config, - _surface_attributes: &SurfaceAttributes, - ) -> Result> { + _config: &Config, + _surface_attributes: SurfaceAttributes, + ) -> Result> { Err(ErrorKind::NotSupported("pbuffers are not implemented with WGL").into()) } - pub(crate) unsafe fn create_window_surface( + pub(crate) fn create_window_surface( &self, - config: &Config, - surface_attributes: &SurfaceAttributes, - ) -> Result> { - let hwnd = match surface_attributes.raw_window_handle.as_ref().unwrap() { - handle @ RawWindowHandle::Win32(window_handle) => { - if window_handle.hwnd.is_null() { - return Err(ErrorKind::BadNativeWindow.into()); - } - - let _ = unsafe { config.apply_on_native_window(handle) }; - window_handle.hwnd as HWND + config: &Config, + surface_attributes: SurfaceAttributes>, + ) -> Result>> { + let hwnd = match surface_attributes.ty.0.window_handle()?.as_raw() { + RawWindowHandle::Win32(window_handle) => { + let _ = config.apply_on_native_window(&surface_attributes.ty.0); + window_handle.hwnd.get() as HWND }, _ => { return Err( @@ -65,23 +60,50 @@ impl Display { let hdc = unsafe { gdi::GetDC(hwnd) }; - let surface = - Surface { display: self.clone(), config: config.clone(), hwnd, hdc, _ty: PhantomData }; + let surface = Surface { + display: self.clone(), + config: config.clone(), + hwnd, + hdc, + ty: surface_attributes.ty, + }; Ok(surface) } } /// A Wrapper around `HWND`. -pub struct Surface { - display: Display, - config: Config, +pub struct Surface { + display: Display, + config: Config, pub(crate) hwnd: HWND, pub(crate) hdc: HDC, - _ty: PhantomData, + ty: T, +} + +impl Surface> { + /// Get a reference to the underlying window. + pub fn window(&self) -> &W { + &self.ty.0 + } +} + +impl AsRef for Surface> { + fn as_ref(&self) -> &W { + self.window() + } +} + +impl HasWindowHandle for Surface> { + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.window().window_handle() + } } -impl Drop for Surface { +impl Drop for Surface { fn drop(&mut self) { unsafe { gdi::ReleaseDC(self.hwnd, self.hdc); @@ -89,8 +111,8 @@ impl Drop for Surface { } } -impl GlSurface for Surface { - type Context = PossiblyCurrentContext; +impl GlSurface for Surface { + type Context = PossiblyCurrentContext; type SurfaceType = T; fn buffer_age(&self) -> u32 { @@ -170,7 +192,7 @@ impl GlSurface for Surface { } } -impl fmt::Debug for Surface { +impl fmt::Debug for Surface { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Surface") .field("config", &self.config.inner.pixel_format_index) @@ -180,26 +202,26 @@ impl fmt::Debug for Surface { } } -impl AsRawSurface for Surface { +impl AsRawSurface for Surface { fn raw_surface(&self) -> RawSurface { RawSurface::Wgl(self.hwnd as _) } } -impl GetGlConfig for Surface { - type Target = Config; +impl GetGlConfig for Surface { + type Target = Config; fn config(&self) -> Self::Target { self.config.clone() } } -impl GetGlDisplay for Surface { - type Target = Display; +impl GetGlDisplay for Surface { + type Target = Display; fn display(&self) -> Self::Target { self.display.clone() } } -impl Sealed for Surface {} +impl Sealed for Surface {} diff --git a/glutin/src/config.rs b/glutin/src/config.rs index 8cb7626e0e..ed4d773b6c 100644 --- a/glutin/src/config.rs +++ b/glutin/src/config.rs @@ -4,7 +4,7 @@ use std::num::NonZeroU32; use bitflags::bitflags; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use crate::display::{Display, GetGlDisplay}; use crate::private::{gl_api_dispatch, Sealed}; @@ -87,18 +87,100 @@ pub trait AsRawConfig { } /// Builder for the [`ConfigTemplate`]. -#[derive(Debug, Default, Clone)] -pub struct ConfigTemplateBuilder { - template: ConfigTemplate, +#[derive(Debug, Clone)] +pub struct ConfigTemplateBuilder { + template: ConfigTemplate, +} + +impl Default for ConfigTemplateBuilder { + fn default() -> Self { + Self { + template: ConfigTemplate { + color_buffer_type: ColorBufferType::Rgb { r_size: 8, g_size: 8, b_size: 8 }, + alpha_size: 8, + depth_size: 24, + stencil_size: 8, + num_samples: None, + transparency: false, + stereoscopy: None, + min_swap_interval: None, + max_swap_interval: None, + single_buffering: false, + float_pixels: false, + config_surface_types: ConfigSurfaceTypes::WINDOW, + max_pbuffer_width: None, + max_pbuffer_height: None, + _native_window: None, + hardware_accelerated: None, + api: None, + }, + } + } } -impl ConfigTemplateBuilder { +impl ConfigTemplateBuilder { /// Create a new configuration template builder. #[inline] pub fn new() -> Self { Default::default() } + /// Request config that can render to a particular native window. + /// + /// # Platform-specific + /// + /// This will use native window when matching the config to get the best one + /// suitable for rendering into that window. + /// + /// When using WGL it's the most reliable way to get a working + /// configuration. With GLX it'll use the visual passed in + /// `native_window` to match the config. + pub fn compatible_with_native_window( + self, + native_window: W2, + ) -> ConfigTemplateBuilder { + let ConfigTemplate { + color_buffer_type, + alpha_size, + depth_size, + stencil_size, + num_samples, + min_swap_interval, + max_swap_interval, + config_surface_types, + api, + transparency, + single_buffering, + stereoscopy, + float_pixels, + max_pbuffer_width, + hardware_accelerated, + max_pbuffer_height, + .. + } = self.template; + ConfigTemplateBuilder { + template: ConfigTemplate { + color_buffer_type, + alpha_size, + depth_size, + stencil_size, + num_samples, + min_swap_interval, + max_swap_interval, + config_surface_types, + api, + transparency, + single_buffering, + stereoscopy, + float_pixels, + max_pbuffer_width, + hardware_accelerated, + max_pbuffer_height, + _native_window: Some(native_window), + }, + } + } + /// Number of alpha bits in the color buffer. /// /// By default `8` is requested. @@ -230,21 +312,6 @@ impl ConfigTemplateBuilder { self } - /// Request config that can render to a particular native window. - /// - /// # Platform-specific - /// - /// This will use native window when matching the config to get the best one - /// suitable for rendering into that window. - /// - /// When using WGL it's the most reliable way to get a working - /// configuration. With GLX it'll use the visual passed in - /// `native_window` to match the config. - pub fn compatible_with_native_window(mut self, native_window: RawWindowHandle) -> Self { - self.template.native_window = Some(native_window); - self - } - /// With supported swap intervals. /// /// By default the value isn't specified. @@ -265,14 +332,14 @@ impl ConfigTemplateBuilder { /// Build the template to match the configs against. #[must_use] - pub fn build(self) -> ConfigTemplate { + pub fn build(self) -> ConfigTemplate { self.template } } /// The context configuration template that is used to find desired config. #[derive(Debug, Clone)] -pub struct ConfigTemplate { +pub struct ConfigTemplate { /// The type of the backing buffer and ancillary buffers. pub(crate) color_buffer_type: ColorBufferType, @@ -322,7 +389,7 @@ pub struct ConfigTemplate { pub(crate) max_pbuffer_height: Option, /// The native window config should support rendering into. - pub(crate) native_window: Option, + pub(crate) _native_window: Option, } impl Default for ConfigTemplate { @@ -355,7 +422,7 @@ impl Default for ConfigTemplate { max_pbuffer_width: None, max_pbuffer_height: None, - native_window: None, + _native_window: None, hardware_accelerated: None, api: None, @@ -421,32 +488,72 @@ pub enum ColorBufferType { /// ```no_run /// fn test_send() {} /// fn test_sync() {} -/// test_send::(); -/// test_sync::(); +/// test_send::>(); +/// test_sync::>(); /// ``` /// /// [`Surface`]: crate::surface::Surface /// [`Context`]: crate::context::NotCurrentContext -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Config { +#[derive(Debug)] +pub enum Config { /// The EGL config. #[cfg(egl_backend)] - Egl(EglConfig), + Egl(EglConfig), /// The GLX config. #[cfg(glx_backend)] - Glx(GlxConfig), + Glx(GlxConfig), /// The WGL config. #[cfg(wgl_backend)] - Wgl(WglConfig), + Wgl(WglConfig), /// The CGL config. #[cfg(cgl_backend)] - Cgl(CglConfig), + Cgl(CglConfig), +} + +impl Clone for Config { + fn clone(&self) -> Self { + match self { + #[cfg(egl_backend)] + Self::Egl(config) => Self::Egl(config.clone()), + + #[cfg(glx_backend)] + Self::Glx(config) => Self::Glx(config.clone()), + + #[cfg(wgl_backend)] + Self::Wgl(config) => Self::Wgl(config.clone()), + + #[cfg(cgl_backend)] + Self::Cgl(config) => Self::Cgl(config.clone()), + } + } +} + +impl PartialEq for Config { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + #[cfg(egl_backend)] + (Self::Egl(left), Self::Egl(right)) => left == right, + + #[cfg(glx_backend)] + (Self::Glx(left), Self::Glx(right)) => left == right, + + #[cfg(wgl_backend)] + (Self::Wgl(left), Self::Wgl(right)) => left == right, + + #[cfg(cgl_backend)] + (Self::Cgl(left), Self::Cgl(right)) => left == right, + + _ => false, + } + } } -impl GlConfig for Config { +impl Eq for Config {} + +impl GlConfig for Config { fn color_buffer_type(&self) -> Option { gl_api_dispatch!(self; Self(config) => config.color_buffer_type()) } @@ -492,8 +599,8 @@ impl GlConfig for Config { } } -impl GetGlDisplay for Config { - type Target = Display; +impl GetGlDisplay for Config { + type Target = Display; fn display(&self) -> Self::Target { gl_api_dispatch!(self; Self(config) => config.display(); as Display) @@ -501,13 +608,13 @@ impl GetGlDisplay for Config { } #[cfg(x11_platform)] -impl X11GlConfigExt for Config { +impl X11GlConfigExt for Config { fn x11_visual(&self) -> Option { gl_api_dispatch!(self; Self(config) => config.x11_visual()) } } -impl Sealed for Config {} +impl Sealed for Config {} /// Raw config. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -529,7 +636,7 @@ pub enum RawConfig { Cgl(*const std::ffi::c_void), } -impl AsRawConfig for Config { +impl AsRawConfig for Config { fn raw_config(&self) -> RawConfig { gl_api_dispatch!(self; Self(config) => config.raw_config()) } diff --git a/glutin/src/context.rs b/glutin/src/context.rs index 9e5dd954a9..7407a267fd 100644 --- a/glutin/src/context.rs +++ b/glutin/src/context.rs @@ -3,7 +3,7 @@ #![allow(unreachable_patterns)] use std::ffi; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use crate::config::{Config, GetGlConfig}; use crate::display::{Display, GetGlDisplay}; @@ -126,7 +126,7 @@ pub trait AsRawContext { /// The builder to help customizing context #[derive(Default, Debug, Clone)] pub struct ContextAttributesBuilder { - attributes: ContextAttributes, + attributes: AttributesInner, } impl ContextAttributesBuilder { @@ -203,21 +203,27 @@ impl ContextAttributesBuilder { /// Build the context attributes. /// - /// The `raw_window_handle` isn't required and here for WGL compatibility. + /// This adds the window handle to the attributes. /// /// # Api-specific /// /// - **WGL:** you **must** pass a `raw_window_handle` if you plan to use /// this context with that window. - pub fn build(mut self, raw_window_handle: Option) -> ContextAttributes { - self.attributes.raw_window_handle = raw_window_handle; - self.attributes + pub fn build(self, window_handle: Option) -> ContextAttributes { + ContextAttributes { inner: self.attributes, _window: window_handle } } } /// The attributes that are used to create a graphics context. #[derive(Default, Debug, Clone)] -pub struct ContextAttributes { +pub struct ContextAttributes { + pub(crate) inner: AttributesInner, + pub(crate) _window: Option, +} + +/// The inner context attributes. +#[derive(Debug, Clone, Default)] +pub(crate) struct AttributesInner { pub(crate) release_behavior: ReleaseBehavior, pub(crate) debug: bool, @@ -229,8 +235,6 @@ pub struct ContextAttributes { pub(crate) api: Option, pub(crate) shared_context: Option, - - pub(crate) raw_window_handle: Option, } /// Specifies the tolerance of the OpenGL context to faults. If you accept @@ -352,35 +356,35 @@ pub enum ReleaseBehavior { /// /// ```no_run /// fn test_send() {} -/// test_send::(); +/// test_send::>(); /// ``` /// However it's not `Sync`. /// ```compile_fail /// fn test_sync() {} -/// test_sync::(); +/// test_sync::>(); /// ``` #[derive(Debug)] -pub enum NotCurrentContext { +pub enum NotCurrentContext { /// The EGL context. #[cfg(egl_backend)] - Egl(NotCurrentEglContext), + Egl(NotCurrentEglContext), /// The GLX context. #[cfg(glx_backend)] - Glx(NotCurrentGlxContext), + Glx(NotCurrentGlxContext), /// The WGL context. #[cfg(wgl_backend)] - Wgl(NotCurrentWglContext), + Wgl(NotCurrentWglContext), /// The CGL context. #[cfg(cgl_backend)] - Cgl(NotCurrentCglContext), + Cgl(NotCurrentCglContext), } -impl NotCurrentGlContext for NotCurrentContext { - type PossiblyCurrentContext = PossiblyCurrentContext; - type Surface = Surface; +impl NotCurrentGlContext for NotCurrentContext { + type PossiblyCurrentContext = PossiblyCurrentContext; + type Surface = Surface; fn treat_as_possibly_current(self) -> Self::PossiblyCurrentContext { gl_api_dispatch!(self; Self(context) => context.treat_as_possibly_current(); as PossiblyCurrentContext) @@ -438,35 +442,35 @@ impl NotCurrentGlContext for NotCurrentContext { } } -impl GlContext for NotCurrentContext { +impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { gl_api_dispatch!(self; Self(context) => context.context_api()) } } -impl GetGlConfig for NotCurrentContext { - type Target = Config; +impl GetGlConfig for NotCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { gl_api_dispatch!(self; Self(context) => context.config(); as Config) } } -impl GetGlDisplay for NotCurrentContext { - type Target = Display; +impl GetGlDisplay for NotCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { gl_api_dispatch!(self; Self(context) => context.display(); as Display) } } -impl AsRawContext for NotCurrentContext { +impl AsRawContext for NotCurrentContext { fn raw_context(&self) -> RawContext { gl_api_dispatch!(self; Self(context) => context.raw_context()) } } -impl Sealed for NotCurrentContext {} +impl Sealed for NotCurrentContext {} /// A context that is possibly current on the current thread. /// @@ -485,27 +489,27 @@ impl Sealed for NotCurrentContext {} /// /// [make it not current]: crate::context::PossiblyCurrentGlContext::make_not_current #[derive(Debug)] -pub enum PossiblyCurrentContext { +pub enum PossiblyCurrentContext { /// The EGL context. #[cfg(egl_backend)] - Egl(PossiblyCurrentEglContext), + Egl(PossiblyCurrentEglContext), /// The GLX context. #[cfg(glx_backend)] - Glx(PossiblyCurrentGlxContext), + Glx(PossiblyCurrentGlxContext), /// The WGL context. #[cfg(wgl_backend)] - Wgl(PossiblyCurrentWglContext), + Wgl(PossiblyCurrentWglContext), /// The CGL context. #[cfg(cgl_backend)] - Cgl(PossiblyCurrentCglContext), + Cgl(PossiblyCurrentCglContext), } -impl PossiblyCurrentGlContext for PossiblyCurrentContext { - type NotCurrentContext = NotCurrentContext; - type Surface = Surface; +impl PossiblyCurrentGlContext for PossiblyCurrentContext { + type NotCurrentContext = NotCurrentContext; + type Surface = Surface; fn is_current(&self) -> bool { gl_api_dispatch!(self; Self(context) => context.is_current()) @@ -558,35 +562,35 @@ impl PossiblyCurrentGlContext for PossiblyCurrentContext { } } -impl GlContext for PossiblyCurrentContext { +impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { gl_api_dispatch!(self; Self(context) => context.context_api()) } } -impl GetGlConfig for PossiblyCurrentContext { - type Target = Config; +impl GetGlConfig for PossiblyCurrentContext { + type Target = Config; fn config(&self) -> Self::Target { gl_api_dispatch!(self; Self(context) => context.config(); as Config) } } -impl GetGlDisplay for PossiblyCurrentContext { - type Target = Display; +impl GetGlDisplay for PossiblyCurrentContext { + type Target = Display; fn display(&self) -> Self::Target { gl_api_dispatch!(self; Self(context) => context.display(); as Display) } } -impl AsRawContext for PossiblyCurrentContext { +impl AsRawContext for PossiblyCurrentContext { fn raw_context(&self) -> RawContext { gl_api_dispatch!(self; Self(context) => context.raw_context()) } } -impl Sealed for PossiblyCurrentContext {} +impl Sealed for PossiblyCurrentContext {} /// Raw context. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/glutin/src/display.rs b/glutin/src/display.rs index 25aa99888b..efc3b2481d 100644 --- a/glutin/src/display.rs +++ b/glutin/src/display.rs @@ -6,7 +6,7 @@ use std::ffi::{self, CStr}; use std::fmt; use bitflags::bitflags; -use raw_window_handle::RawDisplayHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use crate::config::{Config, ConfigTemplate, GlConfig}; use crate::context::{ContextAttributes, NotCurrentContext, NotCurrentGlContext}; @@ -30,7 +30,7 @@ use crate::api::wgl::display::Display as WglDisplay; /// A trait to group common display operations. pub trait GlDisplay: Sealed { /// A window surface created by the display. - type WindowSurface: GlSurface; + type WindowSurface: GlSurface>; /// A pixmap surface created by the display. type PixmapSurface: GlSurface; /// A pbuffer surface created by the display. @@ -41,26 +41,13 @@ pub trait GlDisplay: Sealed { type NotCurrentContext: NotCurrentGlContext; /// Find configurations matching the given `template`. - /// - /// # Safety - /// - /// Some platforms use [`RawWindowHandle`] to pick configs, so it - /// must point to a valid object if it was passed on - /// [`crate::config::ConfigTemplate`]. - /// - /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle - unsafe fn find_configs( + fn find_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, ) -> Result + '_>>; /// Create the graphics platform context. /// - /// # Safety - /// - /// Some platforms use [`RawWindowHandle`] for context creation, so it must - /// point to a valid object. - /// /// # Platform-specific /// /// - **Wayland:** this call may latch the underlying back buffer of the @@ -69,26 +56,19 @@ pub trait GlDisplay: Sealed { /// [`GlSurface::swap_buffers`]. To workaround this behavior the current /// context should be made [`not current`]. /// - /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle /// [`not current`]: crate::context::PossiblyCurrentGlContext::make_not_current - unsafe fn create_context( + fn create_context( &self, config: &Self::Config, - context_attributes: &ContextAttributes, + context_attributes: &ContextAttributes, ) -> Result; /// Create the surface that can be used to render into native window. - /// - /// # Safety - /// - /// The [`RawWindowHandle`] must point to a valid object. - /// - /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle - unsafe fn create_window_surface( + fn create_window_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, - ) -> Result; + surface_attributes: SurfaceAttributes>, + ) -> Result>; /// Create the surface that can be used to render into pbuffer. /// @@ -99,7 +79,7 @@ pub trait GlDisplay: Sealed { unsafe fn create_pbuffer_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result; /// Create the surface that can be used to render into pixmap. @@ -112,7 +92,7 @@ pub trait GlDisplay: Sealed { unsafe fn create_pixmap_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result; /// Return the address of an OpenGL function. @@ -171,169 +151,200 @@ pub trait AsRawDisplay { /// ```no_run /// fn test_send() {} /// fn test_sync() {} -/// test_send::(); -/// test_sync::(); +/// test_send::>(); +/// test_sync::>(); /// ``` -#[derive(Debug, Clone)] -pub enum Display { +#[derive(Debug)] +pub enum Display { /// The EGL display. #[cfg(egl_backend)] - Egl(EglDisplay), + Egl(EglDisplay), /// The GLX display. #[cfg(glx_backend)] - Glx(GlxDisplay), + Glx(GlxDisplay), /// The WGL display. #[cfg(wgl_backend)] - Wgl(WglDisplay), + Wgl(WglDisplay), /// The CGL display. #[cfg(cgl_backend)] - Cgl(CglDisplay), + Cgl(CglDisplay), +} + +impl Clone for Display { + fn clone(&self) -> Self { + match self { + #[cfg(egl_backend)] + Self::Egl(display) => Self::Egl(display.clone()), + #[cfg(glx_backend)] + Self::Glx(display) => Self::Glx(display.clone()), + #[cfg(wgl_backend)] + Self::Wgl(display) => Self::Wgl(display.clone()), + #[cfg(cgl_backend)] + Self::Cgl(display) => Self::Cgl(display.clone()), + } + } } -impl Display { +impl Display { /// Create a graphics platform display from the given raw display handle. /// /// The display mixing isn't supported, so if you created EGL display you /// can't use it with the GLX display objects. Interaction between those /// will result in a runtime panic. - /// - /// # Safety - /// - /// The `display` must point to the valid platform display and be valid for - /// the entire lifetime of all Objects created with that display. - /// - /// The `preference` must contain pointers to the valid values if GLX or WGL - /// specific options were used. - pub unsafe fn new(display: RawDisplayHandle, preference: DisplayApiPreference) -> Result { + pub fn new(display: D, preference: DisplayApiPreference<'_>) -> Result { match preference { #[cfg(egl_backend)] - DisplayApiPreference::Egl => unsafe { Ok(Self::Egl(EglDisplay::new(display)?)) }, + DisplayApiPreference::Egl => Ok(Self::Egl(EglDisplay::new(display)?)), #[cfg(glx_backend)] - DisplayApiPreference::Glx(registrar) => unsafe { + DisplayApiPreference::Glx(registrar) => { Ok(Self::Glx(GlxDisplay::new(display, registrar)?)) }, #[cfg(all(egl_backend, glx_backend))] - DisplayApiPreference::GlxThenEgl(registrar) => unsafe { - if let Ok(display) = GlxDisplay::new(display, registrar) { - Ok(Self::Glx(display)) - } else { - Ok(Self::Egl(EglDisplay::new(display)?)) + DisplayApiPreference::GlxThenEgl(registrar) => { + match GlxDisplay::new_with_display(display, registrar) { + Ok(display) => Ok(Self::Glx(display)), + Err(err) => Ok(Self::Egl(EglDisplay::new_with_display(err.display)?)), } }, #[cfg(all(egl_backend, glx_backend))] - DisplayApiPreference::EglThenGlx(registrar) => unsafe { - if let Ok(display) = EglDisplay::new(display) { - Ok(Self::Egl(display)) - } else { - Ok(Self::Glx(GlxDisplay::new(display, registrar)?)) + DisplayApiPreference::EglThenGlx(registrar) => { + match EglDisplay::new_with_display(display) { + Ok(display) => Ok(Self::Egl(display)), + Err(err) => { + Ok(Self::Glx(GlxDisplay::new_with_display(err.display, registrar)?)) + }, } }, #[cfg(wgl_backend)] - DisplayApiPreference::Wgl(window_handle) => unsafe { + DisplayApiPreference::Wgl(window_handle) => { Ok(Self::Wgl(WglDisplay::new(display, window_handle)?)) }, #[cfg(all(egl_backend, wgl_backend))] - DisplayApiPreference::EglThenWgl(window_handle) => unsafe { - if let Ok(display) = EglDisplay::new(display) { - Ok(Self::Egl(display)) - } else { - Ok(Self::Wgl(WglDisplay::new(display, window_handle)?)) + DisplayApiPreference::EglThenWgl(window_handle) => { + match EglDisplay::new_with_display(display) { + Ok(display) => Ok(Self::Egl(display)), + Err(err) => { + Ok(Self::Wgl(WglDisplay::new_with_display(err.display, window_handle)?)) + }, } }, #[cfg(all(egl_backend, wgl_backend))] - DisplayApiPreference::WglThenEgl(window_handle) => unsafe { - if let Ok(display) = WglDisplay::new(display, window_handle) { - Ok(Self::Wgl(display)) - } else { - Ok(Self::Egl(EglDisplay::new(display)?)) + DisplayApiPreference::WglThenEgl(window_handle) => { + match WglDisplay::new_with_display(display, window_handle) { + Ok(display) => Ok(Self::Wgl(display)), + Err(err) => Ok(Self::Egl(EglDisplay::new_with_display(err.display)?)), } }, #[cfg(cgl_backend)] - DisplayApiPreference::Cgl => unsafe { Ok(Self::Cgl(CglDisplay::new(display)?)) }, + DisplayApiPreference::Cgl => Ok(Self::Cgl(CglDisplay::new(display)?)), + DisplayApiPreference::__CaptureLifetime(_) => unreachable!(), } } + + /// Get the display underpinning this type. + pub fn display(&self) -> &D { + match self { + #[cfg(egl_backend)] + Self::Egl(display) => display.display(), + #[cfg(glx_backend)] + Self::Glx(display) => display.display(), + #[cfg(wgl_backend)] + Self::Wgl(display) => display.display(), + #[cfg(cgl_backend)] + Self::Cgl(display) => display.display(), + } + } +} + +impl AsRef for Display { + #[inline] + fn as_ref(&self) -> &D { + self.display() + } +} + +impl HasDisplayHandle for Display { + #[inline] + fn display_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.display().display_handle() + } } -impl GlDisplay for Display { - type Config = Config; - type NotCurrentContext = NotCurrentContext; - type PbufferSurface = Surface; - type PixmapSurface = Surface; - type WindowSurface = Surface; +impl GlDisplay for Display { + type Config = Config; + type NotCurrentContext = NotCurrentContext; + type PbufferSurface = Surface; + type PixmapSurface = Surface; + type WindowSurface = Surface>; - unsafe fn find_configs( + fn find_configs( &self, - template: ConfigTemplate, + template: ConfigTemplate, ) -> Result + '_>> { match self { #[cfg(egl_backend)] - Self::Egl(display) => unsafe { - Ok(Box::new(display.find_configs(template)?.map(Config::Egl))) - }, + Self::Egl(display) => Ok(Box::new(display.find_configs(template)?.map(Config::Egl))), #[cfg(glx_backend)] - Self::Glx(display) => unsafe { - Ok(Box::new(display.find_configs(template)?.map(Config::Glx))) - }, + Self::Glx(display) => Ok(Box::new(display.find_configs(template)?.map(Config::Glx))), #[cfg(wgl_backend)] - Self::Wgl(display) => unsafe { - Ok(Box::new(display.find_configs(template)?.map(Config::Wgl))) - }, + Self::Wgl(display) => Ok(Box::new(display.find_configs(template)?.map(Config::Wgl))), #[cfg(cgl_backend)] - Self::Cgl(display) => unsafe { - Ok(Box::new(display.find_configs(template)?.map(Config::Cgl))) - }, + Self::Cgl(display) => Ok(Box::new(display.find_configs(template)?.map(Config::Cgl))), } } - unsafe fn create_context( + fn create_context( &self, config: &Self::Config, - context_attributes: &ContextAttributes, + context_attributes: &ContextAttributes, ) -> Result { match (self, config) { #[cfg(egl_backend)] - (Self::Egl(display), Config::Egl(config)) => unsafe { + (Self::Egl(display), Config::Egl(config)) => { Ok(NotCurrentContext::Egl(display.create_context(config, context_attributes)?)) }, #[cfg(glx_backend)] - (Self::Glx(display), Config::Glx(config)) => unsafe { + (Self::Glx(display), Config::Glx(config)) => { Ok(NotCurrentContext::Glx(display.create_context(config, context_attributes)?)) }, #[cfg(wgl_backend)] - (Self::Wgl(display), Config::Wgl(config)) => unsafe { + (Self::Wgl(display), Config::Wgl(config)) => { Ok(NotCurrentContext::Wgl(display.create_context(config, context_attributes)?)) }, #[cfg(cgl_backend)] - (Self::Cgl(display), Config::Cgl(config)) => unsafe { + (Self::Cgl(display), Config::Cgl(config)) => { Ok(NotCurrentContext::Cgl(display.create_context(config, context_attributes)?)) }, _ => unreachable!(), } } - unsafe fn create_window_surface( + fn create_window_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, - ) -> Result { + surface_attributes: SurfaceAttributes>, + ) -> Result> { match (self, config) { #[cfg(egl_backend)] - (Self::Egl(display), Config::Egl(config)) => unsafe { + (Self::Egl(display), Config::Egl(config)) => { Ok(Surface::Egl(display.create_window_surface(config, surface_attributes)?)) }, #[cfg(glx_backend)] - (Self::Glx(display), Config::Glx(config)) => unsafe { + (Self::Glx(display), Config::Glx(config)) => { Ok(Surface::Glx(display.create_window_surface(config, surface_attributes)?)) }, #[cfg(wgl_backend)] - (Self::Wgl(display), Config::Wgl(config)) => unsafe { + (Self::Wgl(display), Config::Wgl(config)) => { Ok(Surface::Wgl(display.create_window_surface(config, surface_attributes)?)) }, #[cfg(cgl_backend)] - (Self::Cgl(display), Config::Cgl(config)) => unsafe { + (Self::Cgl(display), Config::Cgl(config)) => { Ok(Surface::Cgl(display.create_window_surface(config, surface_attributes)?)) }, _ => unreachable!(), @@ -343,7 +354,7 @@ impl GlDisplay for Display { unsafe fn create_pbuffer_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { match (self, config) { #[cfg(egl_backend)] @@ -369,7 +380,7 @@ impl GlDisplay for Display { unsafe fn create_pixmap_surface( &self, config: &Self::Config, - surface_attributes: &SurfaceAttributes, + surface_attributes: SurfaceAttributes, ) -> Result { match (self, config) { #[cfg(egl_backend)] @@ -405,16 +416,16 @@ impl GlDisplay for Display { } } -impl AsRawDisplay for Display { +impl AsRawDisplay for Display { fn raw_display(&self) -> RawDisplay { gl_api_dispatch!(self; Self(display) => display.raw_display()) } } -impl Sealed for Display {} +impl Sealed for Display {} /// Preference of the display that should be used. -pub enum DisplayApiPreference { +pub enum DisplayApiPreference<'a> { /// Use only EGL. /// /// The EGL is a cross platform recent OpenGL platform. That being said @@ -455,7 +466,7 @@ pub enum DisplayApiPreference { /// When raw window handle isn't provided the display will lack extensions /// support and most features will be lacking. #[cfg(wgl_backend)] - Wgl(Option), + Wgl(Option>), /// Use only CGL. /// @@ -488,7 +499,7 @@ pub enum DisplayApiPreference { /// [`Egl`]: Self::Egl /// [`Wgl`]: Self::Wgl #[cfg(all(egl_backend, wgl_backend))] - EglThenWgl(Option), + EglThenWgl(Option>), /// Prefer WGL and fallback to EGL. /// @@ -497,10 +508,14 @@ pub enum DisplayApiPreference { /// [`Egl`]: Self::Egl /// [`Wgl`]: Self::Wgl #[cfg(all(egl_backend, wgl_backend))] - WglThenEgl(Option), + WglThenEgl(Option>), + + /// Hidden option to capture the lifetime. + #[doc(hidden)] + __CaptureLifetime(std::marker::PhantomData<&'a ()>), } -impl fmt::Debug for DisplayApiPreference { +impl fmt::Debug for DisplayApiPreference<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let api = match self { #[cfg(egl_backend)] @@ -519,6 +534,7 @@ impl fmt::Debug for DisplayApiPreference { DisplayApiPreference::WglThenEgl(_) => "WglThenEgl", #[cfg(cgl_backend)] DisplayApiPreference::Cgl => "Cgl", + DisplayApiPreference::__CaptureLifetime(_) => unreachable!(), }; f.write_fmt(format_args!("DisplayApiPreference::{api}")) @@ -590,3 +606,40 @@ pub enum RawDisplay { #[cfg(cgl_backend)] Cgl, } + +#[cfg_attr(cgl_backend, allow(dead_code))] +pub(crate) struct DisplayError { + /// The error that occurred. + pub(crate) error: crate::error::Error, + + /// The display that caused the error. + pub(crate) display: D, +} + +impl DisplayError> { + #[allow(unused)] + pub(crate) fn unwrap(self) -> DisplayError { + DisplayError { error: self.error, display: self.display.unwrap() } + } +} + +impl From> for crate::error::Error { + fn from(value: DisplayError) -> Self { + value.error + } +} + +impl From<(crate::error::Error, D)> for DisplayError { + fn from(value: (crate::error::Error, D)) -> Self { + Self { error: value.0, display: value.1 } + } +} + +impl From<(crate::error::ErrorKind, D)> for DisplayError { + fn from(value: (crate::error::ErrorKind, D)) -> Self { + Self { error: value.0.into(), display: value.1 } + } +} + +#[cfg_attr(cgl_backend, allow(dead_code))] +pub(crate) type DisplayResult = std::result::Result>; diff --git a/glutin/src/error.rs b/glutin/src/error.rs index 1d17578966..5efdfc5499 100644 --- a/glutin/src/error.rs +++ b/glutin/src/error.rs @@ -1,5 +1,6 @@ //! Glutin error handling. +use raw_window_handle::HandleError; use std::fmt; /// A specialized [`Result`] type for graphics operations. @@ -139,6 +140,12 @@ pub enum ErrorKind { /// The operation is not supported by the platform. NotSupported(&'static str), + /// The display/window handle is unavailable at this time. + HandleUnavailable, + + /// The display/window handle is incompatible with the requested operation. + HandleNotSupported, + /// The misc error that can't be classified occurred. Misc, } @@ -166,6 +173,8 @@ impl ErrorKind { BadNativeWindow => "argument does not refer to a valid native window", ContextLost => "context loss", NotSupported(reason) => reason, + HandleUnavailable => "handle unavailable", + HandleNotSupported => "handle not supported", Misc => "misc platform error", } } @@ -176,3 +185,19 @@ impl fmt::Display for ErrorKind { f.write_str(self.as_str()) } } + +impl From for ErrorKind { + fn from(err: HandleError) -> Self { + match err { + HandleError::NotSupported => ErrorKind::HandleNotSupported, + HandleError::Unavailable => ErrorKind::HandleUnavailable, + _ => ErrorKind::BadDisplay, + } + } +} + +impl From for Error { + fn from(err: HandleError) -> Self { + ErrorKind::from(err).into() + } +} diff --git a/glutin/src/lib.rs b/glutin/src/lib.rs index 1f6d51fa20..c9cdeb3e31 100644 --- a/glutin/src/lib.rs +++ b/glutin/src/lib.rs @@ -81,3 +81,29 @@ pub(crate) mod private { pub(crate) use gl_api_dispatch; } + +/// The absence of a display handle. +#[derive(Debug, Clone, Copy)] +pub struct NoDisplay(core::convert::Infallible); + +impl raw_window_handle::HasDisplayHandle for NoDisplay { + fn display_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + match self.0 {} + } +} + +/// The absence of a window handle. +#[derive(Debug, Clone, Copy)] +pub struct NoWindow(core::convert::Infallible); + +impl raw_window_handle::HasWindowHandle for NoWindow { + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + match self.0 {} + } +} diff --git a/glutin/src/surface.rs b/glutin/src/surface.rs index cdde086a04..5c3b7a4f11 100644 --- a/glutin/src/surface.rs +++ b/glutin/src/surface.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use std::num::NonZeroU32; -use raw_window_handle::RawWindowHandle; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use crate::context::{PossiblyCurrentContext, PossiblyCurrentGlContext}; use crate::display::{Display, GetGlDisplay}; @@ -108,9 +108,26 @@ pub trait AsRawSurface { } /// Builder to get the required set of attributes initialized before hand. -#[derive(Default, Debug, Clone)] -pub struct SurfaceAttributesBuilder { - attributes: SurfaceAttributes, +#[derive(Debug, Clone)] +pub struct SurfaceAttributesBuilder { + inner: AttributesInner, + _ty: PhantomData, +} + +impl Default for SurfaceAttributesBuilder { + fn default() -> Self { + Self { + inner: AttributesInner { + srgb: None, + single_buffer: false, + width: None, + height: None, + largest_pbuffer: false, + native_pixmap: None, + }, + _ty: PhantomData, + } + } } impl SurfaceAttributesBuilder { @@ -127,12 +144,12 @@ impl SurfaceAttributesBuilder { /// This only controls EGL surfaces, other platforms use the context for /// that. pub fn with_srgb(mut self, srgb: Option) -> Self { - self.attributes.srgb = srgb; + self.inner.srgb = srgb; self } } -impl SurfaceAttributesBuilder { +impl SurfaceAttributesBuilder> { /// Specify whether the single buffer should be used instead of double /// buffering. This doesn't guarantee that the resulted buffer will have /// only single buffer, to know that the single buffer is actually used @@ -144,35 +161,34 @@ impl SurfaceAttributesBuilder { /// /// This is EGL specific, other platforms use the context for that. pub fn with_single_buffer(mut self, single_buffer: bool) -> Self { - self.attributes.single_buffer = single_buffer; + self.inner.single_buffer = single_buffer; self } /// Build the surface attributes suitable to create a window surface. pub fn build( mut self, - raw_window_handle: RawWindowHandle, + window: W, width: NonZeroU32, height: NonZeroU32, - ) -> SurfaceAttributes { - self.attributes.raw_window_handle = Some(raw_window_handle); - self.attributes.width = Some(width); - self.attributes.height = Some(height); - self.attributes + ) -> SurfaceAttributes> { + self.inner.width = Some(width); + self.inner.height = Some(height); + SurfaceAttributes { inner: self.inner, ty: WindowSurface(window) } } } impl SurfaceAttributesBuilder { /// Request the largest pbuffer. pub fn with_largest_pbuffer(mut self, largest_pbuffer: bool) -> Self { - self.attributes.largest_pbuffer = largest_pbuffer; + self.inner.largest_pbuffer = largest_pbuffer; self } /// The same as in /// [`SurfaceAttributesBuilder::::with_single_buffer`]. pub fn with_single_buffer(mut self, single_buffer: bool) -> Self { - self.attributes.single_buffer = single_buffer; + self.inner.single_buffer = single_buffer; self } @@ -182,46 +198,52 @@ impl SurfaceAttributesBuilder { width: NonZeroU32, height: NonZeroU32, ) -> SurfaceAttributes { - self.attributes.width = Some(width); - self.attributes.height = Some(height); - self.attributes + self.inner.width = Some(width); + self.inner.height = Some(height); + SurfaceAttributes { inner: self.inner, ty: PbufferSurface } } } impl SurfaceAttributesBuilder { /// Build the surface attributes suitable to create a pixmap surface. pub fn build(mut self, native_pixmap: NativePixmap) -> SurfaceAttributes { - self.attributes.native_pixmap = Some(native_pixmap); - self.attributes + self.inner.native_pixmap = Some(native_pixmap); + SurfaceAttributes { inner: self.inner, ty: PixmapSurface } } } /// Attributes which are used for creating a particular surface. #[derive(Default, Debug, Clone)] pub struct SurfaceAttributes { + #[cfg_attr(any(cgl_backend, all(wgl_backend, not(egl_backend))), allow(dead_code))] + pub(crate) inner: AttributesInner, + pub(crate) ty: T, +} + +/// Inner unassociated attributes. +#[derive(Debug, Clone, Default)] +pub(crate) struct AttributesInner { pub(crate) srgb: Option, pub(crate) single_buffer: bool, pub(crate) width: Option, pub(crate) height: Option, pub(crate) largest_pbuffer: bool, - pub(crate) raw_window_handle: Option, pub(crate) native_pixmap: Option, - _ty: PhantomData, } /// Marker that used to type-gate methods for window. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -pub struct WindowSurface; +pub struct WindowSurface(pub(crate) W); -impl SurfaceTypeTrait for WindowSurface { +impl SurfaceTypeTrait for WindowSurface { fn surface_type() -> SurfaceType { SurfaceType::Window } } -impl ResizeableSurface for WindowSurface {} +impl ResizeableSurface for WindowSurface {} -impl Sealed for WindowSurface {} +impl Sealed for WindowSurface {} /// Marker that used to type-gate methods for pbuffer. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] @@ -274,26 +296,48 @@ pub enum SurfaceType { /// test_sync::>(); /// ``` #[derive(Debug)] -pub enum Surface { +pub enum Surface { /// The EGL surface. #[cfg(egl_backend)] - Egl(EglSurface), + Egl(EglSurface), /// The GLX surface. #[cfg(glx_backend)] - Glx(GlxSurface), + Glx(GlxSurface), /// The WGL surface. #[cfg(wgl_backend)] - Wgl(WglSurface), + Wgl(WglSurface), /// The CGL surface. #[cfg(cgl_backend)] - Cgl(CglSurface), + Cgl(CglSurface), +} + +impl Surface> { + /// Get the underlying window. + pub fn window(&self) -> &W { + gl_api_dispatch!(self; Self(surface) => surface.window()) + } +} + +impl AsRef for Surface> { + fn as_ref(&self) -> &W { + self.window() + } +} + +impl HasWindowHandle for Surface> { + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> + { + self.window().window_handle() + } } -impl GlSurface for Surface { - type Context = PossiblyCurrentContext; +impl GlSurface for Surface { + type Context = PossiblyCurrentContext; type SurfaceType = T; fn buffer_age(&self) -> u32 { @@ -448,21 +492,21 @@ impl GlSurface for Surface { } } -impl GetGlDisplay for Surface { - type Target = Display; +impl GetGlDisplay for Surface { + type Target = Display; fn display(&self) -> Self::Target { gl_api_dispatch!(self; Self(surface) => surface.display(); as Display) } } -impl AsRawSurface for Surface { +impl AsRawSurface for Surface { fn raw_surface(&self) -> RawSurface { gl_api_dispatch!(self; Self(surface) => surface.raw_surface()) } } -impl Sealed for Surface {} +impl Sealed for Surface {} /// A swap interval. /// diff --git a/glutin_examples/Cargo.toml b/glutin_examples/Cargo.toml index 2da256a749..f69e72e75b 100644 --- a/glutin_examples/Cargo.toml +++ b/glutin_examples/Cargo.toml @@ -21,8 +21,8 @@ wayland = ["glutin-winit/wayland", "winit/wayland-dlopen", "winit/wayland-csd-ad [dependencies] glutin = { path = "../glutin", default-features = false } glutin-winit = { path = "../glutin-winit", default-features = false } +raw-window-handle = "0.6.0" png = { version = "0.17.6", optional = true } -raw-window-handle = "0.5" winit = { version = "0.29.2", default-features = false, features = ["rwh_05"] } [target.'cfg(target_os = "android")'.dependencies] diff --git a/glutin_examples/examples/egl_device.rs b/glutin_examples/examples/egl_device.rs index 89c9f1a4f6..b1d4c672eb 100644 --- a/glutin_examples/examples/egl_device.rs +++ b/glutin_examples/examples/egl_device.rs @@ -32,11 +32,12 @@ mod example { let device = devices.first().expect("No available devices"); // Create a display using the device. - let display = - unsafe { Display::with_device(device, None) }.expect("Failed to create display"); + let display = unsafe { Display::::with_device(device, None) } + .expect("Failed to create display"); let template = config_template(); - let config = unsafe { display.find_configs(template) } + let config = display + .find_configs(template) .unwrap() .reduce( |config, acc| { @@ -55,14 +56,15 @@ mod example { // // In particular, since we are doing offscreen rendering we have no raw window // handle to provide. - let context_attributes = ContextAttributesBuilder::new().build(None); + let context_attributes = ContextAttributesBuilder::new().build::(None); // Since glutin by default tries to create OpenGL core context, which may not be // present we should try gles. - let fallback_context_attributes = - ContextAttributesBuilder::new().with_context_api(ContextApi::Gles(None)).build(None); + let fallback_context_attributes = ContextAttributesBuilder::new() + .with_context_api(ContextApi::Gles(None)) + .build::(None); - let not_current = unsafe { + let not_current = { display.create_context(&config, &context_attributes).unwrap_or_else(|_| { display .create_context(&config, &fallback_context_attributes) diff --git a/glutin_examples/src/lib.rs b/glutin_examples/src/lib.rs index 393d1beb7d..ace80050df 100644 --- a/glutin_examples/src/lib.rs +++ b/glutin_examples/src/lib.rs @@ -2,8 +2,9 @@ use std::error::Error; use std::ffi::{CStr, CString}; use std::num::NonZeroU32; use std::ops::Deref; +use std::rc::Rc; -use raw_window_handle::HasRawWindowHandle; +use raw_window_handle::HasWindowHandle; use winit::event::{Event, KeyEvent, WindowEvent}; use winit::keyboard::{Key, NamedKey}; use winit::window::WindowBuilder; @@ -48,7 +49,7 @@ pub fn main(event_loop: winit::event_loop::EventLoop<()>) -> Result<(), Box) -> Result<(), Box) -> Result<(), Box) -> Result<(), Box) -> Result<(), Box::default()); + let gl_surface = + { gl_config.display().create_window_surface(&gl_config, attrs).unwrap() }; // Make it current. let gl_context = @@ -152,6 +156,7 @@ pub fn main(event_loop: winit::event_loop::EventLoop<()>) -> Result<(), Box match event { WindowEvent::Resized(size) => {