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