azul_glutin/
context.rs

1use super::*;
2
3use std::marker::PhantomData;
4use winit::event_loop::EventLoopWindowTarget;
5
6/// Represents an OpenGL [`Context`].
7///
8/// A [`Context`] is normally associated with a single Window, however
9/// [`Context`]s can be *shared* between multiple windows or be headless.
10///
11/// If a [`Context`] is backed by a window, it will be wrapped by either
12/// [`RawContext<T>`] or [`WindowedContext<T>`].
13///
14/// # Example
15///
16/// ```no_run
17/// # fn main() {
18/// # let el = glutin::event_loop::EventLoop::new();
19/// # let wb = glutin::window::WindowBuilder::new();
20/// # let some_context = glutin::ContextBuilder::new()
21/// #    .build_windowed(wb, &el)
22/// #    .unwrap();
23/// let cb = glutin::ContextBuilder::new()
24///     .with_vsync(true)
25///     .with_multisampling(8)
26///     .with_shared_lists(some_context.context());
27/// # }
28/// ```
29///
30/// [`WindowedContext<T>`]: type.WindowedContext.html
31/// [`RawContext<T>`]: type.RawContext.html
32/// [`Context`]: struct.Context.html
33#[derive(Debug)]
34pub struct Context<T: ContextCurrentState> {
35    pub(crate) context: platform_impl::Context,
36    pub(crate) phantom: PhantomData<T>,
37}
38
39impl<T: ContextCurrentState> Context<T> {
40    /// See [`ContextWrapper::make_current`].
41    ///
42    /// [`ContextWrapper::make_current`]:
43    /// struct.ContextWrapper.html#method.make_current
44    pub unsafe fn make_current(self) -> Result<Context<PossiblyCurrent>, (Self, ContextError)> {
45        match self.context.make_current() {
46            Ok(()) => Ok(Context { context: self.context, phantom: PhantomData }),
47            Err(err) => Err((Context { context: self.context, phantom: PhantomData }, err)),
48        }
49    }
50
51    /// See [`ContextWrapper::make_not_current`].
52    ///
53    /// [`ContextWrapper::make_not_current`]:
54    /// struct.ContextWrapper.html#method.make_not_current
55    pub unsafe fn make_not_current(self) -> Result<Context<NotCurrent>, (Self, ContextError)> {
56        match self.context.make_not_current() {
57            Ok(()) => Ok(Context { context: self.context, phantom: PhantomData }),
58            Err(err) => Err((Context { context: self.context, phantom: PhantomData }, err)),
59        }
60    }
61
62    /// See [`ContextWrapper::treat_as_not_current`].
63    ///
64    /// [`ContextWrapper::treat_as_not_current`]:
65    /// struct.ContextWrapper.html#method.treat_as_not_current
66    pub unsafe fn treat_as_not_current(self) -> Context<NotCurrent> {
67        Context { context: self.context, phantom: PhantomData }
68    }
69
70    /// See [`ContextWrapper::treat_as_current`].
71    ///
72    /// [`ContextWrapper::treat_as_current`]:
73    /// struct.ContextWrapper.html#method.treat_as_current
74    pub unsafe fn treat_as_current(self) -> Context<PossiblyCurrent> {
75        Context { context: self.context, phantom: PhantomData }
76    }
77
78    /// See [`ContextWrapper::is_current`].
79    ///
80    /// [`ContextWrapper::is_current`]:
81    /// struct.ContextWrapper.html#method.is_current
82    pub fn is_current(&self) -> bool {
83        self.context.is_current()
84    }
85
86    /// See [`ContextWrapper::get_api`].
87    ///
88    /// [`ContextWrapper::get_api`]: struct.ContextWrapper.html#method.get_api
89    pub fn get_api(&self) -> Api {
90        self.context.get_api()
91    }
92}
93
94impl Context<PossiblyCurrent> {
95    /// See [`ContextWrapper::get_proc_address`].
96    ///
97    /// [`ContextWrapper::get_proc_address`]:
98    /// struct.ContextWrapper.html#method.get_proc_address
99    pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void {
100        self.context.get_proc_address(addr)
101    }
102}
103
104impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> {
105    /// Builds the given GL context.
106    ///
107    /// When on a unix operating system, prefer [`build_surfaceless`]. If both
108    /// [`build_surfaceless`] and `build_headless` fail, try using a hidden
109    /// window, or [`build_osmesa`]. Please note that if you choose to use a
110    /// hidden window, you must still handle the events it generates on the
111    /// events loop.
112    ///
113    /// Errors can occur in two scenarios:
114    ///  - If the window could not be created (via permission denied,
115    ///  incompatible system, out of memory, etc.). This should be very rare.
116    ///  - If the OpenGL [`Context`] could not be created. This generally
117    ///    happens
118    ///  because the underlying platform doesn't support a requested feature.
119    ///
120    /// [`Context`]: struct.Context.html
121    #[cfg_attr(
122        not(any(
123            target_os = "linux",
124            target_os = "dragonfly",
125            target_os = "freebsd",
126            target_os = "netbsd",
127            target_os = "openbsd",
128        )),
129        doc = "\
130    [`build_surfaceless`]: platform/index.html\n\
131    [`build_osmesa`]: platform/index.html\
132    "
133    )]
134    #[cfg_attr(
135        any(
136            target_os = "linux",
137            target_os = "dragonfly",
138            target_os = "freebsd",
139            target_os = "netbsd",
140            target_os = "openbsd",
141        ),
142        doc = "\
143    [`build_surfaceless`]: platform/unix/trait.HeadlessContextExt.html#tymethod.build_surfaceless\n\
144    [`build_osmesa`]: platform/unix/trait.HeadlessContextExt.html#tymethod.build_osmesa\
145    "
146    )]
147    pub fn build_headless<TE>(
148        self,
149        el: &EventLoopWindowTarget<TE>,
150        size: dpi::PhysicalSize<u32>,
151    ) -> Result<Context<NotCurrent>, CreationError> {
152        let ContextBuilder { pf_reqs, gl_attr } = self;
153        let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
154        platform_impl::Context::new_headless(el, &pf_reqs, &gl_attr, size)
155            .map(|context| Context { context, phantom: PhantomData })
156    }
157}
158
159// This is nightly only:
160// impl !Send for Context<PossiblyCurrent> {}
161// impl !Sync for Context<PossiblyCurrent> {}
162//
163// Instead we add a phantom type to PossiblyCurrent
164
165/// A type that [`Context`]s which might possibly be currently current on some
166/// thread take as a generic.
167///
168/// See [`ContextWrapper::make_current`] for more details.
169///
170/// [`ContextWrapper::make_current`]:
171/// struct.ContextWrapper.html#method.make_current
172/// [`Context`]: struct.Context.html
173#[derive(Debug, Clone, Copy)]
174pub struct PossiblyCurrent {
175    phantom: PhantomData<*mut ()>,
176}
177
178/// A type that [`Context`]s which are not currently current on any thread take
179/// as a generic.
180///
181/// See [`ContextWrapper::make_current`] for more details.
182///
183/// [`ContextWrapper::make_current`]:
184/// struct.ContextWrapper.html#method.make_current
185/// [`Context`]: struct.Context.html
186#[derive(Debug, Clone, Copy)]
187pub enum NotCurrent {}
188
189/// A trait implemented on both [`NotCurrent`] and
190/// [`PossiblyCurrent`].
191///
192/// [`NotCurrent`]: enum.NotCurrent.html
193/// [`PossiblyCurrent`]: struct.PossiblyCurrent.html
194pub trait ContextCurrentState: std::fmt::Debug + Clone {}
195
196impl ContextCurrentState for PossiblyCurrent {}
197impl ContextCurrentState for NotCurrent {}
198
199trait FailToCompileIfNotSendSync
200where
201    Self: Send + Sync,
202{
203}
204impl FailToCompileIfNotSendSync for Context<NotCurrent> {}