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