egl.rs (24926B)
1 // Licensed under the Apache License, Version 2.0. 2 // This file may not be copied, modified, or distributed except according to those terms. 3 4 //! Based on https://github.com/tomaka/glutin/blob/1b2d62c0e9/src/api/egl/mod.rs 5 #![cfg(windows)] 6 #![allow(unused_variables)] 7 8 use glutin::ContextError; 9 use glutin::CreationError; 10 use glutin::GlAttributes; 11 use glutin::GlRequest; 12 use glutin::PixelFormat; 13 use glutin::PixelFormatRequirements; 14 use glutin::ReleaseBehavior; 15 use glutin::Robustness; 16 use glutin::Api; 17 use mozangle::egl::ffi::types::EGLAttrib; 18 19 use std::ffi::{CStr, CString}; 20 use std::os::raw::c_int; 21 use std::os::raw::c_void; 22 use std::ptr; 23 use std::cell::Cell; 24 25 use mozangle::egl::ffi as egl; 26 mod ffi { 27 pub use mozangle::egl::ffi as egl; 28 pub use mozangle::egl::ffi::*; 29 } 30 31 pub struct Context { 32 display: ffi::egl::types::EGLDisplay, 33 context: ffi::egl::types::EGLContext, 34 surface: Cell<ffi::egl::types::EGLSurface>, 35 api: Api, 36 pixel_format: PixelFormat, 37 using_compositor: bool, 38 } 39 40 impl Context { 41 /// Start building an EGL context. 42 /// 43 /// This function initializes some things and chooses the pixel format. 44 /// 45 /// To finish the process, you must call `.finish(window)` on the `ContextPrototype`. 46 pub fn new<'a>( 47 pf_reqs: &PixelFormatRequirements, 48 opengl: &'a GlAttributes<&'a Context>, 49 ) -> Result<ContextPrototype<'a>, CreationError> 50 { 51 if opengl.sharing.is_some() { 52 unimplemented!() 53 } 54 55 // calling `eglGetDisplay` or equivalent 56 let display = unsafe { egl::GetDisplay(ptr::null_mut()) }; 57 58 if display.is_null() { 59 return Err(CreationError::PlatformSpecific("Could not create EGL display object".to_string())); 60 } 61 62 let egl_version = unsafe { 63 let mut major: ffi::egl::types::EGLint = 0; // out param 64 let mut minor: ffi::egl::types::EGLint = 0; // out param 65 66 if egl::Initialize(display, &mut major, &mut minor) == 0 { 67 return Err(CreationError::OsError(format!("eglInitialize failed"))) 68 } 69 70 (major, minor) 71 }; 72 73 // the list of extensions supported by the client once initialized is different from the 74 // list of extensions obtained earlier 75 let extensions = if egl_version >= (1, 2) { 76 let p = unsafe { CStr::from_ptr(egl::QueryString(display, ffi::egl::EXTENSIONS as i32)) }; 77 let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| format!("")); 78 list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>() 79 80 } else { 81 vec![] 82 }; 83 84 // binding the right API and choosing the version 85 let (version, api) = unsafe { 86 match opengl.version { 87 GlRequest::Latest => { 88 if egl_version >= (1, 4) { 89 if egl::BindAPI(ffi::egl::OPENGL_API) != 0 { 90 (None, Api::OpenGl) 91 } else if egl::BindAPI(ffi::egl::OPENGL_ES_API) != 0 { 92 (None, Api::OpenGlEs) 93 } else { 94 return Err(CreationError::OpenGlVersionNotSupported); 95 } 96 } else { 97 (None, Api::OpenGlEs) 98 } 99 }, 100 GlRequest::Specific(Api::OpenGlEs, version) => { 101 if egl_version >= (1, 2) { 102 if egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 { 103 return Err(CreationError::OpenGlVersionNotSupported); 104 } 105 } 106 (Some(version), Api::OpenGlEs) 107 }, 108 GlRequest::Specific(Api::OpenGl, version) => { 109 if egl_version < (1, 4) { 110 return Err(CreationError::OpenGlVersionNotSupported); 111 } 112 if egl::BindAPI(ffi::egl::OPENGL_API) == 0 { 113 return Err(CreationError::OpenGlVersionNotSupported); 114 } 115 (Some(version), Api::OpenGl) 116 }, 117 GlRequest::Specific(_, _) => return Err(CreationError::OpenGlVersionNotSupported), 118 GlRequest::GlThenGles { opengles_version, opengl_version } => { 119 if egl_version >= (1, 4) { 120 if egl::BindAPI(ffi::egl::OPENGL_API) != 0 { 121 (Some(opengl_version), Api::OpenGl) 122 } else if egl::BindAPI(ffi::egl::OPENGL_ES_API) != 0 { 123 (Some(opengles_version), Api::OpenGlEs) 124 } else { 125 return Err(CreationError::OpenGlVersionNotSupported); 126 } 127 } else { 128 (Some(opengles_version), Api::OpenGlEs) 129 } 130 }, 131 } 132 }; 133 134 let (config_id, pixel_format) = unsafe { 135 choose_fbconfig(display, &egl_version, api, version, pf_reqs)? 136 }; 137 138 Ok(ContextPrototype { 139 opengl: opengl, 140 display: display, 141 egl_version: egl_version, 142 extensions: extensions, 143 api: api, 144 version: version, 145 config_id: config_id, 146 pixel_format: pixel_format, 147 }) 148 } 149 150 #[inline] 151 pub fn swap_buffers(&self) -> Result<(), ContextError> { 152 if self.using_compositor { 153 return Ok(()); 154 } 155 156 if self.surface.get() == ffi::egl::NO_SURFACE { 157 return Err(ContextError::ContextLost); 158 } 159 160 let ret = unsafe { 161 egl::SwapBuffers(self.display, self.surface.get()) 162 }; 163 164 if ret == 0 { 165 match unsafe { egl::GetError() } as u32 { 166 ffi::egl::CONTEXT_LOST => return Err(ContextError::ContextLost), 167 err => panic!("eglSwapBuffers failed (eglGetError returned 0x{:x})", err) 168 } 169 170 } else { 171 Ok(()) 172 } 173 } 174 175 pub unsafe fn make_current(&self) -> Result<(), ContextError> { 176 let ret = egl::MakeCurrent(self.display, self.surface.get(), self.surface.get(), self.context); 177 178 if ret == 0 { 179 match egl::GetError() as u32 { 180 ffi::egl::CONTEXT_LOST => return Err(ContextError::ContextLost), 181 err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err) 182 } 183 184 } else { 185 Ok(()) 186 } 187 } 188 189 #[inline] 190 pub fn is_current(&self) -> bool { 191 unsafe { egl::GetCurrentContext() == self.context } 192 } 193 194 pub fn get_proc_address(&self, addr: &str) -> *const () { 195 let addr = CString::new(addr.as_bytes()).unwrap(); 196 let addr = addr.as_ptr(); 197 unsafe { 198 egl::GetProcAddress(addr) as *const _ 199 } 200 } 201 202 #[inline] 203 pub fn get_api(&self) -> Api { 204 self.api 205 } 206 207 #[inline] 208 pub fn get_pixel_format(&self) -> PixelFormat { 209 self.pixel_format.clone() 210 } 211 212 pub fn get_display(&self) -> *const c_void { 213 self.display 214 } 215 216 pub fn get_context(&self) -> *const c_void { 217 self.context 218 } 219 220 pub fn get_d3d11_device(&self) -> *const c_void { 221 let mut egl_device: EGLAttrib = 0; 222 unsafe { 223 egl::QueryDisplayAttribEXT(self.display, egl::DEVICE_EXT as i32, &mut egl_device); 224 } 225 assert!(egl_device != 0); 226 227 let mut d3d_device: EGLAttrib = 0; 228 unsafe { 229 egl::QueryDeviceAttribEXT(egl_device as *const c_void, egl::D3D11_DEVICE_ANGLE as i32, &mut d3d_device); 230 } 231 assert!(d3d_device != 0); 232 233 d3d_device as *const c_void 234 } 235 } 236 237 unsafe impl Send for Context {} 238 unsafe impl Sync for Context {} 239 240 impl Drop for Context { 241 fn drop(&mut self) { 242 unsafe { 243 // we don't call MakeCurrent(0, 0) because we are not sure that the context 244 // is still the current one 245 egl::DestroyContext(self.display, self.context); 246 egl::DestroySurface(self.display, self.surface.get()); 247 egl::Terminate(self.display); 248 } 249 } 250 } 251 252 pub struct ContextPrototype<'a> { 253 opengl: &'a GlAttributes<&'a Context>, 254 display: ffi::egl::types::EGLDisplay, 255 egl_version: (ffi::egl::types::EGLint, ffi::egl::types::EGLint), 256 extensions: Vec<String>, 257 api: Api, 258 version: Option<(u8, u8)>, 259 config_id: ffi::egl::types::EGLConfig, 260 pixel_format: PixelFormat, 261 } 262 263 impl<'a> ContextPrototype<'a> { 264 pub fn get_native_visual_id(&self) -> ffi::egl::types::EGLint { 265 let mut value = 0; 266 let ret = unsafe { egl::GetConfigAttrib(self.display, self.config_id, 267 ffi::egl::NATIVE_VISUAL_ID 268 as ffi::egl::types::EGLint, &mut value) }; 269 if ret == 0 { panic!("eglGetConfigAttrib failed") }; 270 value 271 } 272 273 pub fn finish(self, native_window: ffi::EGLNativeWindowType, using_compositor: bool) 274 -> Result<Context, CreationError> 275 { 276 let surface = if using_compositor { 277 ptr::null() 278 } else { 279 unsafe { 280 let surface = egl::CreateWindowSurface(self.display, self.config_id, native_window, 281 ptr::null()); 282 if surface.is_null() { 283 return Err(CreationError::OsError(format!("eglCreateWindowSurface failed"))) 284 } 285 surface 286 } 287 }; 288 289 self.finish_impl(surface, using_compositor) 290 } 291 292 pub fn finish_pbuffer(self, dimensions: (u32, u32)) -> Result<Context, CreationError> { 293 let attrs = &[ 294 ffi::egl::WIDTH as c_int, dimensions.0 as c_int, 295 ffi::egl::HEIGHT as c_int, dimensions.1 as c_int, 296 ffi::egl::NONE as c_int, 297 ]; 298 299 let surface = unsafe { 300 let surface = egl::CreatePbufferSurface(self.display, self.config_id, 301 attrs.as_ptr()); 302 if surface.is_null() { 303 return Err(CreationError::OsError(format!("eglCreatePbufferSurface failed"))) 304 } 305 surface 306 }; 307 308 self.finish_impl(surface, false) 309 } 310 311 fn finish_impl(self, surface: ffi::egl::types::EGLSurface, using_compositor: bool) 312 -> Result<Context, CreationError> 313 { 314 let context = unsafe { 315 if let Some(version) = self.version { 316 create_context(self.display, &self.egl_version, 317 &self.extensions, self.api, version, self.config_id, 318 self.opengl.debug, self.opengl.robustness)? 319 320 } else if self.api == Api::OpenGlEs { 321 if let Ok(ctxt) = create_context(self.display, &self.egl_version, 322 &self.extensions, self.api, (2, 0), self.config_id, 323 self.opengl.debug, self.opengl.robustness) 324 { 325 ctxt 326 } else if let Ok(ctxt) = create_context(self.display, &self.egl_version, 327 &self.extensions, self.api, (1, 0), 328 self.config_id, self.opengl.debug, 329 self.opengl.robustness) 330 { 331 ctxt 332 } else { 333 return Err(CreationError::OpenGlVersionNotSupported); 334 } 335 336 } else { 337 if let Ok(ctxt) = create_context(self.display, &self.egl_version, 338 &self.extensions, self.api, (3, 2), self.config_id, 339 self.opengl.debug, self.opengl.robustness) 340 { 341 ctxt 342 } else if let Ok(ctxt) = create_context(self.display, &self.egl_version, 343 &self.extensions, self.api, (3, 1), 344 self.config_id, self.opengl.debug, 345 self.opengl.robustness) 346 { 347 ctxt 348 } else if let Ok(ctxt) = create_context(self.display, &self.egl_version, 349 &self.extensions, self.api, (1, 0), 350 self.config_id, self.opengl.debug, 351 self.opengl.robustness) 352 { 353 ctxt 354 } else { 355 return Err(CreationError::OpenGlVersionNotSupported); 356 } 357 } 358 }; 359 360 Ok(Context { 361 display: self.display, 362 context: context, 363 surface: Cell::new(surface), 364 api: self.api, 365 pixel_format: self.pixel_format, 366 using_compositor, 367 }) 368 } 369 } 370 371 unsafe fn choose_fbconfig(display: ffi::egl::types::EGLDisplay, 372 egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), 373 api: Api, version: Option<(u8, u8)>, reqs: &PixelFormatRequirements) 374 -> Result<(ffi::egl::types::EGLConfig, PixelFormat), CreationError> 375 { 376 let descriptor = { 377 let mut out: Vec<c_int> = Vec::with_capacity(37); 378 379 if egl_version >= &(1, 2) { 380 out.push(ffi::egl::COLOR_BUFFER_TYPE as c_int); 381 out.push(ffi::egl::RGB_BUFFER as c_int); 382 } 383 384 out.push(ffi::egl::SURFACE_TYPE as c_int); 385 // TODO: Some versions of Mesa report a BAD_ATTRIBUTE error 386 // if we ask for PBUFFER_BIT as well as WINDOW_BIT 387 out.push((ffi::egl::WINDOW_BIT) as c_int); 388 389 match (api, version) { 390 (Api::OpenGlEs, Some((3, _))) => { 391 if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } 392 out.push(ffi::egl::RENDERABLE_TYPE as c_int); 393 out.push(ffi::egl::OPENGL_ES3_BIT as c_int); 394 out.push(ffi::egl::CONFORMANT as c_int); 395 out.push(ffi::egl::OPENGL_ES3_BIT as c_int); 396 }, 397 (Api::OpenGlEs, Some((2, _))) => { 398 if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } 399 out.push(ffi::egl::RENDERABLE_TYPE as c_int); 400 out.push(ffi::egl::OPENGL_ES2_BIT as c_int); 401 out.push(ffi::egl::CONFORMANT as c_int); 402 out.push(ffi::egl::OPENGL_ES2_BIT as c_int); 403 }, 404 (Api::OpenGlEs, Some((1, _))) => { 405 if egl_version >= &(1, 3) { 406 out.push(ffi::egl::RENDERABLE_TYPE as c_int); 407 out.push(ffi::egl::OPENGL_ES_BIT as c_int); 408 out.push(ffi::egl::CONFORMANT as c_int); 409 out.push(ffi::egl::OPENGL_ES_BIT as c_int); 410 } 411 }, 412 (Api::OpenGlEs, _) => unimplemented!(), 413 (Api::OpenGl, _) => { 414 if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } 415 out.push(ffi::egl::RENDERABLE_TYPE as c_int); 416 out.push(ffi::egl::OPENGL_BIT as c_int); 417 out.push(ffi::egl::CONFORMANT as c_int); 418 out.push(ffi::egl::OPENGL_BIT as c_int); 419 }, 420 (_, _) => unimplemented!(), 421 }; 422 423 if let Some(hardware_accelerated) = reqs.hardware_accelerated { 424 out.push(ffi::egl::CONFIG_CAVEAT as c_int); 425 out.push(if hardware_accelerated { 426 ffi::egl::NONE as c_int 427 } else { 428 ffi::egl::SLOW_CONFIG as c_int 429 }); 430 } 431 432 if let Some(color) = reqs.color_bits { 433 out.push(ffi::egl::RED_SIZE as c_int); 434 out.push((color / 3) as c_int); 435 out.push(ffi::egl::GREEN_SIZE as c_int); 436 out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int); 437 out.push(ffi::egl::BLUE_SIZE as c_int); 438 out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int); 439 } 440 441 if let Some(alpha) = reqs.alpha_bits { 442 out.push(ffi::egl::ALPHA_SIZE as c_int); 443 out.push(alpha as c_int); 444 } 445 446 if let Some(depth) = reqs.depth_bits { 447 out.push(ffi::egl::DEPTH_SIZE as c_int); 448 out.push(depth as c_int); 449 } 450 451 if let Some(stencil) = reqs.stencil_bits { 452 out.push(ffi::egl::STENCIL_SIZE as c_int); 453 out.push(stencil as c_int); 454 } 455 456 if let Some(true) = reqs.double_buffer { 457 return Err(CreationError::NoAvailablePixelFormat); 458 } 459 460 if let Some(multisampling) = reqs.multisampling { 461 out.push(ffi::egl::SAMPLES as c_int); 462 out.push(multisampling as c_int); 463 } 464 465 if reqs.stereoscopy { 466 return Err(CreationError::NoAvailablePixelFormat); 467 } 468 469 // FIXME: srgb is not taken into account 470 471 match reqs.release_behavior { 472 ReleaseBehavior::Flush => (), 473 ReleaseBehavior::None => { 474 // TODO: with EGL you need to manually set the behavior 475 unimplemented!() 476 }, 477 } 478 479 out.push(ffi::egl::NONE as c_int); 480 out 481 }; 482 483 // calling `eglChooseConfig` 484 let mut config_id = ptr::null(); // out param 485 let mut num_configs = 0; // out param 486 if egl::ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 { 487 return Err(CreationError::OsError(format!("eglChooseConfig failed"))); 488 } 489 if num_configs == 0 { 490 return Err(CreationError::NoAvailablePixelFormat); 491 } 492 493 // analyzing each config 494 macro_rules! attrib { 495 ($display:expr, $config:expr, $attr:expr) => ( 496 { 497 let mut value = 0; // out param 498 let res = egl::GetConfigAttrib($display, $config, 499 $attr as ffi::egl::types::EGLint, &mut value); 500 if res == 0 { 501 return Err(CreationError::OsError(format!("eglGetConfigAttrib failed"))); 502 } 503 value 504 } 505 ) 506 } 507 508 let desc = PixelFormat { 509 hardware_accelerated: attrib!(display, config_id, ffi::egl::CONFIG_CAVEAT) 510 != ffi::egl::SLOW_CONFIG as i32, 511 color_bits: attrib!(display, config_id, ffi::egl::RED_SIZE) as u8 + 512 attrib!(display, config_id, ffi::egl::BLUE_SIZE) as u8 + 513 attrib!(display, config_id, ffi::egl::GREEN_SIZE) as u8, 514 alpha_bits: attrib!(display, config_id, ffi::egl::ALPHA_SIZE) as u8, 515 depth_bits: attrib!(display, config_id, ffi::egl::DEPTH_SIZE) as u8, 516 stencil_bits: attrib!(display, config_id, ffi::egl::STENCIL_SIZE) as u8, 517 stereoscopy: false, 518 double_buffer: true, 519 multisampling: match attrib!(display, config_id, ffi::egl::SAMPLES) { 520 0 | 1 => None, 521 a => Some(a as u16), 522 }, 523 srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that 524 }; 525 526 Ok((config_id, desc)) 527 } 528 529 unsafe fn create_context(display: ffi::egl::types::EGLDisplay, 530 egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), 531 extensions: &[String], api: Api, version: (u8, u8), 532 config_id: ffi::egl::types::EGLConfig, gl_debug: bool, 533 gl_robustness: Robustness) 534 -> Result<ffi::egl::types::EGLContext, CreationError> 535 { 536 let mut context_attributes = Vec::with_capacity(10); 537 let mut flags = 0; 538 539 if egl_version >= &(1, 5) || extensions.iter().find(|s| s == &"EGL_KHR_create_context") 540 .is_some() 541 { 542 context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32); 543 context_attributes.push(version.0 as i32); 544 context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32); 545 context_attributes.push(version.1 as i32); 546 547 // handling robustness 548 let supports_robustness = egl_version >= &(1, 5) || 549 extensions.iter() 550 .find(|s| s == &"EGL_EXT_create_context_robustness") 551 .is_some(); 552 553 match gl_robustness { 554 Robustness::NotRobust => (), 555 556 Robustness::NoError => { 557 if extensions.iter().find(|s| s == &"EGL_KHR_create_context_no_error").is_some() { 558 context_attributes.push(ffi::egl::CONTEXT_OPENGL_NO_ERROR_KHR as c_int); 559 context_attributes.push(1); 560 } 561 }, 562 563 Robustness::RobustNoResetNotification => { 564 if supports_robustness { 565 context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 566 as c_int); 567 context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as c_int); 568 flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; 569 } else { 570 return Err(CreationError::RobustnessNotSupported); 571 } 572 }, 573 574 Robustness::TryRobustNoResetNotification => { 575 if supports_robustness { 576 context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 577 as c_int); 578 context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as c_int); 579 flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; 580 } 581 }, 582 583 Robustness::RobustLoseContextOnReset => { 584 if supports_robustness { 585 context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 586 as c_int); 587 context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as c_int); 588 flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; 589 } else { 590 return Err(CreationError::RobustnessNotSupported); 591 } 592 }, 593 594 Robustness::TryRobustLoseContextOnReset => { 595 if supports_robustness { 596 context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 597 as c_int); 598 context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as c_int); 599 flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int; 600 } 601 }, 602 } 603 604 if gl_debug { 605 if egl_version >= &(1, 5) { 606 context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32); 607 context_attributes.push(ffi::egl::TRUE as i32); 608 } 609 610 // TODO: using this flag sometimes generates an error 611 // there was a change in the specs that added this flag, so it may not be 612 // supported everywhere ; however it is not possible to know whether it is 613 // supported or not 614 //flags = flags | ffi::egl::CONTEXT_OPENGL_DEBUG_BIT_KHR as i32; 615 } 616 617 context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32); 618 context_attributes.push(flags); 619 620 } else if egl_version >= &(1, 3) && api == Api::OpenGlEs { 621 // robustness is not supported 622 match gl_robustness { 623 Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => { 624 return Err(CreationError::RobustnessNotSupported); 625 }, 626 _ => () 627 } 628 629 context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); 630 context_attributes.push(version.0 as i32); 631 } 632 633 context_attributes.push(ffi::egl::NONE as i32); 634 635 let context = egl::CreateContext(display, config_id, ptr::null(), 636 context_attributes.as_ptr()); 637 638 if context.is_null() { 639 match egl::GetError() as u32 { 640 ffi::egl::BAD_ATTRIBUTE => return Err(CreationError::OpenGlVersionNotSupported), 641 e => panic!("eglCreateContext failed: 0x{:x}", e), 642 } 643 } 644 645 Ok(context) 646 }