1 #![cfg(target_os = "windows")] 2 3 use crate::{ 4 Api, ContextCurrentState, ContextError, CreationError, GlAttributes, 5 GlRequest, NotCurrent, PixelFormat, PixelFormatRequirements, 6 }; 7 8 use crate::api::egl::{ 9 Context as EglContext, NativeDisplay, SurfaceType as EglSurfaceType, EGL, 10 }; 11 use crate::api::wgl::Context as WglContext; 12 use crate::os::windows::WindowExt; 13 14 use glutin_egl_sys as ffi; 15 use winapi::shared::windef::{HGLRC, HWND}; 16 use winit; 17 use winit::dpi; 18 19 use std::marker::PhantomData; 20 use std::os::raw; 21 22 /// Context handles available on Windows. 23 #[derive(Clone, Debug)] 24 pub enum RawHandle { 25 Egl(ffi::EGLContext), 26 Wgl(HGLRC), 27 } 28 29 #[derive(Debug)] 30 pub enum Context { 31 /// A regular window 32 Egl(EglContext), 33 Wgl(WglContext), 34 /// A regular window, but invisible. 35 HiddenWindowEgl(winit::Window, EglContext), 36 HiddenWindowWgl(winit::Window, WglContext), 37 /// An EGL pbuffer. 38 EglPbuffer(EglContext), 39 } 40 41 unsafe impl Send for Context {} 42 unsafe impl Sync for Context {} 43 44 impl Context { 45 /// See the docs in the crate root file. 46 #[inline] new_windowed( wb: winit::WindowBuilder, el: &winit::EventsLoop, pf_reqs: &PixelFormatRequirements, gl_attr: &GlAttributes<&Self>, ) -> Result<(winit::Window, Self), CreationError>47 pub fn new_windowed( 48 wb: winit::WindowBuilder, 49 el: &winit::EventsLoop, 50 pf_reqs: &PixelFormatRequirements, 51 gl_attr: &GlAttributes<&Self>, 52 ) -> Result<(winit::Window, Self), CreationError> { 53 let win = wb.build(el)?; 54 let hwnd = win.get_hwnd() as HWND; 55 let ctx = Self::new_raw_context(hwnd, pf_reqs, gl_attr)?; 56 57 Ok((win, ctx)) 58 } 59 60 #[inline] new_raw_context( hwnd: HWND, pf_reqs: &PixelFormatRequirements, gl_attr: &GlAttributes<&Self>, ) -> Result<Self, CreationError>61 pub fn new_raw_context( 62 hwnd: HWND, 63 pf_reqs: &PixelFormatRequirements, 64 gl_attr: &GlAttributes<&Self>, 65 ) -> Result<Self, CreationError> { 66 match gl_attr.version { 67 GlRequest::Specific(Api::OpenGlEs, (_major, _minor)) => { 68 match (gl_attr.sharing, &*EGL) { 69 // We must use WGL. 70 (Some(&Context::HiddenWindowWgl(_, _)), _) 71 | (Some(&Context::Wgl(_)), _) 72 | (None, None) => { 73 let gl_attr_wgl = 74 gl_attr.clone().map_sharing(|ctx| match *ctx { 75 Context::HiddenWindowWgl(_, ref c) 76 | Context::Wgl(ref c) => c.get_hglrc(), 77 _ => unreachable!(), 78 }); 79 unsafe { 80 WglContext::new(&pf_reqs, &gl_attr_wgl, hwnd) 81 .map(Context::Wgl) 82 } 83 } 84 // We must use EGL. 85 (Some(_), Some(_)) => { 86 let gl_attr_egl = 87 gl_attr.clone().map_sharing(|ctx| match *ctx { 88 Context::Egl(ref c) 89 | Context::EglPbuffer(ref c) 90 | Context::HiddenWindowEgl(_, ref c) => c, 91 _ => unreachable!(), 92 }); 93 94 EglContext::new( 95 &pf_reqs, 96 &gl_attr_egl, 97 NativeDisplay::Other(Some(std::ptr::null())), 98 EglSurfaceType::Window, 99 ) 100 .and_then(|p| p.finish(hwnd)) 101 .map(|c| Context::Egl(c)) 102 } 103 // Try EGL, fallback to WGL. 104 (None, Some(_)) => { 105 let gl_attr_egl = 106 gl_attr.clone().map_sharing(|_| unreachable!()); 107 let gl_attr_wgl = 108 gl_attr.clone().map_sharing(|_| unreachable!()); 109 110 if let Ok(c) = EglContext::new( 111 &pf_reqs, 112 &gl_attr_egl, 113 NativeDisplay::Other(Some(std::ptr::null())), 114 EglSurfaceType::Window, 115 ) 116 .and_then(|p| p.finish(hwnd)) 117 { 118 Ok(Context::Egl(c)) 119 } else { 120 unsafe { 121 WglContext::new(&pf_reqs, &gl_attr_wgl, hwnd) 122 .map(Context::Wgl) 123 } 124 } 125 } 126 _ => panic!(), 127 } 128 } 129 _ => { 130 let gl_attr_wgl = 131 gl_attr.clone().map_sharing(|ctx| match *ctx { 132 Context::HiddenWindowWgl(_, ref c) 133 | Context::Wgl(ref c) => c.get_hglrc(), 134 _ => panic!(), 135 }); 136 unsafe { 137 WglContext::new(&pf_reqs, &gl_attr_wgl, hwnd) 138 .map(Context::Wgl) 139 } 140 } 141 } 142 } 143 144 #[inline] new_headless( el: &winit::EventsLoop, pf_reqs: &PixelFormatRequirements, gl_attr: &GlAttributes<&Context>, size: dpi::PhysicalSize, ) -> Result<Self, CreationError>145 pub fn new_headless( 146 el: &winit::EventsLoop, 147 pf_reqs: &PixelFormatRequirements, 148 gl_attr: &GlAttributes<&Context>, 149 size: dpi::PhysicalSize, 150 ) -> Result<Self, CreationError> { 151 // if EGL is available, we try using EGL first 152 // if EGL returns an error, we try the hidden window method 153 match (gl_attr.sharing, &*EGL) { 154 (None, Some(_)) 155 | (Some(&Context::Egl(_)), Some(_)) 156 | (Some(&Context::HiddenWindowEgl(_, _)), Some(_)) 157 | (Some(&Context::EglPbuffer(_)), Some(_)) => { 158 let gl_attr_egl = 159 gl_attr.clone().map_sharing(|ctx| match *ctx { 160 Context::Egl(ref c) 161 | Context::EglPbuffer(ref c) 162 | Context::HiddenWindowEgl(_, ref c) => c, 163 _ => unreachable!(), 164 }); 165 166 let native_display = NativeDisplay::Other(None); 167 let context = EglContext::new( 168 pf_reqs, 169 &gl_attr_egl, 170 native_display, 171 EglSurfaceType::PBuffer, 172 ) 173 .and_then(|prototype| prototype.finish_pbuffer(size)) 174 .map(|ctx| Context::EglPbuffer(ctx)); 175 176 if let Ok(context) = context { 177 return Ok(context); 178 } 179 } 180 _ => (), 181 } 182 183 let wb = winit::WindowBuilder::new() 184 .with_visibility(false) 185 .with_dimensions(size.to_logical(1.)); 186 Self::new_windowed(wb, &el, pf_reqs, gl_attr).map(|(win, context)| { 187 match context { 188 Context::Egl(context) => Context::HiddenWindowEgl(win, context), 189 Context::Wgl(context) => Context::HiddenWindowWgl(win, context), 190 _ => unreachable!(), 191 } 192 }) 193 } 194 195 #[inline] resize(&self, _width: u32, _height: u32)196 pub fn resize(&self, _width: u32, _height: u32) { 197 // Method is for API consistency. 198 } 199 200 #[inline] make_current(&self) -> Result<(), ContextError>201 pub unsafe fn make_current(&self) -> Result<(), ContextError> { 202 match *self { 203 Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => { 204 c.make_current() 205 } 206 Context::Egl(ref c) 207 | Context::HiddenWindowEgl(_, ref c) 208 | Context::EglPbuffer(ref c) => c.make_current(), 209 } 210 } 211 212 #[inline] make_not_current(&self) -> Result<(), ContextError>213 pub unsafe fn make_not_current(&self) -> Result<(), ContextError> { 214 match *self { 215 Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => { 216 c.make_not_current() 217 } 218 Context::Egl(ref c) 219 | Context::HiddenWindowEgl(_, ref c) 220 | Context::EglPbuffer(ref c) => c.make_not_current(), 221 } 222 } 223 224 #[inline] is_current(&self) -> bool225 pub fn is_current(&self) -> bool { 226 match *self { 227 Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => { 228 c.is_current() 229 } 230 Context::Egl(ref c) 231 | Context::HiddenWindowEgl(_, ref c) 232 | Context::EglPbuffer(ref c) => c.is_current(), 233 } 234 } 235 236 #[inline] get_proc_address(&self, addr: &str) -> *const ()237 pub fn get_proc_address(&self, addr: &str) -> *const () { 238 match *self { 239 Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => { 240 c.get_proc_address(addr) 241 } 242 Context::Egl(ref c) 243 | Context::HiddenWindowEgl(_, ref c) 244 | Context::EglPbuffer(ref c) => c.get_proc_address(addr), 245 } 246 } 247 248 #[inline] swap_buffers(&self) -> Result<(), ContextError>249 pub fn swap_buffers(&self) -> Result<(), ContextError> { 250 match *self { 251 Context::Wgl(ref c) => c.swap_buffers(), 252 Context::Egl(ref c) => c.swap_buffers(), 253 _ => unreachable!(), 254 } 255 } 256 257 #[inline] get_api(&self) -> Api258 pub fn get_api(&self) -> Api { 259 match *self { 260 Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => { 261 c.get_api() 262 } 263 Context::Egl(ref c) 264 | Context::HiddenWindowEgl(_, ref c) 265 | Context::EglPbuffer(ref c) => c.get_api(), 266 } 267 } 268 269 #[inline] get_pixel_format(&self) -> PixelFormat270 pub fn get_pixel_format(&self) -> PixelFormat { 271 match *self { 272 Context::Wgl(ref c) => c.get_pixel_format(), 273 Context::Egl(ref c) => c.get_pixel_format(), 274 _ => unreachable!(), 275 } 276 } 277 278 #[inline] raw_handle(&self) -> RawHandle279 pub unsafe fn raw_handle(&self) -> RawHandle { 280 match *self { 281 Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => { 282 RawHandle::Wgl(c.get_hglrc()) 283 } 284 Context::Egl(ref c) 285 | Context::HiddenWindowEgl(_, ref c) 286 | Context::EglPbuffer(ref c) => RawHandle::Egl(c.raw_handle()), 287 } 288 } 289 290 #[inline] get_egl_display(&self) -> Option<*const raw::c_void>291 pub unsafe fn get_egl_display(&self) -> Option<*const raw::c_void> { 292 match *self { 293 Context::Egl(ref c) 294 | Context::HiddenWindowEgl(_, ref c) 295 | Context::EglPbuffer(ref c) => Some(c.get_egl_display()), 296 _ => None, 297 } 298 } 299 } 300 301 pub trait RawContextExt { 302 /// Creates a raw context on the provided window. 303 /// 304 /// Unsafe behaviour might happen if you: 305 /// - Provide us with invalid parameters. 306 /// - The window is destroyed before the context build_raw_context( self, hwnd: *mut raw::c_void, ) -> Result<crate::RawContext<NotCurrent>, CreationError> where Self: Sized307 unsafe fn build_raw_context( 308 self, 309 hwnd: *mut raw::c_void, 310 ) -> Result<crate::RawContext<NotCurrent>, CreationError> 311 where 312 Self: Sized; 313 } 314 315 impl<'a, T: ContextCurrentState> RawContextExt 316 for crate::ContextBuilder<'a, T> 317 { 318 #[inline] build_raw_context( self, hwnd: *mut raw::c_void, ) -> Result<crate::RawContext<NotCurrent>, CreationError> where Self: Sized,319 unsafe fn build_raw_context( 320 self, 321 hwnd: *mut raw::c_void, 322 ) -> Result<crate::RawContext<NotCurrent>, CreationError> 323 where 324 Self: Sized, 325 { 326 let crate::ContextBuilder { pf_reqs, gl_attr } = self; 327 let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context); 328 Context::new_raw_context(hwnd as *mut _, &pf_reqs, &gl_attr) 329 .map(|context| crate::Context { 330 context, 331 phantom: PhantomData, 332 }) 333 .map(|context| crate::RawContext { 334 context, 335 window: (), 336 }) 337 } 338 } 339