glutin/
config.rs

1//! Api config picking and creating utils.
2#![allow(unreachable_patterns)]
3
4use std::num::NonZeroU32;
5
6use bitflags::bitflags;
7use raw_window_handle::RawWindowHandle;
8
9use crate::display::{Display, GetGlDisplay};
10use crate::private::{gl_api_dispatch, Sealed};
11
12#[cfg(x11_platform)]
13use crate::platform::x11::{X11GlConfigExt, X11VisualInfo};
14
15#[cfg(cgl_backend)]
16use crate::api::cgl::config::Config as CglConfig;
17#[cfg(egl_backend)]
18use crate::api::egl::config::Config as EglConfig;
19#[cfg(glx_backend)]
20use crate::api::glx::config::Config as GlxConfig;
21#[cfg(wgl_backend)]
22use crate::api::wgl::config::Config as WglConfig;
23
24/// The trait to group all common config option.
25pub trait GlConfig: Sealed {
26    /// The type of the underlying color buffer.
27    ///
28    /// `None` is returned when the format can not be identified.
29    fn color_buffer_type(&self) -> Option<ColorBufferType>;
30
31    /// Whether the config uses floating pixels.
32    fn float_pixels(&self) -> bool;
33
34    /// The size of the alpha.
35    fn alpha_size(&self) -> u8;
36
37    /// The size of the depth buffer.
38    fn depth_size(&self) -> u8;
39
40    /// The size of the stencil buffer.
41    fn stencil_size(&self) -> u8;
42
43    /// The number of samples in multisample buffer.
44    ///
45    /// Zero would mean that there're no samples.
46    fn num_samples(&self) -> u8;
47
48    /// Whether the config supports creating srgb capable [`Surface`].
49    ///
50    /// [`Surface`]: crate::surface::Surface
51    fn srgb_capable(&self) -> bool;
52
53    /// Whether the config supports creating transparent surfaces.
54    ///
55    /// This function will return `None` when the property couldn't be
56    /// identified, in that case transparent window could still work.
57    fn supports_transparency(&self) -> Option<bool>;
58
59    /// Whether the config is hardware accelerated.
60    ///
61    /// The meaning of this may vary from system to system. On some it could
62    /// mean that you're using a software backend renderer, it could mean
63    /// that you're using not the fastest available GPU, like in laptops
64    /// with hybrid graphics.
65    fn hardware_accelerated(&self) -> bool;
66
67    /// The type of the surfaces that can be created with this config.
68    fn config_surface_types(&self) -> ConfigSurfaceTypes;
69
70    /// The [`crate::config::Api`] supported by the configuration.
71    fn api(&self) -> Api;
72}
73
74/// The trait to
75pub trait GetGlConfig: Sealed {
76    /// The config type.
77    type Target: GlConfig;
78
79    /// Get the GL config used to create a particular GL object.
80    fn config(&self) -> Self::Target;
81}
82
83/// Get the raw config.
84pub trait AsRawConfig {
85    /// Obtain the [`RawConfig`] of the underlying Api.
86    fn raw_config(&self) -> RawConfig;
87}
88
89/// Builder for the [`ConfigTemplate`].
90#[derive(Debug, Default, Clone)]
91pub struct ConfigTemplateBuilder {
92    template: ConfigTemplate,
93}
94
95impl ConfigTemplateBuilder {
96    /// Create a new configuration template builder.
97    #[inline]
98    pub fn new() -> Self {
99        Default::default()
100    }
101
102    /// Number of alpha bits in the color buffer.
103    ///
104    /// By default `8` is requested.
105    #[inline]
106    pub fn with_alpha_size(mut self, alpha_size: u8) -> Self {
107        self.template.alpha_size = alpha_size;
108        self
109    }
110
111    /// Whether the floating pixel formats should be used.
112    ///
113    /// By default `false` is requested.
114    #[inline]
115    pub fn with_float_pixels(mut self, float_pixels: bool) -> Self {
116        self.template.float_pixels = float_pixels;
117        self
118    }
119
120    /// Number of bits in the stencil buffer.
121    ///
122    /// By default `0` is requested.
123    #[inline]
124    pub fn with_stencil_size(mut self, stencil_size: u8) -> Self {
125        self.template.stencil_size = stencil_size;
126        self
127    }
128
129    /// Number of bits in the depth buffer.
130    ///
131    /// By default `0` is requested.
132    #[inline]
133    pub fn with_depth_size(mut self, depth_size: u8) -> Self {
134        self.template.depth_size = depth_size;
135        self
136    }
137
138    /// Whether multisampling configurations should be picked. The `num_samples`
139    /// must be a power of two.
140    ///
141    /// By default multisampling is not specified.
142    #[inline]
143    pub fn with_multisampling(mut self, num_samples: u8) -> Self {
144        debug_assert!(num_samples.is_power_of_two());
145        self.template.num_samples = Some(num_samples);
146        self
147    }
148
149    /// The types of the surfaces that must be supported by the configuration.
150    ///
151    /// By default only the `WINDOW` bit is set.
152    #[inline]
153    pub fn with_surface_type(mut self, config_surface_types: ConfigSurfaceTypes) -> Self {
154        self.template.config_surface_types = config_surface_types;
155        self
156    }
157
158    /// The type of the color buffer.
159    ///
160    /// By default `RGB` buffer with all components sizes of `8` is requested.
161    #[inline]
162    pub fn with_buffer_type(mut self, color_buffer_type: ColorBufferType) -> Self {
163        self.template.color_buffer_type = color_buffer_type;
164        self
165    }
166
167    /// The set of apis that are supported by this configuration.
168    ///
169    /// The default [`Api`] depends on the used graphics platform interface. If
170    /// you want to do config filtering based on the [`Api`] yourself, use
171    /// [`Api::empty`].
172    ///
173    /// # Api-specific
174    ///
175    /// - **EGL:** [`Api::GLES2`] bit is set by default to avoid matching
176    ///   [`Api::GLES1`] configs;
177    /// - **GLX/WGL/CGL:** [`Api::OPENGL`] is always present in the result.
178    #[inline]
179    pub fn with_api(mut self, api: Api) -> Self {
180        self.template.api = Some(api);
181        self
182    }
183
184    /// Whether the stereo pairs should be present.
185    ///
186    /// By default it isn't specified.
187    #[inline]
188    pub fn with_stereoscopy(mut self, stereoscopy: Option<bool>) -> Self {
189        self.template.stereoscopy = stereoscopy;
190        self
191    }
192
193    /// Whether the single buffer should be used.
194    ///
195    /// By default `false` is requested.
196    #[inline]
197    pub fn with_single_buffering(mut self, single_buffering: bool) -> Self {
198        self.template.single_buffering = single_buffering;
199        self
200    }
201
202    /// Whether the configuration should support transparency.
203    ///
204    /// The default is `false`.
205    ///
206    /// # Api-specific
207    ///
208    /// EGL on X11 doesn't provide a way to create a transparent surface at the
209    /// time of writing. Use GLX for that instead.
210    #[inline]
211    pub fn with_transparency(mut self, transparency: bool) -> Self {
212        self.template.transparency = transparency;
213        self
214    }
215
216    /// With the maximum sizes of pbuffer.
217    #[inline]
218    pub fn with_pbuffer_sizes(mut self, width: NonZeroU32, height: NonZeroU32) -> Self {
219        self.template.max_pbuffer_width = Some(width.into());
220        self.template.max_pbuffer_height = Some(height.into());
221        self
222    }
223
224    /// Whether the configuration should prefer hardware accelerated formats or
225    /// not.
226    ///
227    /// By default hardware acceleration or its absence is not requested.
228    pub fn prefer_hardware_accelerated(mut self, hardware_accerelated: Option<bool>) -> Self {
229        self.template.hardware_accelerated = hardware_accerelated;
230        self
231    }
232
233    /// Request config that can render to a particular native window.
234    ///
235    /// # Platform-specific
236    ///
237    /// This will use native window when matching the config to get the best one
238    /// suitable for rendering into that window.
239    ///
240    /// When using WGL it's the most reliable way to get a working
241    /// configuration. With GLX it'll use the visual passed in
242    /// `native_window` to match the config.
243    pub fn compatible_with_native_window(mut self, native_window: RawWindowHandle) -> Self {
244        self.template.native_window = Some(native_window);
245        self
246    }
247
248    /// With supported swap intervals.
249    ///
250    /// By default the value isn't specified.
251    ////
252    /// # Api-specific
253    ///
254    /// Only supported with `EGL`.
255    #[inline]
256    pub fn with_swap_interval(
257        mut self,
258        min_swap_interval: Option<u16>,
259        max_swap_interval: Option<u16>,
260    ) -> Self {
261        self.template.min_swap_interval = min_swap_interval;
262        self.template.max_swap_interval = max_swap_interval;
263        self
264    }
265
266    /// Build the template to match the configs against.
267    #[must_use]
268    pub fn build(self) -> ConfigTemplate {
269        self.template
270    }
271}
272
273/// The context configuration template that is used to find desired config.
274#[derive(Debug, Clone)]
275pub struct ConfigTemplate {
276    /// The type of the backing buffer and ancillary buffers.
277    pub(crate) color_buffer_type: ColorBufferType,
278
279    /// Bits of alpha in the color buffer.
280    pub(crate) alpha_size: u8,
281
282    /// Bits of depth in the depth buffer.
283    pub(crate) depth_size: u8,
284
285    /// Bits of stencil in the stencil buffer.
286    pub(crate) stencil_size: u8,
287
288    /// The amount of samples in multisample buffer.
289    pub(crate) num_samples: Option<u8>,
290
291    /// The minimum swap interval supported by the configuration.
292    pub(crate) min_swap_interval: Option<u16>,
293
294    /// The maximum swap interval supported by the configuration.
295    pub(crate) max_swap_interval: Option<u16>,
296
297    /// The types of the surfaces supported by the configuration.
298    pub(crate) config_surface_types: ConfigSurfaceTypes,
299
300    /// The rendering Api's supported by the configuration.
301    pub(crate) api: Option<Api>,
302
303    /// The config should support transparency.
304    pub(crate) transparency: bool,
305
306    /// The config should prefer single buffering.
307    pub(crate) single_buffering: bool,
308
309    /// The config supports stereoscopy.
310    pub(crate) stereoscopy: Option<bool>,
311
312    /// The config uses floating pixels.
313    pub(crate) float_pixels: bool,
314
315    /// The maximum width of the pbuffer.
316    pub(crate) max_pbuffer_width: Option<u32>,
317
318    /// The config should prefer hardware accelerated formats.
319    pub(crate) hardware_accelerated: Option<bool>,
320
321    /// The maximum height of the pbuffer.
322    pub(crate) max_pbuffer_height: Option<u32>,
323
324    /// The native window config should support rendering into.
325    pub(crate) native_window: Option<RawWindowHandle>,
326}
327
328impl Default for ConfigTemplate {
329    fn default() -> Self {
330        ConfigTemplate {
331            color_buffer_type: ColorBufferType::Rgb { r_size: 8, g_size: 8, b_size: 8 },
332
333            alpha_size: 8,
334
335            depth_size: 24,
336
337            stencil_size: 8,
338
339            num_samples: None,
340
341            transparency: false,
342
343            stereoscopy: None,
344
345            min_swap_interval: None,
346
347            max_swap_interval: None,
348
349            single_buffering: false,
350
351            float_pixels: false,
352
353            config_surface_types: ConfigSurfaceTypes::WINDOW,
354
355            max_pbuffer_width: None,
356            max_pbuffer_height: None,
357
358            native_window: None,
359            hardware_accelerated: None,
360
361            api: None,
362        }
363    }
364}
365
366bitflags! {
367    /// The types of the surface supported by the config.
368    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
369    pub struct ConfigSurfaceTypes: u8 {
370        /// Context must support windows.
371        const WINDOW  = 0b00000001;
372
373        /// Context must support pixmaps.
374        const PIXMAP  = 0b00000010;
375
376        /// Context must support pbuffers.
377        const PBUFFER = 0b00000100;
378    }
379}
380
381bitflags! {
382    /// The Api supported by the config.
383    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
384    pub struct Api : u8 {
385        /// Context supports OpenGL API.
386        const OPENGL = 0b00000001;
387
388        /// Context supports OpenGL ES 1 API.
389        const GLES1  = 0b00000010;
390
391        /// Context supports OpenGL ES 2 API.
392        const GLES2  = 0b00000100;
393
394        /// Context supports OpenGL ES 3 API.
395        const GLES3  = 0b00001000;
396    }
397}
398
399/// The buffer type baked by the config.
400#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401pub enum ColorBufferType {
402    /// The backing buffer is using RGB format.
403    Rgb {
404        /// Size of the red component in bits.
405        r_size: u8,
406        /// Size of the green component in bits.
407        g_size: u8,
408        /// Size of the blue component in bits.
409        b_size: u8,
410    },
411
412    /// The backing buffer is using Luminance.
413    Luminance(u8),
414}
415
416/// The GL configuration used to create [`Surface`] and [`Context`] in a cross
417/// platform way.
418///
419/// The config could be accessed from any thread.
420///
421/// ```no_run
422/// fn test_send<T: Send>() {}
423/// fn test_sync<T: Sync>() {}
424/// test_send::<glutin::config::Config>();
425/// test_sync::<glutin::config::Config>();
426/// ```
427///
428/// [`Surface`]: crate::surface::Surface
429/// [`Context`]: crate::context::NotCurrentContext
430#[derive(Debug, Clone, PartialEq, Eq)]
431pub enum Config {
432    /// The EGL config.
433    #[cfg(egl_backend)]
434    Egl(EglConfig),
435
436    /// The GLX config.
437    #[cfg(glx_backend)]
438    Glx(GlxConfig),
439
440    /// The WGL config.
441    #[cfg(wgl_backend)]
442    Wgl(WglConfig),
443
444    /// The CGL config.
445    #[cfg(cgl_backend)]
446    Cgl(CglConfig),
447}
448
449impl GlConfig for Config {
450    fn color_buffer_type(&self) -> Option<ColorBufferType> {
451        gl_api_dispatch!(self; Self(config) => config.color_buffer_type())
452    }
453
454    fn float_pixels(&self) -> bool {
455        gl_api_dispatch!(self; Self(config) => config.float_pixels())
456    }
457
458    fn alpha_size(&self) -> u8 {
459        gl_api_dispatch!(self; Self(config) => config.alpha_size())
460    }
461
462    fn depth_size(&self) -> u8 {
463        gl_api_dispatch!(self; Self(config) => config.depth_size())
464    }
465
466    fn stencil_size(&self) -> u8 {
467        gl_api_dispatch!(self; Self(config) => config.stencil_size())
468    }
469
470    fn num_samples(&self) -> u8 {
471        gl_api_dispatch!(self; Self(config) => config.num_samples())
472    }
473
474    fn srgb_capable(&self) -> bool {
475        gl_api_dispatch!(self; Self(config) => config.srgb_capable())
476    }
477
478    fn config_surface_types(&self) -> ConfigSurfaceTypes {
479        gl_api_dispatch!(self; Self(config) => config.config_surface_types())
480    }
481
482    fn hardware_accelerated(&self) -> bool {
483        gl_api_dispatch!(self; Self(config) => config.hardware_accelerated())
484    }
485
486    fn supports_transparency(&self) -> Option<bool> {
487        gl_api_dispatch!(self; Self(config) => config.supports_transparency())
488    }
489
490    fn api(&self) -> Api {
491        gl_api_dispatch!(self; Self(config) => config.api())
492    }
493}
494
495impl GetGlDisplay for Config {
496    type Target = Display;
497
498    fn display(&self) -> Self::Target {
499        gl_api_dispatch!(self; Self(config) => config.display(); as Display)
500    }
501}
502
503#[cfg(x11_platform)]
504impl X11GlConfigExt for Config {
505    fn x11_visual(&self) -> Option<X11VisualInfo> {
506        gl_api_dispatch!(self; Self(config) => config.x11_visual())
507    }
508}
509
510impl Sealed for Config {}
511
512/// Raw config.
513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
514pub enum RawConfig {
515    /// Raw EGL config.
516    #[cfg(egl_backend)]
517    Egl(*const std::ffi::c_void),
518
519    /// Raw GLX config.
520    #[cfg(glx_backend)]
521    Glx(*const std::ffi::c_void),
522
523    /// WGL pixel format index.
524    #[cfg(wgl_backend)]
525    Wgl(i32),
526
527    /// NSOpenGLPixelFormat.
528    #[cfg(cgl_backend)]
529    Cgl(*const std::ffi::c_void),
530}
531
532impl AsRawConfig for Config {
533    fn raw_config(&self) -> RawConfig {
534        gl_api_dispatch!(self; Self(config) => config.raw_config())
535    }
536}