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