glium/backend/glutin/
mod.rs1#![cfg(feature = "glutin")]
2pub use glutin;
12use glutin::surface::Surface;
13use glutin::surface::SwapInterval;
14
15use crate::backend;
16use crate::backend::Backend;
17use crate::backend::Context;
18use crate::context;
19use crate::debug;
20use crate::glutin::context::PossiblyCurrentContext;
21use crate::glutin::display::GetGlDisplay;
22use crate::glutin::prelude::*;
23use crate::glutin::surface::{ResizeableSurface, SurfaceTypeTrait};
24use crate::SwapBuffersError;
25use crate::{Frame, IncompatibleOpenGl};
26use std::cell::RefCell;
27use std::error::Error;
28use std::ffi::CString;
29use std::fmt;
30use std::num::NonZeroU32;
31use std::ops::Deref;
32use std::os::raw::c_void;
33use std::rc::Rc;
34
35#[cfg(feature = "simple_window_builder")]
36pub use self::simple_window_builder::SimpleWindowBuilder;
37
38#[cfg(feature = "simple_window_builder")]
39pub mod simple_window_builder;
40
41pub struct ContextSurfacePair<T: SurfaceTypeTrait + ResizeableSurface> {
44 context: PossiblyCurrentContext,
45 surface: glutin::surface::Surface<T>,
46}
47
48impl<T: SurfaceTypeTrait + ResizeableSurface> ContextSurfacePair<T> {
49 fn new(context: PossiblyCurrentContext, surface: glutin::surface::Surface<T>) -> Self {
50 Self { context, surface }
51 }
52
53 #[inline]
54 pub fn get_framebuffer_dimensions(&self) -> (u32, u32) {
56 (
57 self.surface.width().unwrap(),
58 self.surface.height().unwrap(),
59 )
60 }
61
62 #[inline]
63 pub fn swap_buffers(&self) -> Result<(), glutin::error::Error> {
65 self.surface.swap_buffers(&self.context)
66 }
67
68 #[inline]
69 pub fn set_swap_interval(&self, interval: SwapInterval) -> Result<(), glutin::error::Error> {
71 self.surface.set_swap_interval(&self.context, interval)
72 }
73
74 #[inline]
75 pub fn resize(&self, new_size: (u32, u32)) {
77 let width = NonZeroU32::new(new_size.0).unwrap_or(NonZeroU32::new(1).unwrap());
79 let height = NonZeroU32::new(new_size.1).unwrap_or(NonZeroU32::new(1).unwrap());
80 self.surface.resize(&self.context, width, height);
81 }
82}
83
84impl<T: SurfaceTypeTrait + ResizeableSurface> Deref for ContextSurfacePair<T> {
85 type Target = PossiblyCurrentContext;
86 #[inline]
87 fn deref(&self) -> &PossiblyCurrentContext {
88 &self.context
89 }
90}
91
92#[derive(Clone)]
98pub struct Display<T: SurfaceTypeTrait + ResizeableSurface + 'static> {
99 context: Rc<context::Context>,
101 gl_context: Rc<RefCell<Option<ContextSurfacePair<T>>>>,
103}
104
105#[derive(Clone)]
107pub struct GlutinBackend<T: SurfaceTypeTrait + ResizeableSurface>(
108 Rc<RefCell<Option<ContextSurfacePair<T>>>>,
109);
110
111#[derive(Debug)]
113pub enum DisplayCreationError {
114 GlutinError(glutin::error::Error),
116 IncompatibleOpenGl(IncompatibleOpenGl),
118}
119
120impl<T: SurfaceTypeTrait + ResizeableSurface> std::fmt::Debug for Display<T> {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "[glium::backend::glutin::Display]")
123 }
124}
125
126impl<T: SurfaceTypeTrait + ResizeableSurface> Display<T> {
127 pub fn new(
132 context: PossiblyCurrentContext,
133 surface: Surface<T>,
134 ) -> Result<Self, DisplayCreationError> {
135 Self::from_context_surface(context, surface).map_err(From::from)
136 }
137
138 pub fn from_context_surface(
143 context: PossiblyCurrentContext,
144 surface: Surface<T>,
145 ) -> Result<Self, IncompatibleOpenGl> {
146 Self::with_debug(context, surface, Default::default())
147 }
148
149 pub unsafe fn unchecked(
154 context: PossiblyCurrentContext,
155 surface: Surface<T>,
156 ) -> Result<Self, IncompatibleOpenGl> {
157 Self::unchecked_with_debug(context, surface, Default::default())
158 }
159
160 pub fn with_debug(
162 context: PossiblyCurrentContext,
163 surface: Surface<T>,
164 debug: debug::DebugCallbackBehavior,
165 ) -> Result<Self, IncompatibleOpenGl> {
166 Self::new_inner(context, surface, debug, true)
167 }
168
169 pub unsafe fn unchecked_with_debug(
171 context: PossiblyCurrentContext,
172 surface: Surface<T>,
173 debug: debug::DebugCallbackBehavior,
174 ) -> Result<Self, IncompatibleOpenGl> {
175 Self::new_inner(context, surface, debug, false)
176 }
177
178 fn new_inner(
179 context: PossiblyCurrentContext,
180 surface: Surface<T>,
181 debug: debug::DebugCallbackBehavior,
182 checked: bool,
183 ) -> Result<Self, IncompatibleOpenGl> {
184 let context_surface_pair = ContextSurfacePair::new(context, surface);
185 let gl_window = Rc::new(RefCell::new(Some(context_surface_pair)));
186 let glutin_backend = GlutinBackend(gl_window.clone());
187 let context = unsafe { context::Context::new(glutin_backend, checked, debug) }?;
188 Ok(Display {
189 gl_context: gl_window,
190 context,
191 })
192 }
193
194 #[inline]
196 pub fn resize(&self, new_size: (u32, u32)) {
197 self.gl_context.borrow().as_ref().unwrap().resize(new_size)
198 }
199
200 #[inline]
201 pub fn set_swap_interval(&self, interval: SwapInterval) -> Result<(), glutin::error::Error> {
203 self.gl_context
204 .borrow()
205 .as_ref()
206 .unwrap()
207 .set_swap_interval(interval)
208 }
209
210 #[inline]
217 pub fn draw(&self) -> Frame {
218 let dimensions = self.get_framebuffer_dimensions();
219 Frame::new(self.context.clone(), dimensions)
220 }
221}
222
223impl fmt::Display for DisplayCreationError {
224 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
225 match self {
226 DisplayCreationError::GlutinError(err) => write!(fmt, "{}", err),
227 DisplayCreationError::IncompatibleOpenGl(err) => write!(fmt, "{}", err),
228 }
229 }
230}
231
232impl Error for DisplayCreationError {
233 #[inline]
234 fn source(&self) -> Option<&(dyn Error + 'static)> {
235 match *self {
236 DisplayCreationError::GlutinError(ref err) => Some(err),
237 DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
238 }
239 }
240}
241
242impl From<glutin::error::Error> for DisplayCreationError {
243 #[inline]
244 fn from(err: glutin::error::Error) -> DisplayCreationError {
245 DisplayCreationError::GlutinError(err)
246 }
247}
248
249impl From<IncompatibleOpenGl> for DisplayCreationError {
250 #[inline]
251 fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
252 DisplayCreationError::IncompatibleOpenGl(err)
253 }
254}
255
256impl<T: SurfaceTypeTrait + ResizeableSurface> Deref for Display<T> {
257 type Target = Context;
258 #[inline]
259 fn deref(&self) -> &Context {
260 &self.context
261 }
262}
263
264impl<T: SurfaceTypeTrait + ResizeableSurface> backend::Facade for Display<T> {
265 #[inline]
266 fn get_context(&self) -> &Rc<Context> {
267 &self.context
268 }
269}
270
271impl<T: SurfaceTypeTrait + ResizeableSurface> Deref for GlutinBackend<T> {
272 type Target = Rc<RefCell<Option<ContextSurfacePair<T>>>>;
273 #[inline]
274 fn deref(&self) -> &Self::Target {
275 &self.0
276 }
277}
278
279unsafe impl<T: SurfaceTypeTrait + ResizeableSurface> Backend for GlutinBackend<T> {
280 #[inline]
281 fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
282 match self.borrow().as_ref().unwrap().swap_buffers() {
283 Ok(()) => Ok(()),
284 _ => Err(SwapBuffersError::ContextLost),
285 }
286 }
287
288 #[inline]
289 unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
290 let symbol = CString::new(symbol).unwrap();
291 self.borrow()
292 .as_ref()
293 .unwrap()
294 .display()
295 .get_proc_address(&symbol) as *const _
296 }
297
298 #[inline]
299 fn get_framebuffer_dimensions(&self) -> (u32, u32) {
300 self.0
301 .borrow()
302 .as_ref()
303 .unwrap()
304 .get_framebuffer_dimensions()
305 }
306
307 #[inline]
308 fn resize(&self, new_size: (u32, u32)) {
309 self.borrow().as_ref().unwrap().resize(new_size)
310 }
311
312 #[inline]
313 fn set_swap_interval(&self, interval: SwapInterval) {
314 self.borrow()
315 .as_ref()
316 .unwrap()
317 .set_swap_interval(interval)
318 .unwrap()
319 }
320
321 #[inline]
322 fn is_current(&self) -> bool {
323 self.borrow().as_ref().unwrap().is_current()
324 }
325
326 #[inline]
327 unsafe fn make_current(&self) {
328 let pair = self.borrow();
329 pair.as_ref()
330 .unwrap()
331 .context
332 .make_current(&pair.as_ref().unwrap().surface)
333 .unwrap();
334 }
335}