1 //========================================================================
2 // GLFW 3.3 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 // Please use C89 style variable declarations in this file because VS 2010
28 //========================================================================
29 
30 #include "internal.h"
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <assert.h>
36 
37 
38 // Return a description of the specified EGL error
39 //
getEGLErrorString(EGLint error)40 static const char* getEGLErrorString(EGLint error)
41 {
42     switch (error)
43     {
44         case EGL_SUCCESS:
45             return "Success";
46         case EGL_NOT_INITIALIZED:
47             return "EGL is not or could not be initialized";
48         case EGL_BAD_ACCESS:
49             return "EGL cannot access a requested resource";
50         case EGL_BAD_ALLOC:
51             return "EGL failed to allocate resources for the requested operation";
52         case EGL_BAD_ATTRIBUTE:
53             return "An unrecognized attribute or attribute value was passed in the attribute list";
54         case EGL_BAD_CONTEXT:
55             return "An EGLContext argument does not name a valid EGL rendering context";
56         case EGL_BAD_CONFIG:
57             return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
58         case EGL_BAD_CURRENT_SURFACE:
59             return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
60         case EGL_BAD_DISPLAY:
61             return "An EGLDisplay argument does not name a valid EGL display connection";
62         case EGL_BAD_SURFACE:
63             return "An EGLSurface argument does not name a valid surface configured for GL rendering";
64         case EGL_BAD_MATCH:
65             return "Arguments are inconsistent";
66         case EGL_BAD_PARAMETER:
67             return "One or more argument values are invalid";
68         case EGL_BAD_NATIVE_PIXMAP:
69             return "A NativePixmapType argument does not refer to a valid native pixmap";
70         case EGL_BAD_NATIVE_WINDOW:
71             return "A NativeWindowType argument does not refer to a valid native window";
72         case EGL_CONTEXT_LOST:
73             return "The application must destroy all contexts and reinitialise";
74         default:
75             return "ERROR: UNKNOWN EGL ERROR";
76     }
77 }
78 
79 // Returns the specified attribute of the specified EGLConfig
80 //
getEGLConfigAttrib(EGLConfig config,int attrib)81 static int getEGLConfigAttrib(EGLConfig config, int attrib)
82 {
83     int value;
84     eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
85     return value;
86 }
87 
88 // Return the EGLConfig most closely matching the specified hints
89 //
chooseEGLConfig(const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * desired,EGLConfig * result)90 static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
91                                 const _GLFWfbconfig* desired,
92                                 EGLConfig* result)
93 {
94     EGLConfig* nativeConfigs;
95     _GLFWfbconfig* usableConfigs;
96     const _GLFWfbconfig* closest;
97     int i, nativeCount, usableCount;
98 
99     eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
100     if (!nativeCount)
101     {
102         _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
103         return GLFW_FALSE;
104     }
105 
106     nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
107     eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
108 
109     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
110     usableCount = 0;
111 
112     for (i = 0;  i < nativeCount;  i++)
113     {
114         const EGLConfig n = nativeConfigs[i];
115         _GLFWfbconfig* u = usableConfigs + usableCount;
116 
117         // Only consider RGB(A) EGLConfigs
118         if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
119             continue;
120 
121         // Only consider window EGLConfigs
122         if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
123             continue;
124 
125 #if defined(_GLFW_X11)
126         {
127             XVisualInfo vi = {0};
128 
129             // Only consider EGLConfigs with associated Visuals
130             vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
131             if (!vi.visualid)
132                 continue;
133 
134             if (desired->transparent)
135             {
136                 int count;
137                 XVisualInfo* vis =
138                     XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
139                 if (vis)
140                 {
141                     u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
142                     XFree(vis);
143                 }
144             }
145         }
146 #endif // _GLFW_X11
147 
148         if (ctxconfig->client == GLFW_OPENGL_ES_API)
149         {
150             if (ctxconfig->major == 1)
151             {
152                 if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
153                     continue;
154             }
155             else
156             {
157                 if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
158                     continue;
159             }
160         }
161         else if (ctxconfig->client == GLFW_OPENGL_API)
162         {
163             if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
164                 continue;
165         }
166 
167         u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
168         u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
169         u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
170 
171         u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
172         u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
173         u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
174 
175         u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
176         u->doublebuffer = GLFW_TRUE;
177 
178         u->handle = (uintptr_t) n;
179         usableCount++;
180     }
181 
182     closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
183     if (closest)
184         *result = (EGLConfig) closest->handle;
185 
186     free(nativeConfigs);
187     free(usableConfigs);
188 
189     return closest != NULL;
190 }
191 
makeContextCurrentEGL(_GLFWwindow * window)192 static void makeContextCurrentEGL(_GLFWwindow* window)
193 {
194     if (window)
195     {
196         if (!eglMakeCurrent(_glfw.egl.display,
197                             window->context.egl.surface,
198                             window->context.egl.surface,
199                             window->context.egl.handle))
200         {
201             _glfwInputError(GLFW_PLATFORM_ERROR,
202                             "EGL: Failed to make context current: %s",
203                             getEGLErrorString(eglGetError()));
204             return;
205         }
206     }
207     else
208     {
209         if (!eglMakeCurrent(_glfw.egl.display,
210                             EGL_NO_SURFACE,
211                             EGL_NO_SURFACE,
212                             EGL_NO_CONTEXT))
213         {
214             _glfwInputError(GLFW_PLATFORM_ERROR,
215                             "EGL: Failed to clear current context: %s",
216                             getEGLErrorString(eglGetError()));
217             return;
218         }
219     }
220 
221     _glfwPlatformSetTls(&_glfw.contextSlot, window);
222 }
223 
swapBuffersEGL(_GLFWwindow * window)224 static void swapBuffersEGL(_GLFWwindow* window)
225 {
226     if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
227     {
228         _glfwInputError(GLFW_PLATFORM_ERROR,
229                         "EGL: The context must be current on the calling thread when swapping buffers");
230         return;
231     }
232 
233     eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
234 }
235 
swapIntervalEGL(int interval)236 static void swapIntervalEGL(int interval)
237 {
238     eglSwapInterval(_glfw.egl.display, interval);
239 }
240 
extensionSupportedEGL(const char * extension)241 static int extensionSupportedEGL(const char* extension)
242 {
243     const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
244     if (extensions)
245     {
246         if (_glfwStringInExtensionString(extension, extensions))
247             return GLFW_TRUE;
248     }
249 
250     return GLFW_FALSE;
251 }
252 
getProcAddressEGL(const char * procname)253 static GLFWglproc getProcAddressEGL(const char* procname)
254 {
255     _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
256 
257     if (window->context.egl.client)
258     {
259         GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
260                                                    procname);
261         if (proc)
262             return proc;
263     }
264 
265     return eglGetProcAddress(procname);
266 }
267 
destroyContextEGL(_GLFWwindow * window)268 static void destroyContextEGL(_GLFWwindow* window)
269 {
270 #if defined(_GLFW_X11)
271     // NOTE: Do not unload libGL.so.1 while the X11 display is still open,
272     //       as it will make XCloseDisplay segfault
273     if (window->context.client != GLFW_OPENGL_API)
274 #endif // _GLFW_X11
275     {
276         if (window->context.egl.client)
277         {
278             _glfw_dlclose(window->context.egl.client);
279             window->context.egl.client = NULL;
280         }
281     }
282 
283     if (window->context.egl.surface)
284     {
285         eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
286         window->context.egl.surface = EGL_NO_SURFACE;
287     }
288 
289     if (window->context.egl.handle)
290     {
291         eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
292         window->context.egl.handle = EGL_NO_CONTEXT;
293     }
294 }
295 
296 
297 //////////////////////////////////////////////////////////////////////////
298 //////                       GLFW internal API                      //////
299 //////////////////////////////////////////////////////////////////////////
300 
301 // Initialize EGL
302 //
_glfwInitEGL(void)303 GLFWbool _glfwInitEGL(void)
304 {
305     int i;
306     const char* sonames[] =
307     {
308 #if defined(_GLFW_EGL_LIBRARY)
309         _GLFW_EGL_LIBRARY,
310 #elif defined(_GLFW_WIN32)
311         "libEGL.dll",
312         "EGL.dll",
313 #elif defined(_GLFW_COCOA)
314         "libEGL.dylib",
315 #elif defined(__CYGWIN__)
316         "libEGL-1.so",
317 #else
318         "libEGL.so.1",
319 #endif
320         NULL
321     };
322 
323     if (_glfw.egl.handle)
324         return GLFW_TRUE;
325 
326     for (i = 0;  sonames[i];  i++)
327     {
328         _glfw.egl.handle = _glfw_dlopen(sonames[i]);
329         if (_glfw.egl.handle)
330             break;
331     }
332 
333     if (!_glfw.egl.handle)
334     {
335         _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
336         return GLFW_FALSE;
337     }
338 
339     _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
340 
341     _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
342         _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
343     _glfw.egl.GetConfigs = (PFN_eglGetConfigs)
344         _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
345     _glfw.egl.GetDisplay = (PFN_eglGetDisplay)
346         _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
347     _glfw.egl.GetError = (PFN_eglGetError)
348         _glfw_dlsym(_glfw.egl.handle, "eglGetError");
349     _glfw.egl.Initialize = (PFN_eglInitialize)
350         _glfw_dlsym(_glfw.egl.handle, "eglInitialize");
351     _glfw.egl.Terminate = (PFN_eglTerminate)
352         _glfw_dlsym(_glfw.egl.handle, "eglTerminate");
353     _glfw.egl.BindAPI = (PFN_eglBindAPI)
354         _glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
355     _glfw.egl.CreateContext = (PFN_eglCreateContext)
356         _glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
357     _glfw.egl.DestroySurface = (PFN_eglDestroySurface)
358         _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
359     _glfw.egl.DestroyContext = (PFN_eglDestroyContext)
360         _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
361     _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
362         _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
363     _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
364         _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
365     _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
366         _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
367     _glfw.egl.SwapInterval = (PFN_eglSwapInterval)
368         _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
369     _glfw.egl.QueryString = (PFN_eglQueryString)
370         _glfw_dlsym(_glfw.egl.handle, "eglQueryString");
371     _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
372         _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
373 
374     if (!_glfw.egl.GetConfigAttrib ||
375         !_glfw.egl.GetConfigs ||
376         !_glfw.egl.GetDisplay ||
377         !_glfw.egl.GetError ||
378         !_glfw.egl.Initialize ||
379         !_glfw.egl.Terminate ||
380         !_glfw.egl.BindAPI ||
381         !_glfw.egl.CreateContext ||
382         !_glfw.egl.DestroySurface ||
383         !_glfw.egl.DestroyContext ||
384         !_glfw.egl.CreateWindowSurface ||
385         !_glfw.egl.MakeCurrent ||
386         !_glfw.egl.SwapBuffers ||
387         !_glfw.egl.SwapInterval ||
388         !_glfw.egl.QueryString ||
389         !_glfw.egl.GetProcAddress)
390     {
391         _glfwInputError(GLFW_PLATFORM_ERROR,
392                         "EGL: Failed to load required entry points");
393 
394         _glfwTerminateEGL();
395         return GLFW_FALSE;
396     }
397 
398     _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
399     if (_glfw.egl.display == EGL_NO_DISPLAY)
400     {
401         _glfwInputError(GLFW_API_UNAVAILABLE,
402                         "EGL: Failed to get EGL display: %s",
403                         getEGLErrorString(eglGetError()));
404 
405         _glfwTerminateEGL();
406         return GLFW_FALSE;
407     }
408 
409     if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
410     {
411         _glfwInputError(GLFW_API_UNAVAILABLE,
412                         "EGL: Failed to initialize EGL: %s",
413                         getEGLErrorString(eglGetError()));
414 
415         _glfwTerminateEGL();
416         return GLFW_FALSE;
417     }
418 
419     _glfw.egl.KHR_create_context =
420         extensionSupportedEGL("EGL_KHR_create_context");
421     _glfw.egl.KHR_create_context_no_error =
422         extensionSupportedEGL("EGL_KHR_create_context_no_error");
423     _glfw.egl.KHR_gl_colorspace =
424         extensionSupportedEGL("EGL_KHR_gl_colorspace");
425     _glfw.egl.KHR_get_all_proc_addresses =
426         extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
427     _glfw.egl.KHR_context_flush_control =
428         extensionSupportedEGL("EGL_KHR_context_flush_control");
429 
430     return GLFW_TRUE;
431 }
432 
433 // Terminate EGL
434 //
_glfwTerminateEGL(void)435 void _glfwTerminateEGL(void)
436 {
437     if (_glfw.egl.display)
438     {
439         eglTerminate(_glfw.egl.display);
440         _glfw.egl.display = EGL_NO_DISPLAY;
441     }
442 
443     if (_glfw.egl.handle)
444     {
445         _glfw_dlclose(_glfw.egl.handle);
446         _glfw.egl.handle = NULL;
447     }
448 }
449 
450 #define setAttrib(a, v) \
451 { \
452     assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
453     attribs[index++] = a; \
454     attribs[index++] = v; \
455 }
456 
457 // Create the OpenGL or OpenGL ES context
458 //
_glfwCreateContextEGL(_GLFWwindow * window,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)459 GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
460                                const _GLFWctxconfig* ctxconfig,
461                                const _GLFWfbconfig* fbconfig)
462 {
463     EGLint attribs[40];
464     EGLConfig config;
465     EGLContext share = NULL;
466     int index = 0;
467 
468     if (!_glfw.egl.display)
469     {
470         _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
471         return GLFW_FALSE;
472     }
473 
474     if (ctxconfig->share)
475         share = ctxconfig->share->context.egl.handle;
476 
477     if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
478     {
479         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
480                         "EGL: Failed to find a suitable EGLConfig");
481         return GLFW_FALSE;
482     }
483 
484     if (ctxconfig->client == GLFW_OPENGL_ES_API)
485     {
486         if (!eglBindAPI(EGL_OPENGL_ES_API))
487         {
488             _glfwInputError(GLFW_API_UNAVAILABLE,
489                             "EGL: Failed to bind OpenGL ES: %s",
490                             getEGLErrorString(eglGetError()));
491             return GLFW_FALSE;
492         }
493     }
494     else
495     {
496         if (!eglBindAPI(EGL_OPENGL_API))
497         {
498             _glfwInputError(GLFW_API_UNAVAILABLE,
499                             "EGL: Failed to bind OpenGL: %s",
500                             getEGLErrorString(eglGetError()));
501             return GLFW_FALSE;
502         }
503     }
504 
505     if (_glfw.egl.KHR_create_context)
506     {
507         int mask = 0, flags = 0;
508 
509         if (ctxconfig->client == GLFW_OPENGL_API)
510         {
511             if (ctxconfig->forward)
512                 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
513 
514             if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
515                 mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
516             else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
517                 mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
518         }
519 
520         if (ctxconfig->debug)
521             flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
522 
523         if (ctxconfig->robustness)
524         {
525             if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
526             {
527                 setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
528                           EGL_NO_RESET_NOTIFICATION_KHR);
529             }
530             else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
531             {
532                 setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
533                           EGL_LOSE_CONTEXT_ON_RESET_KHR);
534             }
535 
536             flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
537         }
538 
539         if (ctxconfig->noerror)
540         {
541             if (_glfw.egl.KHR_create_context_no_error)
542                 setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
543         }
544 
545         if (ctxconfig->major != 1 || ctxconfig->minor != 0)
546         {
547             setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
548             setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
549         }
550 
551         if (mask)
552             setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
553 
554         if (flags)
555             setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
556     }
557     else
558     {
559         if (ctxconfig->client == GLFW_OPENGL_ES_API)
560             setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
561     }
562 
563     if (_glfw.egl.KHR_context_flush_control)
564     {
565         if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
566         {
567             setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
568                       EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
569         }
570         else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
571         {
572             setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
573                       EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
574         }
575     }
576 
577     setAttrib(EGL_NONE, EGL_NONE);
578 
579     window->context.egl.handle = eglCreateContext(_glfw.egl.display,
580                                                   config, share, attribs);
581 
582     if (window->context.egl.handle == EGL_NO_CONTEXT)
583     {
584         _glfwInputError(GLFW_VERSION_UNAVAILABLE,
585                         "EGL: Failed to create context: %s",
586                         getEGLErrorString(eglGetError()));
587         return GLFW_FALSE;
588     }
589 
590     // Set up attributes for surface creation
591     index = 0;
592 
593     if (fbconfig->sRGB)
594     {
595         if (_glfw.egl.KHR_gl_colorspace)
596             setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
597     }
598 
599     setAttrib(EGL_NONE, EGL_NONE);
600 
601     window->context.egl.surface =
602         eglCreateWindowSurface(_glfw.egl.display,
603                                config,
604                                _GLFW_EGL_NATIVE_WINDOW,
605                                attribs);
606     if (window->context.egl.surface == EGL_NO_SURFACE)
607     {
608         _glfwInputError(GLFW_PLATFORM_ERROR,
609                         "EGL: Failed to create window surface: %s",
610                         getEGLErrorString(eglGetError()));
611         return GLFW_FALSE;
612     }
613 
614     window->context.egl.config = config;
615 
616     // Load the appropriate client library
617     if (!_glfw.egl.KHR_get_all_proc_addresses)
618     {
619         int i;
620         const char** sonames;
621         const char* es1sonames[] =
622         {
623 #if defined(_GLFW_GLESV1_LIBRARY)
624             _GLFW_GLESV1_LIBRARY,
625 #elif defined(_GLFW_WIN32)
626             "GLESv1_CM.dll",
627             "libGLES_CM.dll",
628 #elif defined(_GLFW_COCOA)
629             "libGLESv1_CM.dylib",
630 #else
631             "libGLESv1_CM.so.1",
632             "libGLES_CM.so.1",
633 #endif
634             NULL
635         };
636         const char* es2sonames[] =
637         {
638 #if defined(_GLFW_GLESV2_LIBRARY)
639             _GLFW_GLESV2_LIBRARY,
640 #elif defined(_GLFW_WIN32)
641             "GLESv2.dll",
642             "libGLESv2.dll",
643 #elif defined(_GLFW_COCOA)
644             "libGLESv2.dylib",
645 #elif defined(__CYGWIN__)
646             "libGLESv2-2.so",
647 #else
648             "libGLESv2.so.2",
649 #endif
650             NULL
651         };
652         const char* glsonames[] =
653         {
654 #if defined(_GLFW_OPENGL_LIBRARY)
655             _GLFW_OPENGL_LIBRARY,
656 #elif defined(_GLFW_WIN32)
657 #elif defined(_GLFW_COCOA)
658 #else
659             "libGL.so.1",
660 #endif
661             NULL
662         };
663 
664         if (ctxconfig->client == GLFW_OPENGL_ES_API)
665         {
666             if (ctxconfig->major == 1)
667                 sonames = es1sonames;
668             else
669                 sonames = es2sonames;
670         }
671         else
672             sonames = glsonames;
673 
674         for (i = 0;  sonames[i];  i++)
675         {
676             // HACK: Match presence of lib prefix to increase chance of finding
677             //       a matching pair in the jungle that is Win32 EGL/GLES
678             if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
679                 continue;
680 
681             window->context.egl.client = _glfw_dlopen(sonames[i]);
682             if (window->context.egl.client)
683                 break;
684         }
685 
686         if (!window->context.egl.client)
687         {
688             _glfwInputError(GLFW_API_UNAVAILABLE,
689                             "EGL: Failed to load client library");
690             return GLFW_FALSE;
691         }
692     }
693 
694     window->context.makeCurrent = makeContextCurrentEGL;
695     window->context.swapBuffers = swapBuffersEGL;
696     window->context.swapInterval = swapIntervalEGL;
697     window->context.extensionSupported = extensionSupportedEGL;
698     window->context.getProcAddress = getProcAddressEGL;
699     window->context.destroy = destroyContextEGL;
700 
701     return GLFW_TRUE;
702 }
703 
704 #undef setAttrib
705 
706 // Returns the Visual and depth of the chosen EGLConfig
707 //
708 #if defined(_GLFW_X11)
_glfwChooseVisualEGL(const _GLFWwndconfig * wndconfig,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig,Visual ** visual,int * depth)709 GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
710                               const _GLFWctxconfig* ctxconfig,
711                               const _GLFWfbconfig* fbconfig,
712                               Visual** visual, int* depth)
713 {
714     XVisualInfo* result;
715     XVisualInfo desired;
716     EGLConfig native;
717     EGLint visualID = 0, count = 0;
718     const long vimask = VisualScreenMask | VisualIDMask;
719 
720     if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
721     {
722         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
723                         "EGL: Failed to find a suitable EGLConfig");
724         return GLFW_FALSE;
725     }
726 
727     eglGetConfigAttrib(_glfw.egl.display, native,
728                        EGL_NATIVE_VISUAL_ID, &visualID);
729 
730     desired.screen = _glfw.x11.screen;
731     desired.visualid = visualID;
732 
733     result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
734     if (!result)
735     {
736         _glfwInputError(GLFW_PLATFORM_ERROR,
737                         "EGL: Failed to retrieve Visual for EGLConfig");
738         return GLFW_FALSE;
739     }
740 
741     *visual = result->visual;
742     *depth = result->depth;
743 
744     XFree(result);
745     return GLFW_TRUE;
746 }
747 #endif // _GLFW_X11
748 
749 
750 //////////////////////////////////////////////////////////////////////////
751 //////                        GLFW native API                       //////
752 //////////////////////////////////////////////////////////////////////////
753 
glfwGetEGLDisplay(void)754 GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
755 {
756     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
757     return _glfw.egl.display;
758 }
759 
glfwGetEGLContext(GLFWwindow * handle)760 GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
761 {
762     _GLFWwindow* window = (_GLFWwindow*) handle;
763     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
764 
765     if (window->context.client == GLFW_NO_API)
766     {
767         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
768         return EGL_NO_CONTEXT;
769     }
770 
771     return window->context.egl.handle;
772 }
773 
glfwGetEGLSurface(GLFWwindow * handle)774 GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
775 {
776     _GLFWwindow* window = (_GLFWwindow*) handle;
777     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
778 
779     if (window->context.client == GLFW_NO_API)
780     {
781         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
782         return EGL_NO_SURFACE;
783     }
784 
785     return window->context.egl.surface;
786 }
787 
788