1#![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
30pub trait GlDisplay: Sealed {
32 type WindowSurface: GlSurface<WindowSurface>;
34 type PixmapSurface: GlSurface<PixmapSurface>;
36 type PbufferSurface: GlSurface<PbufferSurface>;
38 type Config: GlConfig;
40 type NotCurrentContext: NotCurrentGlContext;
42
43 unsafe fn find_configs(
53 &self,
54 template: ConfigTemplate,
55 ) -> Result<Box<dyn Iterator<Item = Self::Config> + '_>>;
56
57 unsafe fn create_context(
75 &self,
76 config: &Self::Config,
77 context_attributes: &ContextAttributes,
78 ) -> Result<Self::NotCurrentContext>;
79
80 unsafe fn create_window_surface(
88 &self,
89 config: &Self::Config,
90 surface_attributes: &SurfaceAttributes<WindowSurface>,
91 ) -> Result<Self::WindowSurface>;
92
93 unsafe fn create_pbuffer_surface(
100 &self,
101 config: &Self::Config,
102 surface_attributes: &SurfaceAttributes<PbufferSurface>,
103 ) -> Result<Self::PbufferSurface>;
104
105 unsafe fn create_pixmap_surface(
113 &self,
114 config: &Self::Config,
115 surface_attributes: &SurfaceAttributes<PixmapSurface>,
116 ) -> Result<Self::PixmapSurface>;
117
118 fn get_proc_address(&self, addr: &CStr) -> *const ffi::c_void;
126
127 fn version_string(&self) -> String;
132
133 fn supported_features(&self) -> DisplayFeatures;
138}
139
140pub trait GetGlDisplay: Sealed {
142 type Target: GlDisplay;
144
145 fn display(&self) -> Self::Target;
147}
148
149pub trait GetDisplayExtensions: Sealed {
151 fn extensions(&self) -> &HashSet<&'static str>;
158}
159
160pub trait AsRawDisplay {
162 fn raw_display(&self) -> RawDisplay;
164}
165
166#[derive(Debug, Clone)]
178pub enum Display {
179 #[cfg(egl_backend)]
181 Egl(EglDisplay),
182
183 #[cfg(glx_backend)]
185 Glx(GlxDisplay),
186
187 #[cfg(wgl_backend)]
189 Wgl(WglDisplay),
190
191 #[cfg(cgl_backend)]
193 Cgl(CglDisplay),
194}
195
196impl Display {
197 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
416pub enum DisplayApiPreference {
418 #[cfg(egl_backend)]
435 Egl,
436
437 #[cfg(glx_backend)]
447 Glx(XlibErrorHookRegistrar),
448
449 #[cfg(wgl_backend)]
458 Wgl(Option<raw_window_handle::RawWindowHandle>),
459
460 #[cfg(cgl_backend)]
464 Cgl,
465
466 #[cfg(all(egl_backend, glx_backend))]
473 EglThenGlx(XlibErrorHookRegistrar),
474
475 #[cfg(all(egl_backend, glx_backend))]
482 GlxThenEgl(XlibErrorHookRegistrar),
483
484 #[cfg(all(egl_backend, wgl_backend))]
491 EglThenWgl(Option<raw_window_handle::RawWindowHandle>),
492
493 #[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 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
531 pub struct DisplayFeatures: u32 {
532 const CONTEXT_ROBUSTNESS = 0b0000_0001;
536
537 const CONTEXT_NO_ERROR = 0b0000_0010;
541
542 const FLOAT_PIXEL_FORMAT = 0b0000_0100;
546
547 const SWAP_CONTROL = 0b0000_1000;
551
552 const CONTEXT_RELEASE_BEHAVIOR = 0b0001_0000;
556
557 const CREATE_ES_CONTEXT = 0b0010_0000;
561
562 const MULTISAMPLING_PIXEL_FORMATS = 0b0100_0000;
566
567 const SRGB_FRAMEBUFFERS = 0b1000_0000;
571 }
572}
573
574#[derive(Debug, Clone, Copy, PartialEq, Eq)]
576pub enum RawDisplay {
577 #[cfg(egl_backend)]
579 Egl(*const std::ffi::c_void),
580
581 #[cfg(glx_backend)]
583 Glx(*const std::ffi::c_void),
584
585 #[cfg(wgl_backend)]
587 Wgl,
588
589 #[cfg(cgl_backend)]
591 Cgl,
592}