egl_context.c (29593B)
1 //======================================================================== 2 // GLFW 3.4 EGL - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 28 #include "internal.h" 29 30 #include <stdio.h> 31 #include <string.h> 32 #include <stdlib.h> 33 #include <assert.h> 34 35 36 // Return a description of the specified EGL error 37 // 38 static const char* getEGLErrorString(EGLint error) 39 { 40 switch (error) 41 { 42 case EGL_SUCCESS: 43 return "Success"; 44 case EGL_NOT_INITIALIZED: 45 return "EGL is not or could not be initialized"; 46 case EGL_BAD_ACCESS: 47 return "EGL cannot access a requested resource"; 48 case EGL_BAD_ALLOC: 49 return "EGL failed to allocate resources for the requested operation"; 50 case EGL_BAD_ATTRIBUTE: 51 return "An unrecognized attribute or attribute value was passed in the attribute list"; 52 case EGL_BAD_CONTEXT: 53 return "An EGLContext argument does not name a valid EGL rendering context"; 54 case EGL_BAD_CONFIG: 55 return "An EGLConfig argument does not name a valid EGL frame buffer configuration"; 56 case EGL_BAD_CURRENT_SURFACE: 57 return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid"; 58 case EGL_BAD_DISPLAY: 59 return "An EGLDisplay argument does not name a valid EGL display connection"; 60 case EGL_BAD_SURFACE: 61 return "An EGLSurface argument does not name a valid surface configured for GL rendering"; 62 case EGL_BAD_MATCH: 63 return "Arguments are inconsistent"; 64 case EGL_BAD_PARAMETER: 65 return "One or more argument values are invalid"; 66 case EGL_BAD_NATIVE_PIXMAP: 67 return "A NativePixmapType argument does not refer to a valid native pixmap"; 68 case EGL_BAD_NATIVE_WINDOW: 69 return "A NativeWindowType argument does not refer to a valid native window"; 70 case EGL_CONTEXT_LOST: 71 return "The application must destroy all contexts and reinitialise"; 72 default: 73 return "ERROR: UNKNOWN EGL ERROR"; 74 } 75 } 76 77 // Returns the specified attribute of the specified EGLConfig 78 // 79 static int getEGLConfigAttrib(EGLConfig config, int attrib) 80 { 81 int value; 82 eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); 83 return value; 84 } 85 86 // Return the EGLConfig most closely matching the specified hints 87 // 88 static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, 89 const _GLFWfbconfig* fbconfig, 90 EGLConfig* result) 91 { 92 EGLConfig* nativeConfigs; 93 _GLFWfbconfig* usableConfigs; 94 const _GLFWfbconfig* closest; 95 int i, nativeCount, usableCount, apiBit; 96 GLFWbool wrongApiAvailable = GLFW_FALSE; 97 98 if (ctxconfig->client == GLFW_OPENGL_ES_API) 99 { 100 if (ctxconfig->major == 1) 101 apiBit = EGL_OPENGL_ES_BIT; 102 else 103 apiBit = EGL_OPENGL_ES2_BIT; 104 } 105 else 106 apiBit = EGL_OPENGL_BIT; 107 108 if (fbconfig->stereo) 109 { 110 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported"); 111 return GLFW_FALSE; 112 } 113 114 eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); 115 if (!nativeCount) 116 { 117 _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); 118 return GLFW_FALSE; 119 } 120 121 nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig)); 122 eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); 123 124 usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig)); 125 usableCount = 0; 126 127 for (i = 0; i < nativeCount; i++) 128 { 129 const EGLConfig n = nativeConfigs[i]; 130 _GLFWfbconfig* u = usableConfigs + usableCount; 131 132 // Only consider RGB(A) EGLConfigs 133 if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER) 134 continue; 135 136 // Only consider window EGLConfigs 137 if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) 138 continue; 139 140 #if defined(_GLFW_X11) 141 if (_glfw.platform.platformID == GLFW_PLATFORM_X11) 142 { 143 XVisualInfo vi = {0}; 144 145 // Only consider EGLConfigs with associated Visuals 146 vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); 147 if (!vi.visualid) 148 continue; 149 150 if (fbconfig->transparent) 151 { 152 int count; 153 XVisualInfo* vis = 154 XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count); 155 if (vis) 156 { 157 u->transparent = _glfwIsVisualTransparentX11(vis[0].visual); 158 XFree(vis); 159 } 160 } 161 } 162 #endif // _GLFW_X11 163 164 if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit)) 165 { 166 wrongApiAvailable = GLFW_TRUE; 167 continue; 168 } 169 170 u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); 171 u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE); 172 u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE); 173 174 u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE); 175 u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE); 176 u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE); 177 178 #if defined(_GLFW_WAYLAND) 179 if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) 180 { 181 // NOTE: The wl_surface opaque region is no guarantee that its buffer 182 // is presented as opaque, if it also has an alpha channel 183 // HACK: If EGL_EXT_present_opaque is unavailable, ignore any config 184 // with an alpha channel to ensure the buffer is opaque 185 if (!_glfw.egl.EXT_present_opaque) 186 { 187 if (!fbconfig->transparent && u->alphaBits > 0) 188 continue; 189 } 190 } 191 #endif // _GLFW_WAYLAND 192 193 u->samples = getEGLConfigAttrib(n, EGL_SAMPLES); 194 u->doublebuffer = fbconfig->doublebuffer; 195 196 u->handle = (uintptr_t) n; 197 usableCount++; 198 } 199 200 closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount); 201 if (closest) 202 *result = (EGLConfig) closest->handle; 203 else 204 { 205 if (wrongApiAvailable) 206 { 207 if (ctxconfig->client == GLFW_OPENGL_ES_API) 208 { 209 if (ctxconfig->major == 1) 210 { 211 _glfwInputError(GLFW_API_UNAVAILABLE, 212 "EGL: Failed to find support for OpenGL ES 1.x"); 213 } 214 else 215 { 216 _glfwInputError(GLFW_API_UNAVAILABLE, 217 "EGL: Failed to find support for OpenGL ES 2 or later"); 218 } 219 } 220 else 221 { 222 _glfwInputError(GLFW_API_UNAVAILABLE, 223 "EGL: Failed to find support for OpenGL"); 224 } 225 } 226 else 227 { 228 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, 229 "EGL: Failed to find a suitable EGLConfig"); 230 } 231 } 232 233 _glfw_free(nativeConfigs); 234 _glfw_free(usableConfigs); 235 236 return closest != NULL; 237 } 238 239 static void makeContextCurrentEGL(_GLFWwindow* window) 240 { 241 if (window) 242 { 243 if (!eglMakeCurrent(_glfw.egl.display, 244 window->context.egl.surface, 245 window->context.egl.surface, 246 window->context.egl.handle)) 247 { 248 _glfwInputError(GLFW_PLATFORM_ERROR, 249 "EGL: Failed to make context current: %s", 250 getEGLErrorString(eglGetError())); 251 return; 252 } 253 } 254 else 255 { 256 if (!eglMakeCurrent(_glfw.egl.display, 257 EGL_NO_SURFACE, 258 EGL_NO_SURFACE, 259 EGL_NO_CONTEXT)) 260 { 261 _glfwInputError(GLFW_PLATFORM_ERROR, 262 "EGL: Failed to clear current context: %s", 263 getEGLErrorString(eglGetError())); 264 return; 265 } 266 } 267 268 _glfwPlatformSetTls(&_glfw.contextSlot, window); 269 } 270 271 static void swapBuffersEGL(_GLFWwindow* window) 272 { 273 if (window != _glfwPlatformGetTls(&_glfw.contextSlot)) 274 { 275 _glfwInputError(GLFW_PLATFORM_ERROR, 276 "EGL: The context must be current on the calling thread when swapping buffers"); 277 return; 278 } 279 280 #if defined(_GLFW_WAYLAND) 281 if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) 282 { 283 // NOTE: Swapping buffers on a hidden window on Wayland makes it visible 284 if (!window->wl.visible) 285 return; 286 } 287 #endif 288 289 eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); 290 } 291 292 static void swapIntervalEGL(int interval) 293 { 294 eglSwapInterval(_glfw.egl.display, interval); 295 } 296 297 static int extensionSupportedEGL(const char* extension) 298 { 299 const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); 300 if (extensions) 301 { 302 if (_glfwStringInExtensionString(extension, extensions)) 303 return GLFW_TRUE; 304 } 305 306 return GLFW_FALSE; 307 } 308 309 static GLFWglproc getProcAddressEGL(const char* procname) 310 { 311 _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); 312 assert(window != NULL); 313 314 if (window->context.egl.client) 315 { 316 GLFWglproc proc = (GLFWglproc) 317 _glfwPlatformGetModuleSymbol(window->context.egl.client, procname); 318 if (proc) 319 return proc; 320 } 321 322 return eglGetProcAddress(procname); 323 } 324 325 static void destroyContextEGL(_GLFWwindow* window) 326 { 327 // NOTE: Do not unload libGL.so.1 while the X11 display is still open, 328 // as it will make XCloseDisplay segfault 329 if (_glfw.platform.platformID != GLFW_PLATFORM_X11 || 330 window->context.client != GLFW_OPENGL_API) 331 { 332 if (window->context.egl.client) 333 { 334 _glfwPlatformFreeModule(window->context.egl.client); 335 window->context.egl.client = NULL; 336 } 337 } 338 339 if (window->context.egl.surface) 340 { 341 eglDestroySurface(_glfw.egl.display, window->context.egl.surface); 342 window->context.egl.surface = EGL_NO_SURFACE; 343 } 344 345 if (window->context.egl.handle) 346 { 347 eglDestroyContext(_glfw.egl.display, window->context.egl.handle); 348 window->context.egl.handle = EGL_NO_CONTEXT; 349 } 350 } 351 352 353 ////////////////////////////////////////////////////////////////////////// 354 ////// GLFW internal API ////// 355 ////////////////////////////////////////////////////////////////////////// 356 357 // Initialize EGL 358 // 359 GLFWbool _glfwInitEGL(void) 360 { 361 int i; 362 EGLint* attribs = NULL; 363 const char* extensions; 364 const char* sonames[] = 365 { 366 #if defined(_GLFW_EGL_LIBRARY) 367 _GLFW_EGL_LIBRARY, 368 #elif defined(_GLFW_WIN32) 369 "libEGL.dll", 370 "EGL.dll", 371 #elif defined(_GLFW_COCOA) 372 "libEGL.dylib", 373 #elif defined(__CYGWIN__) 374 "libEGL-1.so", 375 #elif defined(__OpenBSD__) || defined(__NetBSD__) 376 "libEGL.so", 377 #else 378 "libEGL.so.1", 379 #endif 380 NULL 381 }; 382 383 if (_glfw.egl.handle) 384 return GLFW_TRUE; 385 386 for (i = 0; sonames[i]; i++) 387 { 388 _glfw.egl.handle = _glfwPlatformLoadModule(sonames[i]); 389 if (_glfw.egl.handle) 390 break; 391 } 392 393 if (!_glfw.egl.handle) 394 { 395 _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found"); 396 return GLFW_FALSE; 397 } 398 399 _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0); 400 401 _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib) 402 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigAttrib"); 403 _glfw.egl.GetConfigs = (PFN_eglGetConfigs) 404 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigs"); 405 _glfw.egl.GetDisplay = (PFN_eglGetDisplay) 406 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetDisplay"); 407 _glfw.egl.GetError = (PFN_eglGetError) 408 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetError"); 409 _glfw.egl.Initialize = (PFN_eglInitialize) 410 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglInitialize"); 411 _glfw.egl.Terminate = (PFN_eglTerminate) 412 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglTerminate"); 413 _glfw.egl.BindAPI = (PFN_eglBindAPI) 414 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglBindAPI"); 415 _glfw.egl.CreateContext = (PFN_eglCreateContext) 416 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateContext"); 417 _glfw.egl.DestroySurface = (PFN_eglDestroySurface) 418 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroySurface"); 419 _glfw.egl.DestroyContext = (PFN_eglDestroyContext) 420 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroyContext"); 421 _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface) 422 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateWindowSurface"); 423 _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent) 424 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglMakeCurrent"); 425 _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers) 426 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapBuffers"); 427 _glfw.egl.SwapInterval = (PFN_eglSwapInterval) 428 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapInterval"); 429 _glfw.egl.QueryString = (PFN_eglQueryString) 430 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString"); 431 _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress) 432 _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress"); 433 434 if (!_glfw.egl.GetConfigAttrib || 435 !_glfw.egl.GetConfigs || 436 !_glfw.egl.GetDisplay || 437 !_glfw.egl.GetError || 438 !_glfw.egl.Initialize || 439 !_glfw.egl.Terminate || 440 !_glfw.egl.BindAPI || 441 !_glfw.egl.CreateContext || 442 !_glfw.egl.DestroySurface || 443 !_glfw.egl.DestroyContext || 444 !_glfw.egl.CreateWindowSurface || 445 !_glfw.egl.MakeCurrent || 446 !_glfw.egl.SwapBuffers || 447 !_glfw.egl.SwapInterval || 448 !_glfw.egl.QueryString || 449 !_glfw.egl.GetProcAddress) 450 { 451 _glfwInputError(GLFW_PLATFORM_ERROR, 452 "EGL: Failed to load required entry points"); 453 454 _glfwTerminateEGL(); 455 return GLFW_FALSE; 456 } 457 458 extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); 459 if (extensions && eglGetError() == EGL_SUCCESS) 460 _glfw.egl.EXT_client_extensions = GLFW_TRUE; 461 462 if (_glfw.egl.EXT_client_extensions) 463 { 464 _glfw.egl.EXT_platform_base = 465 _glfwStringInExtensionString("EGL_EXT_platform_base", extensions); 466 _glfw.egl.EXT_platform_x11 = 467 _glfwStringInExtensionString("EGL_EXT_platform_x11", extensions); 468 _glfw.egl.EXT_platform_wayland = 469 _glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions); 470 _glfw.egl.ANGLE_platform_angle = 471 _glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions); 472 _glfw.egl.ANGLE_platform_angle_opengl = 473 _glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions); 474 _glfw.egl.ANGLE_platform_angle_d3d = 475 _glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions); 476 _glfw.egl.ANGLE_platform_angle_vulkan = 477 _glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions); 478 _glfw.egl.ANGLE_platform_angle_metal = 479 _glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions); 480 } 481 482 if (_glfw.egl.EXT_platform_base) 483 { 484 _glfw.egl.GetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) 485 eglGetProcAddress("eglGetPlatformDisplayEXT"); 486 _glfw.egl.CreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) 487 eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); 488 } 489 490 _glfw.egl.platform = _glfw.platform.getEGLPlatform(&attribs); 491 if (_glfw.egl.platform) 492 { 493 _glfw.egl.display = 494 eglGetPlatformDisplayEXT(_glfw.egl.platform, 495 _glfw.platform.getEGLNativeDisplay(), 496 attribs); 497 } 498 else 499 _glfw.egl.display = eglGetDisplay(_glfw.platform.getEGLNativeDisplay()); 500 501 _glfw_free(attribs); 502 503 if (_glfw.egl.display == EGL_NO_DISPLAY) 504 { 505 _glfwInputError(GLFW_API_UNAVAILABLE, 506 "EGL: Failed to get EGL display: %s", 507 getEGLErrorString(eglGetError())); 508 509 _glfwTerminateEGL(); 510 return GLFW_FALSE; 511 } 512 513 if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) 514 { 515 _glfwInputError(GLFW_API_UNAVAILABLE, 516 "EGL: Failed to initialize EGL: %s", 517 getEGLErrorString(eglGetError())); 518 519 _glfwTerminateEGL(); 520 return GLFW_FALSE; 521 } 522 523 _glfw.egl.KHR_create_context = 524 extensionSupportedEGL("EGL_KHR_create_context"); 525 _glfw.egl.KHR_create_context_no_error = 526 extensionSupportedEGL("EGL_KHR_create_context_no_error"); 527 _glfw.egl.KHR_gl_colorspace = 528 extensionSupportedEGL("EGL_KHR_gl_colorspace"); 529 _glfw.egl.KHR_get_all_proc_addresses = 530 extensionSupportedEGL("EGL_KHR_get_all_proc_addresses"); 531 _glfw.egl.KHR_context_flush_control = 532 extensionSupportedEGL("EGL_KHR_context_flush_control"); 533 _glfw.egl.EXT_present_opaque = 534 extensionSupportedEGL("EGL_EXT_present_opaque"); 535 536 return GLFW_TRUE; 537 } 538 539 // Terminate EGL 540 // 541 void _glfwTerminateEGL(void) 542 { 543 if (_glfw.egl.display) 544 { 545 eglTerminate(_glfw.egl.display); 546 _glfw.egl.display = EGL_NO_DISPLAY; 547 } 548 549 if (_glfw.egl.handle) 550 { 551 _glfwPlatformFreeModule(_glfw.egl.handle); 552 _glfw.egl.handle = NULL; 553 } 554 } 555 556 #define SET_ATTRIB(a, v) \ 557 { \ 558 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ 559 attribs[index++] = a; \ 560 attribs[index++] = v; \ 561 } 562 563 // Create the OpenGL or OpenGL ES context 564 // 565 GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, 566 const _GLFWctxconfig* ctxconfig, 567 const _GLFWfbconfig* fbconfig) 568 { 569 EGLint attribs[40]; 570 EGLConfig config; 571 EGLContext share = NULL; 572 EGLNativeWindowType native; 573 int index = 0; 574 575 if (!_glfw.egl.display) 576 { 577 _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available"); 578 return GLFW_FALSE; 579 } 580 581 if (ctxconfig->share) 582 share = ctxconfig->share->context.egl.handle; 583 584 if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) 585 return GLFW_FALSE; 586 587 if (ctxconfig->client == GLFW_OPENGL_ES_API) 588 { 589 if (!eglBindAPI(EGL_OPENGL_ES_API)) 590 { 591 _glfwInputError(GLFW_API_UNAVAILABLE, 592 "EGL: Failed to bind OpenGL ES: %s", 593 getEGLErrorString(eglGetError())); 594 return GLFW_FALSE; 595 } 596 } 597 else 598 { 599 if (!eglBindAPI(EGL_OPENGL_API)) 600 { 601 _glfwInputError(GLFW_API_UNAVAILABLE, 602 "EGL: Failed to bind OpenGL: %s", 603 getEGLErrorString(eglGetError())); 604 return GLFW_FALSE; 605 } 606 } 607 608 if (_glfw.egl.KHR_create_context) 609 { 610 int mask = 0, flags = 0; 611 612 if (ctxconfig->client == GLFW_OPENGL_API) 613 { 614 if (ctxconfig->forward) 615 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; 616 617 if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) 618 mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; 619 else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) 620 mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; 621 } 622 623 if (ctxconfig->debug) 624 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; 625 626 if (ctxconfig->robustness) 627 { 628 if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) 629 { 630 SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, 631 EGL_NO_RESET_NOTIFICATION_KHR); 632 } 633 else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) 634 { 635 SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, 636 EGL_LOSE_CONTEXT_ON_RESET_KHR); 637 } 638 639 flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; 640 } 641 642 if (ctxconfig->major != 1 || ctxconfig->minor != 0) 643 { 644 SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); 645 SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); 646 } 647 648 if (ctxconfig->noerror) 649 { 650 if (_glfw.egl.KHR_create_context_no_error) 651 SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE); 652 } 653 654 if (mask) 655 SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); 656 657 if (flags) 658 SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags); 659 } 660 else 661 { 662 if (ctxconfig->client == GLFW_OPENGL_ES_API) 663 SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); 664 } 665 666 if (_glfw.egl.KHR_context_flush_control) 667 { 668 if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) 669 { 670 SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 671 EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR); 672 } 673 else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) 674 { 675 SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 676 EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); 677 } 678 } 679 680 SET_ATTRIB(EGL_NONE, EGL_NONE); 681 682 window->context.egl.handle = eglCreateContext(_glfw.egl.display, 683 config, share, attribs); 684 685 if (window->context.egl.handle == EGL_NO_CONTEXT) 686 { 687 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 688 "EGL: Failed to create context: %s", 689 getEGLErrorString(eglGetError())); 690 return GLFW_FALSE; 691 } 692 693 // Set up attributes for surface creation 694 index = 0; 695 696 if (fbconfig->sRGB) 697 { 698 if (_glfw.egl.KHR_gl_colorspace) 699 SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); 700 } 701 702 if (!fbconfig->doublebuffer) 703 SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); 704 705 if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND) 706 { 707 if (_glfw.egl.EXT_present_opaque) 708 SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent); 709 } 710 711 SET_ATTRIB(EGL_NONE, EGL_NONE); 712 713 native = _glfw.platform.getEGLNativeWindow(window); 714 // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT 715 // despite reporting EGL_EXT_platform_base 716 if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE) 717 { 718 window->context.egl.surface = 719 eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs); 720 } 721 else 722 { 723 window->context.egl.surface = 724 eglCreateWindowSurface(_glfw.egl.display, config, native, attribs); 725 } 726 727 if (window->context.egl.surface == EGL_NO_SURFACE) 728 { 729 _glfwInputError(GLFW_PLATFORM_ERROR, 730 "EGL: Failed to create window surface: %s", 731 getEGLErrorString(eglGetError())); 732 return GLFW_FALSE; 733 } 734 735 window->context.egl.config = config; 736 737 // Load the appropriate client library 738 if (!_glfw.egl.KHR_get_all_proc_addresses) 739 { 740 int i; 741 const char** sonames; 742 const char* es1sonames[] = 743 { 744 #if defined(_GLFW_GLESV1_LIBRARY) 745 _GLFW_GLESV1_LIBRARY, 746 #elif defined(_GLFW_WIN32) 747 "GLESv1_CM.dll", 748 "libGLES_CM.dll", 749 #elif defined(_GLFW_COCOA) 750 "libGLESv1_CM.dylib", 751 #elif defined(__OpenBSD__) || defined(__NetBSD__) 752 "libGLESv1_CM.so", 753 #else 754 "libGLESv1_CM.so.1", 755 "libGLES_CM.so.1", 756 #endif 757 NULL 758 }; 759 const char* es2sonames[] = 760 { 761 #if defined(_GLFW_GLESV2_LIBRARY) 762 _GLFW_GLESV2_LIBRARY, 763 #elif defined(_GLFW_WIN32) 764 "GLESv2.dll", 765 "libGLESv2.dll", 766 #elif defined(_GLFW_COCOA) 767 "libGLESv2.dylib", 768 #elif defined(__CYGWIN__) 769 "libGLESv2-2.so", 770 #elif defined(__OpenBSD__) || defined(__NetBSD__) 771 "libGLESv2.so", 772 #else 773 "libGLESv2.so.2", 774 #endif 775 NULL 776 }; 777 const char* glsonames[] = 778 { 779 #if defined(_GLFW_OPENGL_LIBRARY) 780 _GLFW_OPENGL_LIBRARY, 781 #elif defined(_GLFW_WIN32) 782 #elif defined(_GLFW_COCOA) 783 #elif defined(__OpenBSD__) || defined(__NetBSD__) 784 "libGL.so", 785 #else 786 "libOpenGL.so.0", 787 "libGL.so.1", 788 #endif 789 NULL 790 }; 791 792 if (ctxconfig->client == GLFW_OPENGL_ES_API) 793 { 794 if (ctxconfig->major == 1) 795 sonames = es1sonames; 796 else 797 sonames = es2sonames; 798 } 799 else 800 sonames = glsonames; 801 802 for (i = 0; sonames[i]; i++) 803 { 804 // HACK: Match presence of lib prefix to increase chance of finding 805 // a matching pair in the jungle that is Win32 EGL/GLES 806 if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0)) 807 continue; 808 809 window->context.egl.client = _glfwPlatformLoadModule(sonames[i]); 810 if (window->context.egl.client) 811 break; 812 } 813 814 if (!window->context.egl.client) 815 { 816 _glfwInputError(GLFW_API_UNAVAILABLE, 817 "EGL: Failed to load client library"); 818 return GLFW_FALSE; 819 } 820 } 821 822 window->context.makeCurrent = makeContextCurrentEGL; 823 window->context.swapBuffers = swapBuffersEGL; 824 window->context.swapInterval = swapIntervalEGL; 825 window->context.extensionSupported = extensionSupportedEGL; 826 window->context.getProcAddress = getProcAddressEGL; 827 window->context.destroy = destroyContextEGL; 828 829 return GLFW_TRUE; 830 } 831 832 #undef SET_ATTRIB 833 834 // Returns the Visual and depth of the chosen EGLConfig 835 // 836 #if defined(_GLFW_X11) 837 GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, 838 const _GLFWctxconfig* ctxconfig, 839 const _GLFWfbconfig* fbconfig, 840 Visual** visual, int* depth) 841 { 842 XVisualInfo* result; 843 XVisualInfo desired; 844 EGLConfig native; 845 EGLint visualID = 0, count = 0; 846 const long vimask = VisualScreenMask | VisualIDMask; 847 848 if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) 849 return GLFW_FALSE; 850 851 eglGetConfigAttrib(_glfw.egl.display, native, 852 EGL_NATIVE_VISUAL_ID, &visualID); 853 854 desired.screen = _glfw.x11.screen; 855 desired.visualid = visualID; 856 857 result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count); 858 if (!result) 859 { 860 _glfwInputError(GLFW_PLATFORM_ERROR, 861 "EGL: Failed to retrieve Visual for EGLConfig"); 862 return GLFW_FALSE; 863 } 864 865 *visual = result->visual; 866 *depth = result->depth; 867 868 XFree(result); 869 return GLFW_TRUE; 870 } 871 #endif // _GLFW_X11 872 873 874 ////////////////////////////////////////////////////////////////////////// 875 ////// GLFW native API ////// 876 ////////////////////////////////////////////////////////////////////////// 877 878 GLFWAPI EGLDisplay glfwGetEGLDisplay(void) 879 { 880 _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY); 881 return _glfw.egl.display; 882 } 883 884 GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) 885 { 886 _GLFWwindow* window = (_GLFWwindow*) handle; 887 _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); 888 889 if (window->context.source != GLFW_EGL_CONTEXT_API) 890 { 891 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 892 return EGL_NO_CONTEXT; 893 } 894 895 return window->context.egl.handle; 896 } 897 898 GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) 899 { 900 _GLFWwindow* window = (_GLFWwindow*) handle; 901 _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); 902 903 if (window->context.source != GLFW_EGL_CONTEXT_API) 904 { 905 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 906 return EGL_NO_SURFACE; 907 } 908 909 return window->context.egl.surface; 910 } 911