xref: /third_party/glfw/src/egl_context.c (revision b877906b)
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//
38static 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//
79static 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//
88static 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
243static 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
275static 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
296static void swapIntervalEGL(int interval)
297{
298    eglSwapInterval(_glfw.egl.display, interval);
299}
300
301static 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
313static 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
329static 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//
363GLFWbool _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//
550void _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//
574GLFWbool _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)
862GLFWbool _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
903GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
904{
905    _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
906    return _glfw.egl.display;
907}
908
909GLFWAPI 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
929GLFWAPI 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