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> {}