1 | //! OpenGL context creation and initialization. |
2 | |
3 | #![allow (unreachable_patterns)] |
4 | use std::ffi; |
5 | |
6 | use raw_window_handle::RawWindowHandle; |
7 | |
8 | use crate::config::{Config, GetGlConfig}; |
9 | use crate::display::{Display, GetGlDisplay}; |
10 | use crate::error::Result; |
11 | use crate::private::{gl_api_dispatch, Sealed}; |
12 | use crate::surface::{GlSurface, Surface, SurfaceTypeTrait}; |
13 | |
14 | #[cfg (cgl_backend)] |
15 | use crate::api::cgl::context::{ |
16 | NotCurrentContext as NotCurrentCglContext, PossiblyCurrentContext as PossiblyCurrentCglContext, |
17 | }; |
18 | #[cfg (egl_backend)] |
19 | use crate::api::egl::context::{ |
20 | NotCurrentContext as NotCurrentEglContext, PossiblyCurrentContext as PossiblyCurrentEglContext, |
21 | }; |
22 | #[cfg (glx_backend)] |
23 | use crate::api::glx::context::{ |
24 | NotCurrentContext as NotCurrentGlxContext, PossiblyCurrentContext as PossiblyCurrentGlxContext, |
25 | }; |
26 | #[cfg (wgl_backend)] |
27 | use crate::api::wgl::context::{ |
28 | NotCurrentContext as NotCurrentWglContext, PossiblyCurrentContext as PossiblyCurrentWglContext, |
29 | }; |
30 | |
31 | /// A trait to group common context operations. |
32 | pub trait GlContext: Sealed { |
33 | /// Get the [`ContextApi`] used by the context. |
34 | /// |
35 | /// The returned value's [`Version`] will always be `None`. |
36 | fn context_api(&self) -> ContextApi; |
37 | } |
38 | |
39 | /// A trait to group common not current operations. |
40 | pub trait NotCurrentGlContext: Sealed { |
41 | /// The type of possibly current context. |
42 | type PossiblyCurrentContext: PossiblyCurrentGlContext; |
43 | |
44 | /// The surface supported by the context. |
45 | type Surface<T: SurfaceTypeTrait>: GlSurface<T>; |
46 | |
47 | /// Treat the not current context as possibly current. The operation is safe |
48 | /// because the possibly current context is more restricted and not |
49 | /// guaranteed to be current. |
50 | fn treat_as_possibly_current(self) -> Self::PossiblyCurrentContext; |
51 | |
52 | /// Make [`Self::Surface`] on the calling thread producing the |
53 | /// [`Self::PossiblyCurrentContext`] indicating that the context could |
54 | /// be current on the theard. |
55 | /// |
56 | /// # Platform specific |
57 | /// |
58 | /// - **macOS: this will block if your main thread is blocked**; |
59 | /// - **Wayland:** this call may latch the underlying back buffer (will do |
60 | /// with mesa drivers), meaning that all resize operations will apply |
61 | /// after the next [`GlSurface::swap_buffers`]. |
62 | fn make_current<T: SurfaceTypeTrait>( |
63 | self, |
64 | surface: &Self::Surface<T>, |
65 | ) -> Result<Self::PossiblyCurrentContext>; |
66 | |
67 | /// The same as [`Self::make_current`], but provides a way to set read and |
68 | /// draw surfaces. |
69 | /// |
70 | /// # Api-specific: |
71 | /// |
72 | /// - **WGL/CGL:** not supported. |
73 | fn make_current_draw_read<T: SurfaceTypeTrait>( |
74 | self, |
75 | surface_draw: &Self::Surface<T>, |
76 | surface_read: &Self::Surface<T>, |
77 | ) -> Result<Self::PossiblyCurrentContext>; |
78 | } |
79 | |
80 | /// A trait to group common context operations. |
81 | pub trait PossiblyCurrentGlContext: Sealed { |
82 | /// The not current context type. |
83 | type NotCurrentContext: NotCurrentGlContext; |
84 | |
85 | /// The surface supported by the context. |
86 | type Surface<T: SurfaceTypeTrait>: GlSurface<T>; |
87 | |
88 | /// Returns `true` if this context is the current one in this thread. |
89 | fn is_current(&self) -> bool; |
90 | |
91 | /// Make the context not current to the current thread and returns a |
92 | /// [`Self::NotCurrentContext`] to indicate that the context is a not |
93 | /// current to allow sending it to the different thread. |
94 | /// |
95 | /// # Platform specific |
96 | /// |
97 | /// - **macOS: this will block if your main thread is blocked.** |
98 | fn make_not_current(self) -> Result<Self::NotCurrentContext>; |
99 | |
100 | /// Make [`Self::Surface`] current on the calling thread. |
101 | /// |
102 | /// # Platform specific |
103 | /// |
104 | /// - **macOS: this will block if your main thread is blocked.** |
105 | fn make_current<T: SurfaceTypeTrait>(&self, surface: &Self::Surface<T>) -> Result<()>; |
106 | |
107 | /// The same as [`Self::make_current`] but provides a way to set read and |
108 | /// draw surfaces explicitly. |
109 | /// |
110 | /// # Api-specific: |
111 | /// |
112 | /// - **CGL/WGL:** not supported. |
113 | fn make_current_draw_read<T: SurfaceTypeTrait>( |
114 | &self, |
115 | surface_draw: &Self::Surface<T>, |
116 | surface_read: &Self::Surface<T>, |
117 | ) -> Result<()>; |
118 | } |
119 | |
120 | /// A trait that provides raw context. |
121 | pub trait AsRawContext { |
122 | /// Get the raw context handle. |
123 | fn raw_context(&self) -> RawContext; |
124 | } |
125 | |
126 | /// The builder to help customizing context |
127 | #[derive (Default, Debug, Clone)] |
128 | pub struct ContextAttributesBuilder { |
129 | attributes: ContextAttributes, |
130 | } |
131 | |
132 | impl ContextAttributesBuilder { |
133 | /// Create new builder. |
134 | pub fn new() -> Self { |
135 | Default::default() |
136 | } |
137 | |
138 | /// Sets the *debug* flag for the OpenGL context. |
139 | /// |
140 | /// Debug contexts are usually slower, but give better error reporting. |
141 | /// This option is ignored when using [`Robustness::NoError`]. |
142 | /// |
143 | /// The default value for this flag is `false`. |
144 | pub fn with_debug(mut self, debug: bool) -> Self { |
145 | self.attributes.debug = debug; |
146 | self |
147 | } |
148 | |
149 | /// Share the display lists with the given context. |
150 | /// |
151 | /// To get sharing working it's recommended to use the same [`Config`] when |
152 | /// creating contexts that are going to be shared. |
153 | /// |
154 | /// # Platform-specific |
155 | /// |
156 | /// - **Wayland:** both contexts must use the same Wayland connection. |
157 | /// |
158 | /// [`Config`]: crate::config::Config |
159 | pub fn with_sharing(mut self, context: &impl AsRawContext) -> Self { |
160 | self.attributes.shared_context = Some(context.raw_context()); |
161 | self |
162 | } |
163 | |
164 | /// Sets the robustness of the OpenGL context. See the docs of |
165 | /// [`Robustness`]. |
166 | /// |
167 | /// The default is [`Robustness::NotRobust`], because this is what typically |
168 | /// expected when you create an OpenGL context. However for safety you |
169 | /// should consider [`Robustness::RobustLoseContextOnReset`]. |
170 | pub fn with_robustness(mut self, robustness: Robustness) -> Self { |
171 | self.attributes.robustness = robustness; |
172 | self |
173 | } |
174 | |
175 | /// The behavior when changing the current context. See the docs of |
176 | /// [`ReleaseBehavior`]. |
177 | /// |
178 | /// The default is [`ReleaseBehavior::Flush`]. |
179 | pub fn with_release_behavior(mut self, release_behavior: ReleaseBehavior) -> Self { |
180 | self.attributes.release_behavior = release_behavior; |
181 | self |
182 | } |
183 | |
184 | /// Set the desired OpenGL context profile. See the docs of [`GlProfile`]. |
185 | /// |
186 | /// By default the profile is unspecified. |
187 | /// |
188 | /// # Api-specific |
189 | /// |
190 | /// - **macOS:** not supported, the latest is picked automatically. |
191 | pub fn with_profile(mut self, profile: GlProfile) -> Self { |
192 | self.attributes.profile = Some(profile); |
193 | self |
194 | } |
195 | |
196 | /// Set the desired OpenGL context api. See the docs of [`ContextApi`]. |
197 | /// |
198 | /// By default the supported api will be picked. |
199 | pub fn with_context_api(mut self, api: ContextApi) -> Self { |
200 | self.attributes.api = Some(api); |
201 | self |
202 | } |
203 | |
204 | /// Build the context attributes. |
205 | /// |
206 | /// The `raw_window_handle` isn't required and here for WGL compatibility. |
207 | /// |
208 | /// # Api-specific |
209 | /// |
210 | /// - **WGL:** you **must** pass a `raw_window_handle` if you plan to use |
211 | /// this context with that window. |
212 | pub fn build(mut self, raw_window_handle: Option<RawWindowHandle>) -> ContextAttributes { |
213 | self.attributes.raw_window_handle = raw_window_handle; |
214 | self.attributes |
215 | } |
216 | } |
217 | |
218 | /// The attributes that are used to create a graphics context. |
219 | #[derive (Default, Debug, Clone)] |
220 | pub struct ContextAttributes { |
221 | pub(crate) release_behavior: ReleaseBehavior, |
222 | |
223 | pub(crate) debug: bool, |
224 | |
225 | pub(crate) robustness: Robustness, |
226 | |
227 | pub(crate) profile: Option<GlProfile>, |
228 | |
229 | pub(crate) api: Option<ContextApi>, |
230 | |
231 | pub(crate) shared_context: Option<RawContext>, |
232 | |
233 | pub(crate) raw_window_handle: Option<RawWindowHandle>, |
234 | } |
235 | |
236 | /// Specifies the tolerance of the OpenGL context to faults. If you accept |
237 | /// raw OpenGL commands and/or raw shader code from an untrusted source, you |
238 | /// should definitely care about this. |
239 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Default)] |
240 | pub enum Robustness { |
241 | /// Not everything is checked. Your application can crash if you do |
242 | /// something wrong with your shaders. |
243 | #[default] |
244 | NotRobust, |
245 | |
246 | /// The driver doesn't check anything. This option is very dangerous. |
247 | /// Please know what you're doing before using it. See the |
248 | /// `GL_KHR_no_error` extension. |
249 | /// |
250 | /// Since this option is purely an optimization, no error will be returned |
251 | /// if the backend doesn't support it. Instead it will automatically |
252 | /// fall back to [`Robustness::NotRobust`]. |
253 | NoError, |
254 | |
255 | /// Everything is checked to avoid any crash. The driver will attempt to |
256 | /// avoid any problem, but if a problem occurs the behavior is |
257 | /// implementation-defined. You are just guaranteed not to get a crash. |
258 | RobustNoResetNotification, |
259 | |
260 | /// Everything is checked to avoid any crash. If a problem occurs, the |
261 | /// context will enter a "context lost" state. It must then be |
262 | /// recreated. |
263 | RobustLoseContextOnReset, |
264 | } |
265 | |
266 | /// Describes the requested OpenGL context profiles. |
267 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
268 | pub enum GlProfile { |
269 | /// Include all the future-compatible functions and definitions. |
270 | /// |
271 | /// The requested OpenGL version with [`ContextApi`] should be at least 3.3. |
272 | Core, |
273 | /// Include all the immediate more functions and definitions. |
274 | /// |
275 | /// Use it only when it's really needed, otherwise use [`Self::Core`]. |
276 | Compatibility, |
277 | } |
278 | |
279 | /// The rendering Api context should support. |
280 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
281 | pub enum ContextApi { |
282 | /// OpenGL Api version that should be used by the context. |
283 | /// |
284 | /// When using `None` as `Version` any OpenGL context will be picked, |
285 | /// however when the [`GlProfile::Core`] is used at least 3.3 will be |
286 | /// requested. |
287 | OpenGl(Option<Version>), |
288 | |
289 | /// OpenGL Api version that should be used by the context. |
290 | /// |
291 | /// When using `None` as `Version` the latest **known** major version is |
292 | /// picked. Versions that are higher than what was picked automatically |
293 | /// could still be supported. |
294 | Gles(Option<Version>), |
295 | } |
296 | |
297 | #[cfg (any(egl_backend, glx_backend, wgl_backend))] |
298 | impl ContextApi { |
299 | pub(crate) fn version(&self) -> Option<Version> { |
300 | match self { |
301 | Self::OpenGl(version: &Option) => *version, |
302 | Self::Gles(version: &Option) => *version, |
303 | _ => None, |
304 | } |
305 | } |
306 | } |
307 | |
308 | impl Default for ContextApi { |
309 | fn default() -> Self { |
310 | Self::OpenGl(None) |
311 | } |
312 | } |
313 | |
314 | /// The version used to index the Api. |
315 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] |
316 | pub struct Version { |
317 | /// Major version of the Api. |
318 | pub major: u8, |
319 | /// Minor version of the Api. |
320 | pub minor: u8, |
321 | } |
322 | |
323 | impl Version { |
324 | /// Create new version with the given `major` and `minor` values. |
325 | pub const fn new(major: u8, minor: u8) -> Self { |
326 | Self { major, minor } |
327 | } |
328 | } |
329 | |
330 | /// The behavior of the driver when you change the current context. |
331 | #[derive (Debug, Copy, Clone, PartialEq, Eq, Default)] |
332 | pub enum ReleaseBehavior { |
333 | /// Doesn't do anything. Most notably doesn't flush. Not supported by all |
334 | /// drivers. |
335 | /// |
336 | /// # Api-specific |
337 | /// |
338 | /// - **macOS:** not supported, [`Self::Flush`] is always used. |
339 | None, |
340 | |
341 | /// Flushes the context that was previously current as if `glFlush` was |
342 | /// called. This is the default behavior. |
343 | #[default] |
344 | Flush, |
345 | } |
346 | |
347 | /// A context that is known to be not current on the current thread. |
348 | /// |
349 | /// This type is a safe wrapper around the context to indicate that it could be |
350 | /// `Send` to the different thread, since the context must be not current before |
351 | /// doing so. |
352 | /// |
353 | /// ```no_run |
354 | /// fn test_send<T: Send>() {} |
355 | /// test_send::<glutin::context::NotCurrentContext>(); |
356 | /// ``` |
357 | /// However it's not `Sync`. |
358 | /// ```compile_fail |
359 | /// fn test_sync<T: Sync>() {} |
360 | /// test_sync::<glutin::context::NotCurrentContext>(); |
361 | /// ``` |
362 | #[derive (Debug)] |
363 | pub enum NotCurrentContext { |
364 | /// The EGL context. |
365 | #[cfg (egl_backend)] |
366 | Egl(NotCurrentEglContext), |
367 | |
368 | /// The GLX context. |
369 | #[cfg (glx_backend)] |
370 | Glx(NotCurrentGlxContext), |
371 | |
372 | /// The WGL context. |
373 | #[cfg (wgl_backend)] |
374 | Wgl(NotCurrentWglContext), |
375 | |
376 | /// The CGL context. |
377 | #[cfg (cgl_backend)] |
378 | Cgl(NotCurrentCglContext), |
379 | } |
380 | |
381 | impl NotCurrentGlContext for NotCurrentContext { |
382 | type PossiblyCurrentContext = PossiblyCurrentContext; |
383 | type Surface<T: SurfaceTypeTrait> = Surface<T>; |
384 | |
385 | fn treat_as_possibly_current(self) -> Self::PossiblyCurrentContext { |
386 | gl_api_dispatch!(self; Self(context) => context.treat_as_possibly_current(); as PossiblyCurrentContext) |
387 | } |
388 | |
389 | fn make_current<T: SurfaceTypeTrait>( |
390 | self, |
391 | surface: &Self::Surface<T>, |
392 | ) -> Result<Self::PossiblyCurrentContext> { |
393 | match (self, surface) { |
394 | #[cfg (egl_backend)] |
395 | (Self::Egl(context), Surface::Egl(surface)) => { |
396 | Ok(PossiblyCurrentContext::Egl(context.make_current(surface)?)) |
397 | }, |
398 | #[cfg (glx_backend)] |
399 | (Self::Glx(context), Surface::Glx(surface)) => { |
400 | Ok(PossiblyCurrentContext::Glx(context.make_current(surface)?)) |
401 | }, |
402 | #[cfg (wgl_backend)] |
403 | (Self::Wgl(context), Surface::Wgl(surface)) => { |
404 | Ok(PossiblyCurrentContext::Wgl(context.make_current(surface)?)) |
405 | }, |
406 | #[cfg (cgl_backend)] |
407 | (Self::Cgl(context), Surface::Cgl(surface)) => { |
408 | Ok(PossiblyCurrentContext::Cgl(context.make_current(surface)?)) |
409 | }, |
410 | _ => unreachable!(), |
411 | } |
412 | } |
413 | |
414 | fn make_current_draw_read<T: SurfaceTypeTrait>( |
415 | self, |
416 | surface_draw: &Self::Surface<T>, |
417 | surface_read: &Self::Surface<T>, |
418 | ) -> Result<Self::PossiblyCurrentContext> { |
419 | match (self, surface_draw, surface_read) { |
420 | #[cfg (egl_backend)] |
421 | (Self::Egl(context), Surface::Egl(draw), Surface::Egl(read)) => { |
422 | Ok(PossiblyCurrentContext::Egl(context.make_current_draw_read(draw, read)?)) |
423 | }, |
424 | #[cfg (glx_backend)] |
425 | (Self::Glx(context), Surface::Glx(draw), Surface::Glx(read)) => { |
426 | Ok(PossiblyCurrentContext::Glx(context.make_current_draw_read(draw, read)?)) |
427 | }, |
428 | #[cfg (wgl_backend)] |
429 | (Self::Wgl(context), Surface::Wgl(draw), Surface::Wgl(read)) => { |
430 | Ok(PossiblyCurrentContext::Wgl(context.make_current_draw_read(draw, read)?)) |
431 | }, |
432 | #[cfg (cgl_backend)] |
433 | (Self::Cgl(context), Surface::Cgl(draw), Surface::Cgl(read)) => { |
434 | Ok(PossiblyCurrentContext::Cgl(context.make_current_draw_read(draw, read)?)) |
435 | }, |
436 | _ => unreachable!(), |
437 | } |
438 | } |
439 | } |
440 | |
441 | impl GlContext for NotCurrentContext { |
442 | fn context_api(&self) -> ContextApi { |
443 | gl_api_dispatch!(self; Self(context) => context.context_api()) |
444 | } |
445 | } |
446 | |
447 | impl GetGlConfig for NotCurrentContext { |
448 | type Target = Config; |
449 | |
450 | fn config(&self) -> Self::Target { |
451 | gl_api_dispatch!(self; Self(context) => context.config(); as Config) |
452 | } |
453 | } |
454 | |
455 | impl GetGlDisplay for NotCurrentContext { |
456 | type Target = Display; |
457 | |
458 | fn display(&self) -> Self::Target { |
459 | gl_api_dispatch!(self; Self(context) => context.display(); as Display) |
460 | } |
461 | } |
462 | |
463 | impl AsRawContext for NotCurrentContext { |
464 | fn raw_context(&self) -> RawContext { |
465 | gl_api_dispatch!(self; Self(context) => context.raw_context()) |
466 | } |
467 | } |
468 | |
469 | impl Sealed for NotCurrentContext {} |
470 | |
471 | /// A context that is possibly current on the current thread. |
472 | /// |
473 | /// The context that could be current on the current thread can neither be |
474 | /// [`Send`] nor [`Sync`]. In case you need to use it on a different thread |
475 | /// [make it not current]. |
476 | /// ```compile_fail |
477 | /// fn test_send<T: Send>() {} |
478 | /// test_send::<glutin::context::PossiblyCurrentContext>(); |
479 | /// ``` |
480 | /// |
481 | /// ```compile_fail |
482 | /// fn test_sync<T: Sync>() {} |
483 | /// test_sync::<glutin::context::PossiblyCurrentContext>(); |
484 | /// ``` |
485 | /// |
486 | /// [make it not current]: crate::context::PossiblyCurrentGlContext::make_not_current |
487 | #[derive (Debug)] |
488 | pub enum PossiblyCurrentContext { |
489 | /// The EGL context. |
490 | #[cfg (egl_backend)] |
491 | Egl(PossiblyCurrentEglContext), |
492 | |
493 | /// The GLX context. |
494 | #[cfg (glx_backend)] |
495 | Glx(PossiblyCurrentGlxContext), |
496 | |
497 | /// The WGL context. |
498 | #[cfg (wgl_backend)] |
499 | Wgl(PossiblyCurrentWglContext), |
500 | |
501 | /// The CGL context. |
502 | #[cfg (cgl_backend)] |
503 | Cgl(PossiblyCurrentCglContext), |
504 | } |
505 | |
506 | impl PossiblyCurrentGlContext for PossiblyCurrentContext { |
507 | type NotCurrentContext = NotCurrentContext; |
508 | type Surface<T: SurfaceTypeTrait> = Surface<T>; |
509 | |
510 | fn is_current(&self) -> bool { |
511 | gl_api_dispatch!(self; Self(context) => context.is_current()) |
512 | } |
513 | |
514 | fn make_not_current(self) -> Result<Self::NotCurrentContext> { |
515 | Ok( |
516 | gl_api_dispatch!(self; Self(context) => context.make_not_current()?; as NotCurrentContext), |
517 | ) |
518 | } |
519 | |
520 | fn make_current<T: SurfaceTypeTrait>(&self, surface: &Self::Surface<T>) -> Result<()> { |
521 | match (self, surface) { |
522 | #[cfg (egl_backend)] |
523 | (Self::Egl(context), Surface::Egl(surface)) => context.make_current(surface), |
524 | #[cfg (glx_backend)] |
525 | (Self::Glx(context), Surface::Glx(surface)) => context.make_current(surface), |
526 | #[cfg (wgl_backend)] |
527 | (Self::Wgl(context), Surface::Wgl(surface)) => context.make_current(surface), |
528 | #[cfg (cgl_backend)] |
529 | (Self::Cgl(context), Surface::Cgl(surface)) => context.make_current(surface), |
530 | _ => unreachable!(), |
531 | } |
532 | } |
533 | |
534 | fn make_current_draw_read<T: SurfaceTypeTrait>( |
535 | &self, |
536 | surface_draw: &Self::Surface<T>, |
537 | surface_read: &Self::Surface<T>, |
538 | ) -> Result<()> { |
539 | match (self, surface_draw, surface_read) { |
540 | #[cfg (egl_backend)] |
541 | (Self::Egl(context), Surface::Egl(draw), Surface::Egl(read)) => { |
542 | context.make_current_draw_read(draw, read) |
543 | }, |
544 | #[cfg (glx_backend)] |
545 | (Self::Glx(context), Surface::Glx(draw), Surface::Glx(read)) => { |
546 | context.make_current_draw_read(draw, read) |
547 | }, |
548 | #[cfg (wgl_backend)] |
549 | (Self::Wgl(context), Surface::Wgl(draw), Surface::Wgl(read)) => { |
550 | context.make_current_draw_read(draw, read) |
551 | }, |
552 | #[cfg (cgl_backend)] |
553 | (Self::Cgl(context), Surface::Cgl(draw), Surface::Cgl(read)) => { |
554 | context.make_current_draw_read(draw, read) |
555 | }, |
556 | _ => unreachable!(), |
557 | } |
558 | } |
559 | } |
560 | |
561 | impl GlContext for PossiblyCurrentContext { |
562 | fn context_api(&self) -> ContextApi { |
563 | gl_api_dispatch!(self; Self(context) => context.context_api()) |
564 | } |
565 | } |
566 | |
567 | impl GetGlConfig for PossiblyCurrentContext { |
568 | type Target = Config; |
569 | |
570 | fn config(&self) -> Self::Target { |
571 | gl_api_dispatch!(self; Self(context) => context.config(); as Config) |
572 | } |
573 | } |
574 | |
575 | impl GetGlDisplay for PossiblyCurrentContext { |
576 | type Target = Display; |
577 | |
578 | fn display(&self) -> Self::Target { |
579 | gl_api_dispatch!(self; Self(context) => context.display(); as Display) |
580 | } |
581 | } |
582 | |
583 | impl AsRawContext for PossiblyCurrentContext { |
584 | fn raw_context(&self) -> RawContext { |
585 | gl_api_dispatch!(self; Self(context) => context.raw_context()) |
586 | } |
587 | } |
588 | |
589 | impl Sealed for PossiblyCurrentContext {} |
590 | |
591 | /// Raw context. |
592 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
593 | pub enum RawContext { |
594 | /// Raw EGL context. |
595 | #[cfg (egl_backend)] |
596 | Egl(*const ffi::c_void), |
597 | |
598 | /// Raw GLX context. |
599 | #[cfg (glx_backend)] |
600 | Glx(*const ffi::c_void), |
601 | |
602 | /// HGLRC pointer. |
603 | #[cfg (wgl_backend)] |
604 | Wgl(*const ffi::c_void), |
605 | |
606 | /// Pointer to NSOpenGLContext. |
607 | #[cfg (cgl_backend)] |
608 | Cgl(*const ffi::c_void), |
609 | } |
610 | |
611 | /// Pick `GlProfile` and `Version` based on the provided params. |
612 | #[cfg (any(egl_backend, glx_backend, wgl_backend))] |
613 | pub(crate) fn pick_profile( |
614 | profile: Option<GlProfile>, |
615 | version: Option<Version>, |
616 | ) -> (GlProfile, Version) { |
617 | match (profile, version) { |
618 | (Some(GlProfile::Core), Some(version: Version)) => (GlProfile::Core, version), |
619 | (Some(GlProfile::Compatibility), Some(version: Version)) => (GlProfile::Compatibility, version), |
620 | (None, Some(version: Version)) if version >= Version::new(major:3, minor:3) => (GlProfile::Core, version), |
621 | (None, Some(version: Version)) => (GlProfile::Compatibility, version), |
622 | (Some(GlProfile::Core), None) => (GlProfile::Core, Version::new(major:3, minor:3)), |
623 | (Some(GlProfile::Compatibility), None) => (GlProfile::Compatibility, Version::new(major:2, minor:1)), |
624 | (None, None) => (GlProfile::Core, Version::new(major:3, minor:3)), |
625 | } |
626 | } |
627 | |