1#![allow(unreachable_patterns)]
4use std::ffi;
5
6use raw_window_handle::RawWindowHandle;
7
8use crate::config::{Config, GetGlConfig};
9use crate::display::{Display, GetGlDisplay};
10use crate::error::Result;
11use crate::private::{gl_api_dispatch, Sealed};
12use crate::surface::{GlSurface, Surface, SurfaceTypeTrait};
13
14#[cfg(cgl_backend)]
15use crate::api::cgl::context::{
16 NotCurrentContext as NotCurrentCglContext, PossiblyCurrentContext as PossiblyCurrentCglContext,
17};
18#[cfg(egl_backend)]
19use crate::api::egl::context::{
20 NotCurrentContext as NotCurrentEglContext, PossiblyCurrentContext as PossiblyCurrentEglContext,
21};
22#[cfg(glx_backend)]
23use crate::api::glx::context::{
24 NotCurrentContext as NotCurrentGlxContext, PossiblyCurrentContext as PossiblyCurrentGlxContext,
25};
26#[cfg(wgl_backend)]
27use crate::api::wgl::context::{
28 NotCurrentContext as NotCurrentWglContext, PossiblyCurrentContext as PossiblyCurrentWglContext,
29};
30
31pub trait GlContext: Sealed {
33 fn context_api(&self) -> ContextApi;
37
38 fn priority(&self) -> Priority;
40}
41
42pub trait NotCurrentGlContext: Sealed {
44 type PossiblyCurrentContext: PossiblyCurrentGlContext;
46
47 type Surface<T: SurfaceTypeTrait>: GlSurface<T>;
49
50 fn treat_as_possibly_current(self) -> Self::PossiblyCurrentContext;
54
55 fn make_current<T: SurfaceTypeTrait>(
66 self,
67 surface: &Self::Surface<T>,
68 ) -> Result<Self::PossiblyCurrentContext>;
69
70 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
83pub trait PossiblyCurrentGlContext: Sealed {
85 type NotCurrentContext: NotCurrentGlContext;
87
88 type Surface<T: SurfaceTypeTrait>: GlSurface<T>;
90
91 fn is_current(&self) -> bool;
93
94 fn make_not_current(self) -> Result<Self::NotCurrentContext>;
102
103 fn make_not_current_in_place(&self) -> Result<()>;
107
108 fn make_current<T: SurfaceTypeTrait>(&self, surface: &Self::Surface<T>) -> Result<()>;
114
115 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
128pub trait AsRawContext {
130 fn raw_context(&self) -> RawContext;
132}
133
134#[derive(Default, Debug, Clone)]
136pub struct ContextAttributesBuilder {
137 attributes: ContextAttributes,
138}
139
140impl ContextAttributesBuilder {
141 pub fn new() -> Self {
143 Default::default()
144 }
145
146 pub fn with_debug(mut self, debug: bool) -> Self {
153 self.attributes.debug = debug;
154 self
155 }
156
157 pub fn with_sharing(mut self, context: &impl AsRawContext) -> Self {
168 self.attributes.shared_context = Some(context.raw_context());
169 self
170 }
171
172 pub fn with_robustness(mut self, robustness: Robustness) -> Self {
179 self.attributes.robustness = robustness;
180 self
181 }
182
183 pub fn with_release_behavior(mut self, release_behavior: ReleaseBehavior) -> Self {
188 self.attributes.release_behavior = release_behavior;
189 self
190 }
191
192 pub fn with_profile(mut self, profile: GlProfile) -> Self {
200 self.attributes.profile = Some(profile);
201 self
202 }
203
204 pub fn with_context_api(mut self, api: ContextApi) -> Self {
208 self.attributes.api = Some(api);
209 self
210 }
211
212 pub fn with_priority(mut self, priority: Priority) -> Self {
226 self.attributes.priority = Some(priority);
227 self
228 }
229
230 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#[derive(Default, Debug, Clone)]
246pub 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#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
268pub enum Robustness {
269 #[default]
272 NotRobust,
273
274 NoError,
282
283 RobustNoResetNotification,
287
288 RobustLoseContextOnReset,
292}
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq)]
296pub enum GlProfile {
297 Core,
301 Compatibility,
305}
306
307#[derive(Debug, Clone, Copy, PartialEq, Eq)]
309pub enum ContextApi {
310 OpenGl(Option<Version>),
316
317 Gles(Option<Version>),
323}
324
325#[cfg(any(egl_backend, glx_backend, wgl_backend))]
326impl ContextApi {
327 pub(crate) fn version(&self) -> Option<Version> {
328 match self {
329 Self::OpenGl(version) => *version,
330 Self::Gles(version) => *version,
331 _ => None,
332 }
333 }
334}
335
336impl Default for ContextApi {
337 fn default() -> Self {
338 Self::OpenGl(None)
339 }
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
344pub struct Version {
345 pub major: u8,
347 pub minor: u8,
349}
350
351impl Version {
352 pub const fn new(major: u8, minor: u8) -> Self {
354 Self { major, minor }
355 }
356}
357
358#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
360pub enum ReleaseBehavior {
361 None,
368
369 #[default]
372 Flush,
373}
374
375#[derive(Debug)]
391pub enum NotCurrentContext {
392 #[cfg(egl_backend)]
394 Egl(NotCurrentEglContext),
395
396 #[cfg(glx_backend)]
398 Glx(NotCurrentGlxContext),
399
400 #[cfg(wgl_backend)]
402 Wgl(NotCurrentWglContext),
403
404 #[cfg(cgl_backend)]
406 Cgl(NotCurrentCglContext),
407}
408
409impl 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
469impl 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
479impl 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
487impl 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
495impl AsRawContext for NotCurrentContext {
496 fn raw_context(&self) -> RawContext {
497 gl_api_dispatch!(self; Self(context) => context.raw_context())
498 }
499}
500
501impl Sealed for NotCurrentContext {}
502
503#[derive(Debug)]
520pub enum PossiblyCurrentContext {
521 #[cfg(egl_backend)]
523 Egl(PossiblyCurrentEglContext),
524
525 #[cfg(glx_backend)]
527 Glx(PossiblyCurrentGlxContext),
528
529 #[cfg(wgl_backend)]
531 Wgl(PossiblyCurrentWglContext),
532
533 #[cfg(cgl_backend)]
535 Cgl(PossiblyCurrentCglContext),
536}
537
538impl 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
597impl 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
607impl 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
615impl 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
623impl AsRawContext for PossiblyCurrentContext {
624 fn raw_context(&self) -> RawContext {
625 gl_api_dispatch!(self; Self(context) => context.raw_context())
626 }
627}
628
629impl Sealed for PossiblyCurrentContext {}
630
631#[derive(Debug, Clone, Copy, PartialEq, Eq)]
633pub enum RawContext {
634 #[cfg(egl_backend)]
636 Egl(*const ffi::c_void),
637
638 #[cfg(glx_backend)]
640 Glx(*const ffi::c_void),
641
642 #[cfg(wgl_backend)]
644 Wgl(*const ffi::c_void),
645
646 #[cfg(cgl_backend)]
648 Cgl(*const ffi::c_void),
649}
650
651#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
653pub enum Priority {
654 Low,
657 #[default]
659 Medium,
660 High,
662 Realtime,
668}
669
670#[cfg(any(egl_backend, glx_backend, wgl_backend))]
672pub(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)) => (GlProfile::Core, version),
678 (Some(GlProfile::Compatibility), Some(version)) => (GlProfile::Compatibility, version),
679 (None, Some(version)) if version >= Version::new(3, 3) => (GlProfile::Core, version),
680 (None, Some(version)) => (GlProfile::Compatibility, version),
681 (Some(GlProfile::Core), None) => (GlProfile::Core, Version::new(3, 3)),
682 (Some(GlProfile::Compatibility), None) => (GlProfile::Compatibility, Version::new(2, 1)),
683 (None, None) => (GlProfile::Core, Version::new(3, 3)),
684 }
685}