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