1 use super::*;
2 
3 use std::marker::PhantomData;
4 use winit::event_loop::EventLoopWindowTarget;
5 use winit::window::{Window, WindowBuilder};
6 
7 /// Represents an OpenGL [`Context`] and the [`Window`] with which it is
8 /// associated.
9 ///
10 /// Please see [`ContextWrapper<T, Window>`].
11 ///
12 /// # Example
13 ///
14 /// ```no_run
15 /// # fn main() {
16 /// let mut el = glutin::event_loop::EventLoop::new();
17 /// let wb = glutin::window::WindowBuilder::new();
18 /// let windowed_context = glutin::ContextBuilder::new()
19 ///     .build_windowed(wb, &el)
20 ///     .unwrap();
21 ///
22 /// let windowed_context = unsafe { windowed_context.make_current().unwrap() };
23 /// # }
24 /// ```
25 ///
26 /// [`ContextWrapper<T, Window>`]: struct.ContextWrapper.html
27 /// [`Window`]: struct.Window.html
28 /// [`Context`]: struct.Context.html
29 pub type WindowedContext<T> = ContextWrapper<T, Window>;
30 
31 /// Represents an OpenGL [`Context`] which has an underlying window that is
32 /// stored separately.
33 ///
34 /// This type can only be created via one of three ways:
35 ///
36 ///  * [`platform::unix::RawContextExt`]
37 ///  * [`platform::windows::RawContextExt`]
38 ///  * [`WindowedContext<T>::split`]
39 ///
40 /// Please see [`ContextWrapper<T, ()>`].
41 ///
42 /// [`ContextWrapper<T, ()>`]: struct.ContextWrapper.html
43 /// [`WindowedContext<T>::split`]: type.WindowedContext.html#method.split
44 /// [`Context`]: struct.Context.html
45 #[cfg_attr(
46     target_os = "windows",
47     doc = "\
48 [`platform::windows::RawContextExt`]: os/windows/enum.RawHandle.html
49 "
50 )]
51 #[cfg_attr(
52     not(target_os = "windows",),
53     doc = "\
54 [`platform::windows::RawContextExt`]: os/index.html
55 "
56 )]
57 #[cfg_attr(
58     not(any(
59         target_os = "linux",
60         target_os = "dragonfly",
61         target_os = "freebsd",
62         target_os = "netbsd",
63         target_os = "openbsd",
64     )),
65     doc = "\
66 [`platform::unix::RawContextExt`]: os/index.html
67 "
68 )]
69 #[cfg_attr(
70     any(
71         target_os = "linux",
72         target_os = "dragonfly",
73         target_os = "freebsd",
74         target_os = "netbsd",
75         target_os = "openbsd",
76     ),
77     doc = "\
78 [`platform::unix::RawContextExt`]: os/unix/enum.RawHandle.html
79 "
80 )]
81 pub type RawContext<T> = ContextWrapper<T, ()>;
82 
83 /// A context which has an underlying window, which may or may not be stored
84 /// separately.
85 ///
86 /// If the window is stored separately, it is a [`RawContext<T>`]. Otherwise,
87 /// it is a [`WindowedContext<T>`].
88 ///
89 /// [`WindowedContext<T>`]: type.WindowedContext.html
90 /// [`RawContext<T>`]: type.RawContext.html
91 /// [`Context`]: struct.Context.html
92 #[derive(Debug)]
93 pub struct ContextWrapper<T: ContextCurrentState, W> {
94     pub(crate) context: Context<T>,
95     pub(crate) window: W,
96 }
97 
98 impl<T: ContextCurrentState> WindowedContext<T> {
99     /// Borrow the inner `W`.
window(&self) -> &Window100     pub fn window(&self) -> &Window {
101         &self.window
102     }
103 
104     /// Split the [`Window`] apart from the OpenGL [`Context`]. Should only be
105     /// used when intending to transfer the [`RawContext<T>`] to another
106     /// thread.
107     ///
108     /// Unsaftey:
109     ///   - The OpenGL [`Context`] must be dropped before the [`Window`].
110     ///
111     /// [`RawContext<T>`]: type.RawContext.html
112     /// [`Window`]: struct.Window.html
113     /// [`Context`]: struct.Context.html
split(self) -> (RawContext<T>, Window)114     pub unsafe fn split(self) -> (RawContext<T>, Window) {
115         (
116             RawContext {
117                 context: self.context,
118                 window: (),
119             },
120             self.window,
121         )
122     }
123 }
124 
125 impl<W> ContextWrapper<PossiblyCurrent, W> {
126     /// Swaps the buffers in case of double or triple buffering.
127     ///
128     /// You should call this function every time you have finished rendering, or
129     /// the image may not be displayed on the screen.
130     ///
131     /// **Warning**: if you enabled vsync, this function will block until the
132     /// next time the screen is refreshed. However drivers can choose to
133     /// override your vsync settings, which means that you can't know in
134     /// advance whether `swap_buffers` will block or not.
swap_buffers(&self) -> Result<(), ContextError>135     pub fn swap_buffers(&self) -> Result<(), ContextError> {
136         self.context.context.swap_buffers()
137     }
138 
139     /// Swaps the buffers in case of double or triple buffering using specified
140     /// damage rects.
141     ///
142     /// You should call this function every time you have finished rendering, or
143     /// the image may not be displayed on the screen.
144     ///
145     /// **Warning**: if you enabled vsync, this function will block until the
146     /// next time the screen is refreshed. However drivers can choose to
147     /// override your vsync settings, which means that you can't know in
148     /// advance whether `swap_buffers` will block or not.
swap_buffers_with_damage( &self, rects: &[Rect], ) -> Result<(), ContextError>149     pub fn swap_buffers_with_damage(
150         &self,
151         rects: &[Rect],
152     ) -> Result<(), ContextError> {
153         self.context.context.swap_buffers_with_damage(rects)
154     }
155 
156     /// Returns whether or not swap_buffer_with_damage is available. If this
157     /// function returns false, any call to swap_buffers_with_damage will
158     /// return an error.
swap_buffers_with_damage_supported(&self) -> bool159     pub fn swap_buffers_with_damage_supported(&self) -> bool {
160         self.context.context.swap_buffers_with_damage_supported()
161     }
162 
163     /// Returns the pixel format of the main framebuffer of the context.
get_pixel_format(&self) -> PixelFormat164     pub fn get_pixel_format(&self) -> PixelFormat {
165         self.context.context.get_pixel_format()
166     }
167 
168     /// Resize the context.
169     ///
170     /// Some platforms (macOS, Wayland) require being manually updated when
171     /// their window or surface is resized.
172     ///
173     /// The easiest way of doing this is to take every [`Resized`] window event
174     /// that is received with a [`LogicalSize`] and convert it to a
175     /// [`PhysicalSize`] and pass it into this function.
176     ///
177     /// [`LogicalSize`]: dpi/struct.LogicalSize.html
178     /// [`PhysicalSize`]: dpi/struct.PhysicalSize.html
179     /// [`Resized`]: event/enum.WindowEvent.html#variant.Resized
resize(&self, size: dpi::PhysicalSize<u32>)180     pub fn resize(&self, size: dpi::PhysicalSize<u32>) {
181         let (width, height) = size.into();
182         self.context.context.resize(width, height);
183     }
184 }
185 
186 impl<T: ContextCurrentState, W> ContextWrapper<T, W> {
187     /// Borrow the inner GL [`Context`].
188     ///
189     /// [`Context`]: struct.Context.html
context(&self) -> &Context<T>190     pub fn context(&self) -> &Context<T> {
191         &self.context
192     }
193 
194     /// Sets this context as the current context. The previously current context
195     /// (if any) is no longer current.
196     ///
197     /// A failed call to `make_current` might make this, or no context
198     /// current. It could also keep the previous context current. What happens
199     /// varies by platform and error.
200     ///
201     /// To attempt to recover and get back into a know state, either:
202     ///
203     ///  * attempt to use [`is_current`] to find the new current context; or
204     ///  * call [`make_not_current`] on both the previously
205     ///  current context and this context.
206     ///
207     /// # An higher level overview.
208     ///
209     /// In OpenGl, only a single context can be current in a thread at a time.
210     /// Making a new context current will make the old one not current.
211     /// Contexts can only be sent to different threads if they are not current.
212     ///
213     /// If you call `make_current` on some context, you should call
214     /// [`treat_as_not_current`] as soon as possible on the previously current
215     /// context.
216     ///
217     /// If you wish to move a currently current context to a different thread,
218     /// you should do one of two options:
219     ///
220     ///  * Call `make_current` on another context, then call
221     ///  [`treat_as_not_current`] on this context.
222     ///  * Call [`make_not_current`] on this context.
223     ///
224     /// If you are aware of what context you intend to make current next, it is
225     /// preferable for performance reasons to call `make_current` on that
226     /// context, then [`treat_as_not_current`] on this context.
227     ///
228     /// If you are not aware of what context you intend to make current next,
229     /// consider waiting until you do. If you need this context not current
230     /// immediately (e.g. to transfer it to another thread), then call
231     /// [`make_not_current`] on this context.
232     ///
233     /// Please avoid calling [`make_not_current`] on one context only to call
234     /// `make_current` on another context before and/or after. This hurts
235     /// performance by requiring glutin to:
236     ///
237     ///  * Check if this context is current; then
238     ///  * If it is, change the current context from this context to none; then
239     ///  * Change the current context from none to the new context.
240     ///
241     /// Instead prefer the method we mentioned above with `make_current` and
242     /// [`treat_as_not_current`].
243     ///
244     /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current
245     /// [`treat_as_not_current`]:
246     /// struct.ContextWrapper.html#method.treat_as_not_current
247     /// [`is_current`]: struct.ContextWrapper.html#method.is_current
make_current( self, ) -> Result<ContextWrapper<PossiblyCurrent, W>, (Self, ContextError)>248     pub unsafe fn make_current(
249         self,
250     ) -> Result<ContextWrapper<PossiblyCurrent, W>, (Self, ContextError)> {
251         let window = self.window;
252         match self.context.make_current() {
253             Ok(context) => Ok(ContextWrapper { window, context }),
254             Err((context, err)) => {
255                 Err((ContextWrapper { window, context }, err))
256             }
257         }
258     }
259 
260     /// If this context is current, makes this context not current. If this
261     /// context is not current however, this function does nothing.
262     ///
263     /// Please see [`make_current`].
264     ///
265     /// [`make_current`]: struct.ContextWrapper.html#method.make_current
make_not_current( self, ) -> Result<ContextWrapper<NotCurrent, W>, (Self, ContextError)>266     pub unsafe fn make_not_current(
267         self,
268     ) -> Result<ContextWrapper<NotCurrent, W>, (Self, ContextError)> {
269         let window = self.window;
270         match self.context.make_not_current() {
271             Ok(context) => Ok(ContextWrapper { window, context }),
272             Err((context, err)) => {
273                 Err((ContextWrapper { window, context }, err))
274             }
275         }
276     }
277 
278     /// Treats this context as not current, even if it is current. We do no
279     /// checks to confirm that this is actually case.
280     ///
281     /// If unsure whether or not this context is current, please use
282     /// [`make_not_current`] which will do nothing if this context is not
283     /// current.
284     ///
285     /// Please see [`make_current`].
286     ///
287     /// [`make_not_current`]: struct.ContextWrapper.html#method.make_not_current
288     /// [`make_current`]: struct.ContextWrapper.html#method.make_current
treat_as_not_current(self) -> ContextWrapper<NotCurrent, W>289     pub unsafe fn treat_as_not_current(self) -> ContextWrapper<NotCurrent, W> {
290         ContextWrapper {
291             context: self.context.treat_as_not_current(),
292             window: self.window,
293         }
294     }
295 
296     /// Treats this context as current, even if it is not current. We do no
297     /// checks to confirm that this is actually case.
298     ///
299     /// This function should only be used if you intend to track context
300     /// currency without the limited aid of glutin, and you wish to store
301     /// all the [`Context`]s as [`NotCurrent`].
302     ///
303     /// Please see [`make_current`] for the prefered method of handling context
304     /// currency.
305     ///
306     /// [`make_current`]: struct.ContextWrapper.html#method.make_current
307     /// [`NotCurrent`]: enum.NotCurrent.html
308     /// [`Context`]: struct.Context.html
treat_as_current(self) -> ContextWrapper<PossiblyCurrent, W>309     pub unsafe fn treat_as_current(self) -> ContextWrapper<PossiblyCurrent, W> {
310         ContextWrapper {
311             context: self.context.treat_as_current(),
312             window: self.window,
313         }
314     }
315 
316     /// Returns true if this context is the current one in this thread.
is_current(&self) -> bool317     pub fn is_current(&self) -> bool {
318         self.context.is_current()
319     }
320 
321     /// Returns the OpenGL API being used.
get_api(&self) -> Api322     pub fn get_api(&self) -> Api {
323         self.context.get_api()
324     }
325 }
326 
327 impl<W> ContextWrapper<PossiblyCurrent, W> {
328     /// Returns the address of an OpenGL function.
329     #[inline]
get_proc_address(&self, addr: &str) -> *const core::ffi::c_void330     pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void {
331         self.context.get_proc_address(addr)
332     }
333 }
334 
335 impl<T: ContextCurrentState, W> std::ops::Deref for ContextWrapper<T, W> {
336     type Target = Context<T>;
deref(&self) -> &Self::Target337     fn deref(&self) -> &Self::Target {
338         &self.context
339     }
340 }
341 
342 impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> {
343     /// Builds the given window along with the associated GL context, returning
344     /// the pair as a [`WindowedContext<T>`].
345     ///
346     /// Errors can occur in two scenarios:
347     ///  - If the window could not be created (via permission denied,
348     ///  incompatible system, out of memory, etc.). This should be very rare.
349     ///  - If the OpenGL [`Context`] could not be created. This generally
350     ///    happens
351     ///  because the underlying platform doesn't support a requested feature.
352     ///
353     /// [`WindowedContext<T>`]: type.WindowedContext.html
354     /// [`Context`]: struct.Context.html
build_windowed<TE>( self, wb: WindowBuilder, el: &EventLoopWindowTarget<TE>, ) -> Result<WindowedContext<NotCurrent>, CreationError>355     pub fn build_windowed<TE>(
356         self,
357         wb: WindowBuilder,
358         el: &EventLoopWindowTarget<TE>,
359     ) -> Result<WindowedContext<NotCurrent>, CreationError> {
360         let ContextBuilder { pf_reqs, gl_attr } = self;
361         let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
362         platform_impl::Context::new_windowed(wb, el, &pf_reqs, &gl_attr).map(
363             |(window, context)| WindowedContext {
364                 window,
365                 context: Context {
366                     context,
367                     phantom: PhantomData,
368                 },
369             },
370         )
371     }
372 }
373