1 | //! The OpenGL platform display selection and creation. |
2 | #![allow (unreachable_patterns)] |
3 | |
4 | use std::collections::HashSet; |
5 | use std::ffi::{self, CStr}; |
6 | use std::fmt; |
7 | |
8 | use bitflags::bitflags; |
9 | use raw_window_handle::RawDisplayHandle; |
10 | |
11 | use crate::config::{Config, ConfigTemplate, GlConfig}; |
12 | use crate::context::{ContextAttributes, NotCurrentContext, NotCurrentGlContext}; |
13 | use crate::error::Result; |
14 | use crate::private::{gl_api_dispatch, Sealed}; |
15 | use crate::surface::{ |
16 | GlSurface, PbufferSurface, PixmapSurface, Surface, SurfaceAttributes, WindowSurface, |
17 | }; |
18 | |
19 | #[cfg (cgl_backend)] |
20 | use crate::api::cgl::display::Display as CglDisplay; |
21 | #[cfg (egl_backend)] |
22 | use crate::api::egl::display::Display as EglDisplay; |
23 | #[cfg (glx_backend)] |
24 | use crate::api::glx::display::Display as GlxDisplay; |
25 | #[cfg (glx_backend)] |
26 | use crate::api::glx::XlibErrorHookRegistrar; |
27 | #[cfg (wgl_backend)] |
28 | use crate::api::wgl::display::Display as WglDisplay; |
29 | |
30 | /// A trait to group common display operations. |
31 | pub 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`]. |
141 | pub 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. |
150 | pub 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`]. |
161 | pub 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)] |
178 | pub 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 | |
196 | impl 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 | |
260 | impl 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 | |
408 | impl AsRawDisplay for Display { |
409 | fn raw_display(&self) -> RawDisplay { |
410 | gl_api_dispatch!(self; Self(display) => display.raw_display()) |
411 | } |
412 | } |
413 | |
414 | impl Sealed for Display {} |
415 | |
416 | /// Preference of the display that should be used. |
417 | pub 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 | |
503 | impl fmt::Debug for DisplayApiPreference { |
504 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
505 | let api: &str = 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 | |
528 | bitflags! { |
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)] |
576 | pub 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 | } |
593 | |