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