1 #![cfg(feature = "wayland")]
2 
3 use crate::api::egl::{Context as EglContext, NativeDisplay, SurfaceType as EglSurfaceType};
4 use crate::{
5     ContextError, CreationError, GlAttributes, PixelFormat, PixelFormatRequirements, Rect,
6 };
7 
8 use crate::platform::unix::{EventLoopWindowTargetExtUnix, WindowExtUnix};
9 use glutin_egl_sys as ffi;
10 pub use wayland_client::sys::client::wl_display;
11 use winit;
12 use winit::dpi;
13 use winit::event_loop::EventLoopWindowTarget;
14 use winit::window::{Window, WindowBuilder};
15 
16 use std::ops::Deref;
17 use std::os::raw;
18 use std::sync::Arc;
19 
20 pub struct EglSurface(Arc<wayland_egl::WlEglSurface>);
21 
22 impl std::fmt::Debug for EglSurface {
23     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
24         write!(f, "EglSurface(...)")
25     }
26 }
27 
28 #[derive(Debug)]
29 pub enum Context {
30     Windowed(EglContext, EglSurface),
31     PBuffer(EglContext),
32     Surfaceless(EglContext),
33 }
34 
35 impl Deref for Context {
36     type Target = EglContext;
37 
38     fn deref(&self) -> &Self::Target {
39         match self {
40             Context::Windowed(ctx, _) => ctx,
41             Context::PBuffer(ctx) => ctx,
42             Context::Surfaceless(ctx) => ctx,
43         }
44     }
45 }
46 
47 impl Context {
48     #[inline]
49     pub fn new_headless<T>(
50         el: &EventLoopWindowTarget<T>,
51         pf_reqs: &PixelFormatRequirements,
52         gl_attr: &GlAttributes<&Context>,
53         size: Option<dpi::PhysicalSize<u32>>,
54     ) -> Result<Self, CreationError> {
55         let gl_attr = gl_attr.clone().map_sharing(|c| &**c);
56         let display_ptr = el.wayland_display().unwrap() as *const _;
57         let native_display = NativeDisplay::Wayland(Some(display_ptr as *const _));
58         if let Some(size) = size {
59             let context = EglContext::new(
60                 pf_reqs,
61                 &gl_attr,
62                 native_display,
63                 EglSurfaceType::PBuffer,
64                 |c, _| Ok(c[0]),
65             )
66             .and_then(|p| p.finish_pbuffer(size))?;
67             let context = Context::PBuffer(context);
68             Ok(context)
69         } else {
70             // Surfaceless
71             let context = EglContext::new(
72                 pf_reqs,
73                 &gl_attr,
74                 native_display,
75                 EglSurfaceType::Surfaceless,
76                 |c, _| Ok(c[0]),
77             )
78             .and_then(|p| p.finish_surfaceless())?;
79             let context = Context::Surfaceless(context);
80             Ok(context)
81         }
82     }
83 
84     #[inline]
85     pub fn new<T>(
86         wb: WindowBuilder,
87         el: &EventLoopWindowTarget<T>,
88         pf_reqs: &PixelFormatRequirements,
89         gl_attr: &GlAttributes<&Context>,
90     ) -> Result<(Window, Self), CreationError> {
91         let win = wb.build(el)?;
92 
93         let size = win.inner_size();
94         let (width, height): (u32, u32) = size.into();
95 
96         let display_ptr = win.wayland_display().unwrap() as *const _;
97         let surface = win.wayland_surface();
98         let surface = match surface {
99             Some(s) => s,
100             None => {
101                 return Err(CreationError::NotSupported("Wayland not found".to_string()));
102             }
103         };
104 
105         let context = Self::new_raw_context(display_ptr, surface, width, height, pf_reqs, gl_attr)?;
106         Ok((win, context))
107     }
108 
109     #[inline]
110     pub fn new_raw_context(
111         display_ptr: *const wl_display,
112         surface: *mut raw::c_void,
113         width: u32,
114         height: u32,
115         pf_reqs: &PixelFormatRequirements,
116         gl_attr: &GlAttributes<&Context>,
117     ) -> Result<Self, CreationError> {
118         let egl_surface = unsafe {
119             wayland_egl::WlEglSurface::new_from_raw(surface as *mut _, width as i32, height as i32)
120         };
121         let context = {
122             let gl_attr = gl_attr.clone().map_sharing(|c| &**c);
123             let native_display = NativeDisplay::Wayland(Some(display_ptr as *const _));
124             EglContext::new(pf_reqs, &gl_attr, native_display, EglSurfaceType::Window, |c, _| {
125                 Ok(c[0])
126             })
127             .and_then(|p| p.finish(egl_surface.ptr() as *const _))?
128         };
129         let context = Context::Windowed(context, EglSurface(Arc::new(egl_surface)));
130         Ok(context)
131     }
132 
133     #[inline]
134     pub unsafe fn make_current(&self) -> Result<(), ContextError> {
135         (**self).make_current()
136     }
137 
138     #[inline]
139     pub unsafe fn make_not_current(&self) -> Result<(), ContextError> {
140         (**self).make_not_current()
141     }
142 
143     #[inline]
144     pub fn is_current(&self) -> bool {
145         (**self).is_current()
146     }
147 
148     #[inline]
149     pub fn get_api(&self) -> crate::Api {
150         (**self).get_api()
151     }
152 
153     #[inline]
154     pub unsafe fn raw_handle(&self) -> ffi::EGLContext {
155         (**self).raw_handle()
156     }
157 
158     #[inline]
159     pub unsafe fn get_egl_display(&self) -> Option<*const raw::c_void> {
160         Some((**self).get_egl_display())
161     }
162 
163     #[inline]
164     pub fn resize(&self, width: u32, height: u32) {
165         match self {
166             Context::Windowed(_, surface) => surface.0.resize(width as i32, height as i32, 0, 0),
167             _ => unreachable!(),
168         }
169     }
170 
171     #[inline]
172     pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void {
173         (**self).get_proc_address(addr)
174     }
175 
176     #[inline]
177     pub fn swap_buffers(&self) -> Result<(), ContextError> {
178         (**self).swap_buffers()
179     }
180 
181     #[inline]
182     pub fn swap_buffers_with_damage(&self, rects: &[Rect]) -> Result<(), ContextError> {
183         (**self).swap_buffers_with_damage(rects)
184     }
185 
186     #[inline]
187     pub fn swap_buffers_with_damage_supported(&self) -> bool {
188         (**self).swap_buffers_with_damage_supported()
189     }
190 
191     #[inline]
192     pub fn get_pixel_format(&self) -> PixelFormat {
193         (**self).get_pixel_format().clone()
194     }
195 }
196