| 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: &'static 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 | |