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}
537