1 | //! Api config picking and creating utils. |
2 | #![allow (unreachable_patterns)] |
3 | |
4 | use std::num::NonZeroU32; |
5 | |
6 | use bitflags::bitflags; |
7 | use raw_window_handle::RawWindowHandle; |
8 | |
9 | use crate::display::{Display, GetGlDisplay}; |
10 | use crate::private::{gl_api_dispatch, Sealed}; |
11 | |
12 | #[cfg (x11_platform)] |
13 | use crate::platform::x11::{X11GlConfigExt, X11VisualInfo}; |
14 | |
15 | #[cfg (cgl_backend)] |
16 | use crate::api::cgl::config::Config as CglConfig; |
17 | #[cfg (egl_backend)] |
18 | use crate::api::egl::config::Config as EglConfig; |
19 | #[cfg (glx_backend)] |
20 | use crate::api::glx::config::Config as GlxConfig; |
21 | #[cfg (wgl_backend)] |
22 | use crate::api::wgl::config::Config as WglConfig; |
23 | |
24 | /// The trait to group all common config option. |
25 | pub 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 |
75 | pub 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. |
84 | pub 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)] |
91 | pub struct ConfigTemplateBuilder { |
92 | template: ConfigTemplate, |
93 | } |
94 | |
95 | impl 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)] |
275 | pub 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 | |
328 | impl 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 | |
366 | bitflags! { |
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 | |
381 | bitflags! { |
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)] |
401 | pub 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)] |
431 | pub 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 | |
449 | impl 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 | |
495 | impl 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)] |
504 | impl X11GlConfigExt for Config { |
505 | fn x11_visual(&self) -> Option<X11VisualInfo> { |
506 | gl_api_dispatch!(self; Self(config) => config.x11_visual()) |
507 | } |
508 | } |
509 | |
510 | impl Sealed for Config {} |
511 | |
512 | /// Raw config. |
513 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
514 | pub 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 | |
532 | impl AsRawConfig for Config { |
533 | fn raw_config(&self) -> RawConfig { |
534 | gl_api_dispatch!(self; Self(config) => config.raw_config()) |
535 | } |
536 | } |
537 | |