]> git.sesse.net Git - pistorm/blob - raylib_pi4_test/external/glfw/src/egl_context.c
Update raylib files and Makefile for Pi 4 testing
[pistorm] / raylib_pi4_test / external / glfw / src / egl_context.c
1 //========================================================================
2 // GLFW 3.4 EGL - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
6 //
7 // This software is provided 'as-is', without any express or implied
8 // warranty. In no event will the authors be held liable for any damages
9 // arising from the use of this software.
10 //
11 // Permission is granted to anyone to use this software for any purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following restrictions:
14 //
15 // 1. The origin of this software must not be misrepresented; you must not
16 //    claim that you wrote the original software. If you use this software
17 //    in a product, an acknowledgment in the product documentation would
18 //    be appreciated but is not required.
19 //
20 // 2. Altered source versions must be plainly marked as such, and must not
21 //    be misrepresented as being the original software.
22 //
23 // 3. This notice may not be removed or altered from any source
24 //    distribution.
25 //
26 //========================================================================
27 // 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 //
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 //
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 //
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
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
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
236 static void swapIntervalEGL(int interval)
237 {
238     eglSwapInterval(_glfw.egl.display, interval);
239 }
240
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
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
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 //
303 GLFWbool _glfwInitEGL(void)
304 {
305     int i;
306     EGLint* attribs = NULL;
307     const char* extensions;
308     const char* sonames[] =
309     {
310 #if defined(_GLFW_EGL_LIBRARY)
311         _GLFW_EGL_LIBRARY,
312 #elif defined(_GLFW_WIN32)
313         "libEGL.dll",
314         "EGL.dll",
315 #elif defined(_GLFW_COCOA)
316         "libEGL.dylib",
317 #elif defined(__CYGWIN__)
318         "libEGL-1.so",
319 #else
320         "libEGL.so.1",
321 #endif
322         NULL
323     };
324
325     if (_glfw.egl.handle)
326         return GLFW_TRUE;
327
328     for (i = 0;  sonames[i];  i++)
329     {
330         _glfw.egl.handle = _glfw_dlopen(sonames[i]);
331         if (_glfw.egl.handle)
332             break;
333     }
334
335     if (!_glfw.egl.handle)
336     {
337         _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
338         return GLFW_FALSE;
339     }
340
341     _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
342
343     _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
344         _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
345     _glfw.egl.GetConfigs = (PFN_eglGetConfigs)
346         _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
347     _glfw.egl.GetDisplay = (PFN_eglGetDisplay)
348         _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
349     _glfw.egl.GetError = (PFN_eglGetError)
350         _glfw_dlsym(_glfw.egl.handle, "eglGetError");
351     _glfw.egl.Initialize = (PFN_eglInitialize)
352         _glfw_dlsym(_glfw.egl.handle, "eglInitialize");
353     _glfw.egl.Terminate = (PFN_eglTerminate)
354         _glfw_dlsym(_glfw.egl.handle, "eglTerminate");
355     _glfw.egl.BindAPI = (PFN_eglBindAPI)
356         _glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
357     _glfw.egl.CreateContext = (PFN_eglCreateContext)
358         _glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
359     _glfw.egl.DestroySurface = (PFN_eglDestroySurface)
360         _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
361     _glfw.egl.DestroyContext = (PFN_eglDestroyContext)
362         _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
363     _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
364         _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
365     _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
366         _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
367     _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
368         _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
369     _glfw.egl.SwapInterval = (PFN_eglSwapInterval)
370         _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
371     _glfw.egl.QueryString = (PFN_eglQueryString)
372         _glfw_dlsym(_glfw.egl.handle, "eglQueryString");
373     _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
374         _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
375
376     if (!_glfw.egl.GetConfigAttrib ||
377         !_glfw.egl.GetConfigs ||
378         !_glfw.egl.GetDisplay ||
379         !_glfw.egl.GetError ||
380         !_glfw.egl.Initialize ||
381         !_glfw.egl.Terminate ||
382         !_glfw.egl.BindAPI ||
383         !_glfw.egl.CreateContext ||
384         !_glfw.egl.DestroySurface ||
385         !_glfw.egl.DestroyContext ||
386         !_glfw.egl.CreateWindowSurface ||
387         !_glfw.egl.MakeCurrent ||
388         !_glfw.egl.SwapBuffers ||
389         !_glfw.egl.SwapInterval ||
390         !_glfw.egl.QueryString ||
391         !_glfw.egl.GetProcAddress)
392     {
393         _glfwInputError(GLFW_PLATFORM_ERROR,
394                         "EGL: Failed to load required entry points");
395
396         _glfwTerminateEGL();
397         return GLFW_FALSE;
398     }
399
400     extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
401     if (extensions && eglGetError() == EGL_SUCCESS)
402         _glfw.egl.EXT_client_extensions = GLFW_TRUE;
403
404     if (_glfw.egl.EXT_client_extensions)
405     {
406         _glfw.egl.EXT_platform_base =
407             _glfwStringInExtensionString("EGL_EXT_platform_base", extensions);
408         _glfw.egl.EXT_platform_x11 =
409             _glfwStringInExtensionString("EGL_EXT_platform_x11", extensions);
410         _glfw.egl.EXT_platform_wayland =
411             _glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions);
412         _glfw.egl.ANGLE_platform_angle =
413             _glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions);
414         _glfw.egl.ANGLE_platform_angle_opengl =
415             _glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions);
416         _glfw.egl.ANGLE_platform_angle_d3d =
417             _glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions);
418         _glfw.egl.ANGLE_platform_angle_vulkan =
419             _glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions);
420         _glfw.egl.ANGLE_platform_angle_metal =
421             _glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions);
422     }
423
424     if (_glfw.egl.EXT_platform_base)
425     {
426         _glfw.egl.GetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
427             eglGetProcAddress("eglGetPlatformDisplayEXT");
428         _glfw.egl.CreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
429             eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
430     }
431
432     _glfw.egl.platform = _glfwPlatformGetEGLPlatform(&attribs);
433     if (_glfw.egl.platform)
434     {
435         _glfw.egl.display =
436             eglGetPlatformDisplayEXT(_glfw.egl.platform,
437                                      _glfwPlatformGetEGLNativeDisplay(),
438                                      attribs);
439     }
440     else
441         _glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay());
442
443     free(attribs);
444
445     if (_glfw.egl.display == EGL_NO_DISPLAY)
446     {
447         _glfwInputError(GLFW_API_UNAVAILABLE,
448                         "EGL: Failed to get EGL display: %s",
449                         getEGLErrorString(eglGetError()));
450
451         _glfwTerminateEGL();
452         return GLFW_FALSE;
453     }
454
455     if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
456     {
457         _glfwInputError(GLFW_API_UNAVAILABLE,
458                         "EGL: Failed to initialize EGL: %s",
459                         getEGLErrorString(eglGetError()));
460
461         _glfwTerminateEGL();
462         return GLFW_FALSE;
463     }
464
465     _glfw.egl.KHR_create_context =
466         extensionSupportedEGL("EGL_KHR_create_context");
467     _glfw.egl.KHR_create_context_no_error =
468         extensionSupportedEGL("EGL_KHR_create_context_no_error");
469     _glfw.egl.KHR_gl_colorspace =
470         extensionSupportedEGL("EGL_KHR_gl_colorspace");
471     _glfw.egl.KHR_get_all_proc_addresses =
472         extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
473     _glfw.egl.KHR_context_flush_control =
474         extensionSupportedEGL("EGL_KHR_context_flush_control");
475
476     return GLFW_TRUE;
477 }
478
479 // Terminate EGL
480 //
481 void _glfwTerminateEGL(void)
482 {
483     if (_glfw.egl.display)
484     {
485         eglTerminate(_glfw.egl.display);
486         _glfw.egl.display = EGL_NO_DISPLAY;
487     }
488
489     if (_glfw.egl.handle)
490     {
491         _glfw_dlclose(_glfw.egl.handle);
492         _glfw.egl.handle = NULL;
493     }
494 }
495
496 #define setAttrib(a, v) \
497 { \
498     assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
499     attribs[index++] = a; \
500     attribs[index++] = v; \
501 }
502
503 // Create the OpenGL or OpenGL ES context
504 //
505 GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
506                                const _GLFWctxconfig* ctxconfig,
507                                const _GLFWfbconfig* fbconfig)
508 {
509     EGLint attribs[40];
510     EGLConfig config;
511     EGLContext share = NULL;
512     EGLNativeWindowType native;
513     int index = 0;
514
515     if (!_glfw.egl.display)
516     {
517         _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
518         return GLFW_FALSE;
519     }
520
521     if (ctxconfig->share)
522         share = ctxconfig->share->context.egl.handle;
523
524     if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
525     {
526         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
527                         "EGL: Failed to find a suitable EGLConfig");
528         return GLFW_FALSE;
529     }
530
531     if (ctxconfig->client == GLFW_OPENGL_ES_API)
532     {
533         if (!eglBindAPI(EGL_OPENGL_ES_API))
534         {
535             _glfwInputError(GLFW_API_UNAVAILABLE,
536                             "EGL: Failed to bind OpenGL ES: %s",
537                             getEGLErrorString(eglGetError()));
538             return GLFW_FALSE;
539         }
540     }
541     else
542     {
543         if (!eglBindAPI(EGL_OPENGL_API))
544         {
545             _glfwInputError(GLFW_API_UNAVAILABLE,
546                             "EGL: Failed to bind OpenGL: %s",
547                             getEGLErrorString(eglGetError()));
548             return GLFW_FALSE;
549         }
550     }
551
552     if (_glfw.egl.KHR_create_context)
553     {
554         int mask = 0, flags = 0;
555
556         if (ctxconfig->client == GLFW_OPENGL_API)
557         {
558             if (ctxconfig->forward)
559                 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
560
561             if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
562                 mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
563             else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
564                 mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
565         }
566
567         if (ctxconfig->debug)
568             flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
569
570         if (ctxconfig->robustness)
571         {
572             if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
573             {
574                 setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
575                           EGL_NO_RESET_NOTIFICATION_KHR);
576             }
577             else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
578             {
579                 setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
580                           EGL_LOSE_CONTEXT_ON_RESET_KHR);
581             }
582
583             flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
584         }
585
586         if (ctxconfig->noerror)
587         {
588             if (_glfw.egl.KHR_create_context_no_error)
589                 setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
590         }
591
592         if (ctxconfig->major != 1 || ctxconfig->minor != 0)
593         {
594             setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
595             setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
596         }
597
598         if (mask)
599             setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
600
601         if (flags)
602             setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
603     }
604     else
605     {
606         if (ctxconfig->client == GLFW_OPENGL_ES_API)
607             setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
608     }
609
610     if (_glfw.egl.KHR_context_flush_control)
611     {
612         if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
613         {
614             setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
615                       EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
616         }
617         else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
618         {
619             setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
620                       EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
621         }
622     }
623
624     setAttrib(EGL_NONE, EGL_NONE);
625
626     window->context.egl.handle = eglCreateContext(_glfw.egl.display,
627                                                   config, share, attribs);
628
629     if (window->context.egl.handle == EGL_NO_CONTEXT)
630     {
631         _glfwInputError(GLFW_VERSION_UNAVAILABLE,
632                         "EGL: Failed to create context: %s",
633                         getEGLErrorString(eglGetError()));
634         return GLFW_FALSE;
635     }
636
637     // Set up attributes for surface creation
638     index = 0;
639
640     if (fbconfig->sRGB)
641     {
642         if (_glfw.egl.KHR_gl_colorspace)
643             setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
644     }
645
646     setAttrib(EGL_NONE, EGL_NONE);
647
648     native = _glfwPlatformGetEGLNativeWindow(window);
649     // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
650     //       despite reporting EGL_EXT_platform_base
651     if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE)
652     {
653         window->context.egl.surface =
654             eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs);
655     }
656     else
657     {
658         window->context.egl.surface =
659             eglCreateWindowSurface(_glfw.egl.display, config, native, attribs);
660     }
661
662     if (window->context.egl.surface == EGL_NO_SURFACE)
663     {
664         _glfwInputError(GLFW_PLATFORM_ERROR,
665                         "EGL: Failed to create window surface: %s",
666                         getEGLErrorString(eglGetError()));
667         return GLFW_FALSE;
668     }
669
670     window->context.egl.config = config;
671
672     // Load the appropriate client library
673     if (!_glfw.egl.KHR_get_all_proc_addresses)
674     {
675         int i;
676         const char** sonames;
677         const char* es1sonames[] =
678         {
679 #if defined(_GLFW_GLESV1_LIBRARY)
680             _GLFW_GLESV1_LIBRARY,
681 #elif defined(_GLFW_WIN32)
682             "GLESv1_CM.dll",
683             "libGLES_CM.dll",
684 #elif defined(_GLFW_COCOA)
685             "libGLESv1_CM.dylib",
686 #else
687             "libGLESv1_CM.so.1",
688             "libGLES_CM.so.1",
689 #endif
690             NULL
691         };
692         const char* es2sonames[] =
693         {
694 #if defined(_GLFW_GLESV2_LIBRARY)
695             _GLFW_GLESV2_LIBRARY,
696 #elif defined(_GLFW_WIN32)
697             "GLESv2.dll",
698             "libGLESv2.dll",
699 #elif defined(_GLFW_COCOA)
700             "libGLESv2.dylib",
701 #elif defined(__CYGWIN__)
702             "libGLESv2-2.so",
703 #else
704             "libGLESv2.so.2",
705 #endif
706             NULL
707         };
708         const char* glsonames[] =
709         {
710 #if defined(_GLFW_OPENGL_LIBRARY)
711             _GLFW_OPENGL_LIBRARY,
712 #elif defined(_GLFW_WIN32)
713 #elif defined(_GLFW_COCOA)
714 #else
715             "libGL.so.1",
716 #endif
717             NULL
718         };
719
720         if (ctxconfig->client == GLFW_OPENGL_ES_API)
721         {
722             if (ctxconfig->major == 1)
723                 sonames = es1sonames;
724             else
725                 sonames = es2sonames;
726         }
727         else
728             sonames = glsonames;
729
730         for (i = 0;  sonames[i];  i++)
731         {
732             // HACK: Match presence of lib prefix to increase chance of finding
733             //       a matching pair in the jungle that is Win32 EGL/GLES
734             if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
735                 continue;
736
737             window->context.egl.client = _glfw_dlopen(sonames[i]);
738             if (window->context.egl.client)
739                 break;
740         }
741
742         if (!window->context.egl.client)
743         {
744             _glfwInputError(GLFW_API_UNAVAILABLE,
745                             "EGL: Failed to load client library");
746             return GLFW_FALSE;
747         }
748     }
749
750     window->context.makeCurrent = makeContextCurrentEGL;
751     window->context.swapBuffers = swapBuffersEGL;
752     window->context.swapInterval = swapIntervalEGL;
753     window->context.extensionSupported = extensionSupportedEGL;
754     window->context.getProcAddress = getProcAddressEGL;
755     window->context.destroy = destroyContextEGL;
756
757     return GLFW_TRUE;
758 }
759
760 #undef setAttrib
761
762 // Returns the Visual and depth of the chosen EGLConfig
763 //
764 #if defined(_GLFW_X11)
765 GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
766                               const _GLFWctxconfig* ctxconfig,
767                               const _GLFWfbconfig* fbconfig,
768                               Visual** visual, int* depth)
769 {
770     XVisualInfo* result;
771     XVisualInfo desired;
772     EGLConfig native;
773     EGLint visualID = 0, count = 0;
774     const long vimask = VisualScreenMask | VisualIDMask;
775
776     if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
777     {
778         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
779                         "EGL: Failed to find a suitable EGLConfig");
780         return GLFW_FALSE;
781     }
782
783     eglGetConfigAttrib(_glfw.egl.display, native,
784                        EGL_NATIVE_VISUAL_ID, &visualID);
785
786     desired.screen = _glfw.x11.screen;
787     desired.visualid = visualID;
788
789     result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
790     if (!result)
791     {
792         _glfwInputError(GLFW_PLATFORM_ERROR,
793                         "EGL: Failed to retrieve Visual for EGLConfig");
794         return GLFW_FALSE;
795     }
796
797     *visual = result->visual;
798     *depth = result->depth;
799
800     XFree(result);
801     return GLFW_TRUE;
802 }
803 #endif // _GLFW_X11
804
805
806 //////////////////////////////////////////////////////////////////////////
807 //////                        GLFW native API                       //////
808 //////////////////////////////////////////////////////////////////////////
809
810 GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
811 {
812     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
813     return _glfw.egl.display;
814 }
815
816 GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
817 {
818     _GLFWwindow* window = (_GLFWwindow*) handle;
819     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
820
821     if (window->context.client == GLFW_NO_API)
822     {
823         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
824         return EGL_NO_CONTEXT;
825     }
826
827     return window->context.egl.handle;
828 }
829
830 GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
831 {
832     _GLFWwindow* window = (_GLFWwindow*) handle;
833     _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
834
835     if (window->context.client == GLFW_NO_API)
836     {
837         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
838         return EGL_NO_SURFACE;
839     }
840
841     return window->context.egl.surface;
842 }
843