glutin/
display.rs

1//! The OpenGL platform display selection and creation.
2#![allow(unreachable_patterns)]
3
4use std::collections::HashSet;
5use std::ffi::{self, CStr};
6use std::fmt;
7
8use bitflags::bitflags;
9use raw_window_handle::RawDisplayHandle;
10
11use crate::config::{Config, ConfigTemplate, GlConfig};
12use crate::context::{ContextAttributes, NotCurrentContext, NotCurrentGlContext};
13use crate::error::Result;
14use crate::private::{gl_api_dispatch, Sealed};
15use crate::surface::{
16    GlSurface, PbufferSurface, PixmapSurface, Surface, SurfaceAttributes, WindowSurface,
17};
18
19#[cfg(cgl_backend)]
20use crate::api::cgl::display::Display as CglDisplay;
21#[cfg(egl_backend)]
22use crate::api::egl::display::Display as EglDisplay;
23#[cfg(glx_backend)]
24use crate::api::glx::display::Display as GlxDisplay;
25#[cfg(glx_backend)]
26use crate::api::glx::XlibErrorHookRegistrar;
27#[cfg(wgl_backend)]
28use crate::api::wgl::display::Display as WglDisplay;
29
30/// A trait to group common display operations.
31pub trait GlDisplay: Sealed {
32    /// A window surface created by the display.
33    type WindowSurface: GlSurface<WindowSurface>;
34    /// A pixmap surface created by the display.
35    type PixmapSurface: GlSurface<PixmapSurface>;
36    /// A pbuffer surface created by the display.
37    type PbufferSurface: GlSurface<PbufferSurface>;
38    /// A config that is used by the display.
39    type Config: GlConfig;
40    /// A context that is being used by the display.
41    type NotCurrentContext: NotCurrentGlContext;
42
43    /// Find configurations matching the given `template`.
44    ///
45    /// # Safety
46    ///
47    /// Some platforms use [`RawWindowHandle`] to pick configs, so it
48    /// must point to a valid object if it was passed on
49    /// [`crate::config::ConfigTemplate`].
50    ///
51    /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle
52    unsafe fn find_configs(
53        &self,
54        template: ConfigTemplate,
55    ) -> Result<Box<dyn Iterator<Item = Self::Config> + '_>>;
56
57    /// Create the graphics platform context.
58    ///
59    /// # Safety
60    ///
61    /// Some platforms use [`RawWindowHandle`] for context creation, so it must
62    /// point to a valid object.
63    ///
64    /// # Platform-specific
65    ///
66    /// - **Wayland:** this call may latch the underlying back buffer of the
67    ///   currently active context (will do with mesa drivers), meaning that all
68    ///   resize operations will apply to it after the next
69    ///   [`GlSurface::swap_buffers`]. To workaround this behavior the current
70    ///   context should be made [`not current`].
71    ///
72    /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle
73    /// [`not current`]: crate::context::PossiblyCurrentGlContext::make_not_current
74    unsafe fn create_context(
75        &self,
76        config: &Self::Config,
77        context_attributes: &ContextAttributes,
78    ) -> Result<Self::NotCurrentContext>;
79
80    /// Create the surface that can be used to render into native window.
81    ///
82    /// # Safety
83    ///
84    /// The [`RawWindowHandle`] must point to a valid object.
85    ///
86    /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle
87    unsafe fn create_window_surface(
88        &self,
89        config: &Self::Config,
90        surface_attributes: &SurfaceAttributes<WindowSurface>,
91    ) -> Result<Self::WindowSurface>;
92
93    /// Create the surface that can be used to render into pbuffer.
94    ///
95    /// # Safety
96    ///
97    /// The function is safe in general, but marked as not for compatibility
98    /// reasons.
99    unsafe fn create_pbuffer_surface(
100        &self,
101        config: &Self::Config,
102        surface_attributes: &SurfaceAttributes<PbufferSurface>,
103    ) -> Result<Self::PbufferSurface>;
104
105    /// Create the surface that can be used to render into pixmap.
106    ///
107    /// # Safety
108    ///
109    /// The [`NativePixmap`] must represent a valid native pixmap.
110    ///
111    /// [`NativePixmap`]: crate::surface::NativePixmap
112    unsafe fn create_pixmap_surface(
113        &self,
114        config: &Self::Config,
115        surface_attributes: &SurfaceAttributes<PixmapSurface>,
116    ) -> Result<Self::PixmapSurface>;
117
118    /// Return the address of an OpenGL function.
119    ///
120    /// # Api-specific
121    ///
122    /// - **WGL:** to load all the functions you must have a current context on
123    ///   the calling thread, otherwise only a limited set of functions will be
124    ///   loaded.
125    fn get_proc_address(&self, addr: &CStr) -> *const ffi::c_void;
126
127    /// Helper to obtain the information about the underlying display.
128    ///
129    /// This function is intended to be used for logging purposes to help with
130    /// troubleshooting issues.
131    fn version_string(&self) -> String;
132
133    /// Get the features supported by the display.
134    ///
135    /// These features could be used to check that something is supported
136    /// beforehand instead of doing fallback.
137    fn supported_features(&self) -> DisplayFeatures;
138}
139
140/// Get the [`Display`].
141pub trait GetGlDisplay: Sealed {
142    /// The display used by the object.
143    type Target: GlDisplay;
144
145    /// Obtain the GL display used to create a particular GL object.
146    fn display(&self) -> Self::Target;
147}
148
149/// Obtain the underlying api extensions.
150pub trait GetDisplayExtensions: Sealed {
151    /// Supported extensions by the display.
152    ///
153    /// # Api-specific
154    ///
155    /// - **WGL:** to have extensions loaded, `raw_window_handle` must be used
156    ///   when creating the display.
157    fn extensions(&self) -> &HashSet<&'static str>;
158}
159
160/// Get the raw handle to the [`Display`].
161pub trait AsRawDisplay {
162    /// A raw handle to the underlying Api display.
163    fn raw_display(&self) -> RawDisplay;
164}
165
166/// The graphics display to handle underlying graphics platform in a
167/// cross-platform way.
168///
169/// The display can be accessed from any thread.
170///
171/// ```no_run
172/// fn test_send<T: Send>() {}
173/// fn test_sync<T: Sync>() {}
174/// test_send::<glutin::display::Display>();
175/// test_sync::<glutin::display::Display>();
176/// ```
177#[derive(Debug, Clone)]
178pub enum Display {
179    /// The EGL display.
180    #[cfg(egl_backend)]
181    Egl(EglDisplay),
182
183    /// The GLX display.
184    #[cfg(glx_backend)]
185    Glx(GlxDisplay),
186
187    /// The WGL display.
188    #[cfg(wgl_backend)]
189    Wgl(WglDisplay),
190
191    /// The CGL display.
192    #[cfg(cgl_backend)]
193    Cgl(CglDisplay),
194}
195
196impl Display {
197    /// Create a graphics platform display from the given raw display handle.
198    ///
199    /// The display mixing isn't supported, so if you created EGL display you
200    /// can't use it with the GLX display objects. Interaction between those
201    /// will result in a runtime panic.
202    ///
203    /// # Safety
204    ///
205    /// The `display` must point to the valid platform display and be valid for
206    /// the entire lifetime of all Objects created with that display.
207    ///
208    /// The `preference` must contain pointers to the valid values if GLX or WGL
209    /// specific options were used.
210    pub unsafe fn new(display: RawDisplayHandle, preference: DisplayApiPreference) -> Result<Self> {
211        match preference {
212            #[cfg(egl_backend)]
213            DisplayApiPreference::Egl => unsafe { Ok(Self::Egl(EglDisplay::new(display)?)) },
214            #[cfg(glx_backend)]
215            DisplayApiPreference::Glx(registrar) => unsafe {
216                Ok(Self::Glx(GlxDisplay::new(display, registrar)?))
217            },
218            #[cfg(all(egl_backend, glx_backend))]
219            DisplayApiPreference::GlxThenEgl(registrar) => unsafe {
220                if let Ok(display) = GlxDisplay::new(display, registrar) {
221                    Ok(Self::Glx(display))
222                } else {
223                    Ok(Self::Egl(EglDisplay::new(display)?))
224                }
225            },
226            #[cfg(all(egl_backend, glx_backend))]
227            DisplayApiPreference::EglThenGlx(registrar) => unsafe {
228                if let Ok(display) = EglDisplay::new(display) {
229                    Ok(Self::Egl(display))
230                } else {
231                    Ok(Self::Glx(GlxDisplay::new(display, registrar)?))
232                }
233            },
234            #[cfg(wgl_backend)]
235            DisplayApiPreference::Wgl(window_handle) => unsafe {
236                Ok(Self::Wgl(WglDisplay::new(display, window_handle)?))
237            },
238            #[cfg(all(egl_backend, wgl_backend))]
239            DisplayApiPreference::EglThenWgl(window_handle) => unsafe {
240                if let Ok(display) = EglDisplay::new(display) {
241                    Ok(Self::Egl(display))
242                } else {
243                    Ok(Self::Wgl(WglDisplay::new(display, window_handle)?))
244                }
245            },
246            #[cfg(all(egl_backend, wgl_backend))]
247            DisplayApiPreference::WglThenEgl(window_handle) => unsafe {
248                if let Ok(display) = WglDisplay::new(display, window_handle) {
249                    Ok(Self::Wgl(display))
250                } else {
251                    Ok(Self::Egl(EglDisplay::new(display)?))
252                }
253            },
254            #[cfg(cgl_backend)]
255            DisplayApiPreference::Cgl => unsafe { Ok(Self::Cgl(CglDisplay::new(display)?)) },
256        }
257    }
258}
259
260impl GlDisplay for Display {
261    type Config = Config;
262    type NotCurrentContext = NotCurrentContext;
263    type PbufferSurface = Surface<PbufferSurface>;
264    type PixmapSurface = Surface<PixmapSurface>;
265    type WindowSurface = Surface<WindowSurface>;
266
267    unsafe fn find_configs(
268        &self,
269        template: ConfigTemplate,
270    ) -> Result<Box<dyn Iterator<Item = Self::Config> + '_>> {
271        match self {
272            #[cfg(egl_backend)]
273            Self::Egl(display) => unsafe {
274                Ok(Box::new(display.find_configs(template)?.map(Config::Egl)))
275            },
276            #[cfg(glx_backend)]
277            Self::Glx(display) => unsafe {
278                Ok(Box::new(display.find_configs(template)?.map(Config::Glx)))
279            },
280            #[cfg(wgl_backend)]
281            Self::Wgl(display) => unsafe {
282                Ok(Box::new(display.find_configs(template)?.map(Config::Wgl)))
283            },
284            #[cfg(cgl_backend)]
285            Self::Cgl(display) => unsafe {
286                Ok(Box::new(display.find_configs(template)?.map(Config::Cgl)))
287            },
288        }
289    }
290
291    unsafe fn create_context(
292        &self,
293        config: &Self::Config,
294        context_attributes: &ContextAttributes,
295    ) -> Result<Self::NotCurrentContext> {
296        match (self, config) {
297            #[cfg(egl_backend)]
298            (Self::Egl(display), Config::Egl(config)) => unsafe {
299                Ok(NotCurrentContext::Egl(display.create_context(config, context_attributes)?))
300            },
301            #[cfg(glx_backend)]
302            (Self::Glx(display), Config::Glx(config)) => unsafe {
303                Ok(NotCurrentContext::Glx(display.create_context(config, context_attributes)?))
304            },
305            #[cfg(wgl_backend)]
306            (Self::Wgl(display), Config::Wgl(config)) => unsafe {
307                Ok(NotCurrentContext::Wgl(display.create_context(config, context_attributes)?))
308            },
309            #[cfg(cgl_backend)]
310            (Self::Cgl(display), Config::Cgl(config)) => unsafe {
311                Ok(NotCurrentContext::Cgl(display.create_context(config, context_attributes)?))
312            },
313            _ => unreachable!(),
314        }
315    }
316
317    unsafe fn create_window_surface(
318        &self,
319        config: &Self::Config,
320        surface_attributes: &SurfaceAttributes<WindowSurface>,
321    ) -> Result<Self::WindowSurface> {
322        match (self, config) {
323            #[cfg(egl_backend)]
324            (Self::Egl(display), Config::Egl(config)) => unsafe {
325                Ok(Surface::Egl(display.create_window_surface(config, surface_attributes)?))
326            },
327            #[cfg(glx_backend)]
328            (Self::Glx(display), Config::Glx(config)) => unsafe {
329                Ok(Surface::Glx(display.create_window_surface(config, surface_attributes)?))
330            },
331            #[cfg(wgl_backend)]
332            (Self::Wgl(display), Config::Wgl(config)) => unsafe {
333                Ok(Surface::Wgl(display.create_window_surface(config, surface_attributes)?))
334            },
335            #[cfg(cgl_backend)]
336            (Self::Cgl(display), Config::Cgl(config)) => unsafe {
337                Ok(Surface::Cgl(display.create_window_surface(config, surface_attributes)?))
338            },
339            _ => unreachable!(),
340        }
341    }
342
343    unsafe fn create_pbuffer_surface(
344        &self,
345        config: &Self::Config,
346        surface_attributes: &SurfaceAttributes<PbufferSurface>,
347    ) -> Result<Self::PbufferSurface> {
348        match (self, config) {
349            #[cfg(egl_backend)]
350            (Self::Egl(display), Config::Egl(config)) => unsafe {
351                Ok(Surface::Egl(display.create_pbuffer_surface(config, surface_attributes)?))
352            },
353            #[cfg(glx_backend)]
354            (Self::Glx(display), Config::Glx(config)) => unsafe {
355                Ok(Surface::Glx(display.create_pbuffer_surface(config, surface_attributes)?))
356            },
357            #[cfg(wgl_backend)]
358            (Self::Wgl(display), Config::Wgl(config)) => unsafe {
359                Ok(Surface::Wgl(display.create_pbuffer_surface(config, surface_attributes)?))
360            },
361            #[cfg(cgl_backend)]
362            (Self::Cgl(display), Config::Cgl(config)) => unsafe {
363                Ok(Surface::Cgl(display.create_pbuffer_surface(config, surface_attributes)?))
364            },
365            _ => unreachable!(),
366        }
367    }
368
369    unsafe fn create_pixmap_surface(
370        &self,
371        config: &Self::Config,
372        surface_attributes: &SurfaceAttributes<PixmapSurface>,
373    ) -> Result<Self::PixmapSurface> {
374        match (self, config) {
375            #[cfg(egl_backend)]
376            (Self::Egl(display), Config::Egl(config)) => unsafe {
377                Ok(Surface::Egl(display.create_pixmap_surface(config, surface_attributes)?))
378            },
379            #[cfg(glx_backend)]
380            (Self::Glx(display), Config::Glx(config)) => unsafe {
381                Ok(Surface::Glx(display.create_pixmap_surface(config, surface_attributes)?))
382            },
383            #[cfg(wgl_backend)]
384            (Self::Wgl(display), Config::Wgl(config)) => unsafe {
385                Ok(Surface::Wgl(display.create_pixmap_surface(config, surface_attributes)?))
386            },
387            #[cfg(cgl_backend)]
388            (Self::Cgl(display), Config::Cgl(config)) => unsafe {
389                Ok(Surface::Cgl(display.create_pixmap_surface(config, surface_attributes)?))
390            },
391            _ => unreachable!(),
392        }
393    }
394
395    fn get_proc_address(&self, addr: &CStr) -> *const ffi::c_void {
396        gl_api_dispatch!(self; Self(display) => display.get_proc_address(addr))
397    }
398
399    fn version_string(&self) -> String {
400        gl_api_dispatch!(self; Self(display) => display.version_string())
401    }
402
403    fn supported_features(&self) -> DisplayFeatures {
404        gl_api_dispatch!(self; Self(display) => display.supported_features())
405    }
406}
407
408impl AsRawDisplay for Display {
409    fn raw_display(&self) -> RawDisplay {
410        gl_api_dispatch!(self; Self(display) => display.raw_display())
411    }
412}
413
414impl Sealed for Display {}
415
416/// Preference of the display that should be used.
417pub enum DisplayApiPreference {
418    /// Use only EGL.
419    ///
420    /// The EGL is a cross platform recent OpenGL platform. That being said
421    /// it's usually lacking on Windows and not present at all on macOS
422    /// natively.
423    ///
424    /// Be also aware that some features may not be present with it, like window
425    /// transparency on X11 with mesa.
426    ///
427    /// But despite this issues it should be preferred on at least Linux over
428    /// GLX, given that GLX is phasing away.
429    ///
430    /// # Platform-specific
431    ///
432    /// **Windows:** ANGLE can be used if `libEGL.dll` and `libGLESv2.dll` are
433    ///              in the library search path.
434    #[cfg(egl_backend)]
435    Egl,
436
437    /// Use only GLX.
438    ///
439    /// The native GLX platform, it's not very optimal since it's usually tied
440    /// to Xlib. It's know to work fine, but be aware that you must register
441    /// glutin with your X11  error handling callback, since it's a
442    /// per-process global state.
443    ///
444    /// The hook to register glutin error handler in the X11 error handling
445    /// function.
446    #[cfg(glx_backend)]
447    Glx(XlibErrorHookRegistrar),
448
449    /// Use only WGL.
450    ///
451    /// The most spread platform on Windows and what should be used on it by
452    /// default. EGL usually not present there so you'd have to account for that
453    /// and create the window beforehand.
454    ///
455    /// When raw window handle isn't provided the display will lack extensions
456    /// support and most features will be lacking.
457    #[cfg(wgl_backend)]
458    Wgl(Option<raw_window_handle::RawWindowHandle>),
459
460    /// Use only CGL.
461    ///
462    /// The only option on macOS for now.
463    #[cfg(cgl_backend)]
464    Cgl,
465
466    /// Prefer EGL and fallback to GLX.
467    ///
468    /// See [`Egl`] and [`Glx`] to decide what you want.
469    ///
470    /// [`Egl`]: Self::Egl
471    /// [`Glx`]: Self::Glx
472    #[cfg(all(egl_backend, glx_backend))]
473    EglThenGlx(XlibErrorHookRegistrar),
474
475    /// Prefer GLX and fallback to EGL.
476    ///
477    /// See [`Egl`] and [`Glx`] to decide what you want.
478    ///
479    /// [`Egl`]: Self::Egl
480    /// [`Glx`]: Self::Glx
481    #[cfg(all(egl_backend, glx_backend))]
482    GlxThenEgl(XlibErrorHookRegistrar),
483
484    /// Prefer EGL and fallback to WGL.
485    ///
486    /// See [`Egl`] and [`Wgl`] to decide what you want.
487    ///
488    /// [`Egl`]: Self::Egl
489    /// [`Wgl`]: Self::Wgl
490    #[cfg(all(egl_backend, wgl_backend))]
491    EglThenWgl(Option<raw_window_handle::RawWindowHandle>),
492
493    /// Prefer WGL and fallback to EGL.
494    ///
495    /// See [`Egl`] and [`Wgl`] to decide what you want.
496    ///
497    /// [`Egl`]: Self::Egl
498    /// [`Wgl`]: Self::Wgl
499    #[cfg(all(egl_backend, wgl_backend))]
500    WglThenEgl(Option<raw_window_handle::RawWindowHandle>),
501}
502
503impl fmt::Debug for DisplayApiPreference {
504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505        let api = match self {
506            #[cfg(egl_backend)]
507            DisplayApiPreference::Egl => "Egl",
508            #[cfg(glx_backend)]
509            DisplayApiPreference::Glx(_) => "Glx",
510            #[cfg(all(egl_backend, glx_backend))]
511            DisplayApiPreference::GlxThenEgl(_) => "GlxThenEgl",
512            #[cfg(all(egl_backend, glx_backend))]
513            DisplayApiPreference::EglThenGlx(_) => "EglThenGlx",
514            #[cfg(wgl_backend)]
515            DisplayApiPreference::Wgl(_) => "Wgl",
516            #[cfg(all(egl_backend, wgl_backend))]
517            DisplayApiPreference::EglThenWgl(_) => "EglThenWgl",
518            #[cfg(all(egl_backend, wgl_backend))]
519            DisplayApiPreference::WglThenEgl(_) => "WglThenEgl",
520            #[cfg(cgl_backend)]
521            DisplayApiPreference::Cgl => "Cgl",
522        };
523
524        f.write_fmt(format_args!("DisplayApiPreference::{api}"))
525    }
526}
527
528bitflags! {
529    /// The features and extensions supported by the [`Display`].
530    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
531    pub struct DisplayFeatures: u32 {
532        /// The display supports creating [`robust`] context.
533        ///
534        /// [`robust`]: crate::context::Robustness
535        const CONTEXT_ROBUSTNESS          = 0b0000_0001;
536
537        /// The display supports creating [`no error`] context.
538        ///
539        /// [`no error`]: crate::context::Robustness::NoError
540        const CONTEXT_NO_ERROR            = 0b0000_0010;
541
542        /// The display supports [`floating`] pixel formats.
543        ///
544        /// [`floating`]: crate::config::ConfigTemplateBuilder::with_float_pixels
545        const FLOAT_PIXEL_FORMAT          = 0b0000_0100;
546
547        /// The display supports changing the [`swap interval`] on surfaces.
548        ///
549        /// [`swap interval`]: crate::surface::GlSurface::set_swap_interval
550        const SWAP_CONTROL                = 0b0000_1000;
551
552        /// The display supports creating context with explicit [`release behavior`].
553        ///
554        /// [`release behavior`]: crate::context::ReleaseBehavior
555        const CONTEXT_RELEASE_BEHAVIOR   = 0b0001_0000;
556
557        /// The display supports creating OpenGL ES [`context`].
558        ///
559        /// [`context`]: crate::context::ContextApi::Gles
560        const CREATE_ES_CONTEXT           = 0b0010_0000;
561
562        /// The display supports pixel formats with [`multisampling`].
563        ///
564        /// [`multisampling`]: crate::config::ConfigTemplateBuilder::with_multisampling
565        const MULTISAMPLING_PIXEL_FORMATS = 0b0100_0000;
566
567        /// The display supports creating surfaces backed by [`SRGB`] framebuffers.
568        ///
569        /// [`SRGB`]: crate::surface::SurfaceAttributesBuilder::with_srgb
570        const SRGB_FRAMEBUFFERS           = 0b1000_0000;
571    }
572}
573
574/// Raw GL platform display.
575#[derive(Debug, Clone, Copy, PartialEq, Eq)]
576pub enum RawDisplay {
577    /// Raw EGL display.
578    #[cfg(egl_backend)]
579    Egl(*const std::ffi::c_void),
580
581    /// Raw GLX display.
582    #[cfg(glx_backend)]
583    Glx(*const std::ffi::c_void),
584
585    /// Raw display is WGL.
586    #[cfg(wgl_backend)]
587    Wgl,
588
589    /// Raw display is CGL.
590    #[cfg(cgl_backend)]
591    Cgl,
592}