egl_context.c 26.9 KB
Newer Older
Cloudef's avatar
Cloudef committed
1
//========================================================================
Camilla Berglund's avatar
Camilla Berglund committed
2
// GLFW 3.3 EGL - www.glfw.org
Cloudef's avatar
Cloudef committed
3
4
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
Camilla Löwy's avatar
Camilla Löwy committed
5
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
Cloudef's avatar
Cloudef committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would
//    be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
//    be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
//    distribution.
//
//========================================================================
27
28
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
Cloudef's avatar
Cloudef committed
29
30
31
32

#include "internal.h"

#include <stdio.h>
Camilla Berglund's avatar
Camilla Berglund committed
33
#include <string.h>
Cloudef's avatar
Cloudef committed
34
#include <stdlib.h>
35
#include <assert.h>
Cloudef's avatar
Cloudef committed
36

37

38
// Return a description of the specified EGL error
39
//
40
static const char* getEGLErrorString(EGLint error)
41
42
43
44
45
46
47
48
49
50
51
52
{
    switch (error)
    {
        case EGL_SUCCESS:
            return "Success";
        case EGL_NOT_INITIALIZED:
            return "EGL is not or could not be initialized";
        case EGL_BAD_ACCESS:
            return "EGL cannot access a requested resource";
        case EGL_BAD_ALLOC:
            return "EGL failed to allocate resources for the requested operation";
        case EGL_BAD_ATTRIBUTE:
Camilla Berglund's avatar
Camilla Berglund committed
53
            return "An unrecognized attribute or attribute value was passed in the attribute list";
54
        case EGL_BAD_CONTEXT:
Camilla Berglund's avatar
Camilla Berglund committed
55
            return "An EGLContext argument does not name a valid EGL rendering context";
56
        case EGL_BAD_CONFIG:
Camilla Berglund's avatar
Camilla Berglund committed
57
            return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
58
        case EGL_BAD_CURRENT_SURFACE:
Camilla Berglund's avatar
Camilla Berglund committed
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:
Camilla Berglund's avatar
Camilla Berglund committed
61
            return "An EGLDisplay argument does not name a valid EGL display connection";
62
        case EGL_BAD_SURFACE:
Camilla Berglund's avatar
Camilla Berglund committed
63
            return "An EGLSurface argument does not name a valid surface configured for GL rendering";
64
65
66
67
68
        case EGL_BAD_MATCH:
            return "Arguments are inconsistent";
        case EGL_BAD_PARAMETER:
            return "One or more argument values are invalid";
        case EGL_BAD_NATIVE_PIXMAP:
Camilla Berglund's avatar
Camilla Berglund committed
69
            return "A NativePixmapType argument does not refer to a valid native pixmap";
70
        case EGL_BAD_NATIVE_WINDOW:
Camilla Berglund's avatar
Camilla Berglund committed
71
            return "A NativeWindowType argument does not refer to a valid native window";
72
73
        case EGL_CONTEXT_LOST:
            return "The application must destroy all contexts and reinitialise";
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
74
75
        default:
            return "ERROR: UNKNOWN EGL ERROR";
76
77
78
    }
}

79
80
// Returns the specified attribute of the specified EGLConfig
//
81
static int getEGLConfigAttrib(EGLConfig config, int attrib)
82
83
{
    int value;
84
    eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
85
86
87
    return value;
}

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
95
96
97
98
{
    EGLConfig* nativeConfigs;
    _GLFWfbconfig* usableConfigs;
    const _GLFWfbconfig* closest;
    int i, nativeCount, usableCount;

99
    eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
100
101
102
    if (!nativeCount)
    {
        _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
111
112
113
114
115
116
    usableCount = 0;

    for (i = 0;  i < nativeCount;  i++)
    {
        const EGLConfig n = nativeConfigs[i];
        _GLFWfbconfig* u = usableConfigs + usableCount;

Camilla Berglund's avatar
Camilla Berglund committed
117
        // Only consider RGB(A) EGLConfigs
118
        if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
119
120
            continue;

Camilla Berglund's avatar
Camilla Berglund committed
121
        // Only consider window EGLConfigs
122
        if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
123
124
            continue;

125
#if defined(_GLFW_X11)
126
127
        {
            XVisualInfo vi = {0};
128

129
130
131
132
            // Only consider EGLConfigs with associated Visuals
            vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
            if (!vi.visualid)
                continue;
133

134
            if (desired->transparent)
135
            {
136
137
138
139
140
141
142
143
                int count;
                XVisualInfo* vis =
                    XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
                if (vis)
                {
                    u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
                    XFree(vis);
                }
144
            }
145
        }
146
147
#endif // _GLFW_X11

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
154
155
156
                    continue;
            }
            else
            {
157
                if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
158
159
160
                    continue;
            }
        }
161
        else if (ctxconfig->client == GLFW_OPENGL_API)
162
        {
163
            if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
164
165
166
                continue;
        }

167
168
169
        u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
        u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
        u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
170

171
172
173
        u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
        u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
        u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
174

175
        u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
176
        u->doublebuffer = GLFW_TRUE;
177

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
178
        u->handle = (uintptr_t) n;
179
180
181
182
183
        usableCount++;
    }

    closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
    if (closest)
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
184
        *result = (EGLConfig) closest->handle;
185
186
187
188

    free(nativeConfigs);
    free(usableConfigs);

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
189
    return closest != NULL;
190
191
}

192
static void makeContextCurrentEGL(_GLFWwindow* window)
193
194
195
196
197
198
199
200
201
202
{
    if (window)
    {
        if (!eglMakeCurrent(_glfw.egl.display,
                            window->context.egl.surface,
                            window->context.egl.surface,
                            window->context.egl.handle))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "EGL: Failed to make context current: %s",
203
                            getEGLErrorString(eglGetError()));
204
205
206
207
208
209
210
211
212
213
214
215
            return;
        }
    }
    else
    {
        if (!eglMakeCurrent(_glfw.egl.display,
                            EGL_NO_SURFACE,
                            EGL_NO_SURFACE,
                            EGL_NO_CONTEXT))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "EGL: Failed to clear current context: %s",
216
                            getEGLErrorString(eglGetError()));
217
218
219
220
            return;
        }
    }

221
    _glfwPlatformSetTls(&_glfw.contextSlot, window);
222
223
}

224
static void swapBuffersEGL(_GLFWwindow* window)
225
{
226
    if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
227
228
229
230
231
232
233
234
235
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "EGL: The context must be current on the calling thread when swapping buffers");
        return;
    }

    eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
}

236
static void swapIntervalEGL(int interval)
237
238
239
240
{
    eglSwapInterval(_glfw.egl.display, interval);
}

241
static int extensionSupportedEGL(const char* extension)
242
243
244
245
246
247
248
249
250
251
252
{
    const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
    if (extensions)
    {
        if (_glfwStringInExtensionString(extension, extensions))
            return GLFW_TRUE;
    }

    return GLFW_FALSE;
}

253
static GLFWglproc getProcAddressEGL(const char* procname)
254
{
255
    _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
256
257
258
259
260
261
262
263
264
265
266
267

    if (window->context.egl.client)
    {
        GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
                                                   procname);
        if (proc)
            return proc;
    }

    return eglGetProcAddress(procname);
}

268
static void destroyContextEGL(_GLFWwindow* window)
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
{
#if defined(_GLFW_X11)
    // NOTE: Do not unload libGL.so.1 while the X11 display is still open,
    //       as it will make XCloseDisplay segfault
    if (window->context.client != GLFW_OPENGL_API)
#endif // _GLFW_X11
    {
        if (window->context.egl.client)
        {
            _glfw_dlclose(window->context.egl.client);
            window->context.egl.client = NULL;
        }
    }

    if (window->context.egl.surface)
    {
        eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
        window->context.egl.surface = EGL_NO_SURFACE;
    }

    if (window->context.egl.handle)
    {
        eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
        window->context.egl.handle = EGL_NO_CONTEXT;
    }
}

296

297
298
299
//////////////////////////////////////////////////////////////////////////
//////                       GLFW internal API                      //////
//////////////////////////////////////////////////////////////////////////
Cloudef's avatar
Cloudef committed
300

301
// Initialize EGL
302
//
Camilla Berglund's avatar
Camilla Berglund committed
303
GLFWbool _glfwInitEGL(void)
Cloudef's avatar
Cloudef committed
304
{
305
306
307
    int i;
    const char* sonames[] =
    {
308
309
310
#if defined(_GLFW_EGL_LIBRARY)
        _GLFW_EGL_LIBRARY,
#elif defined(_GLFW_WIN32)
311
312
313
314
        "libEGL.dll",
        "EGL.dll",
#elif defined(_GLFW_COCOA)
        "libEGL.dylib",
Camilla Löwy's avatar
Camilla Löwy committed
315
316
#elif defined(__CYGWIN__)
        "libEGL-1.so",
317
318
319
320
321
322
#else
        "libEGL.so.1",
#endif
        NULL
    };

323
324
325
    if (_glfw.egl.handle)
        return GLFW_TRUE;

326
327
328
329
330
331
332
333
    for (i = 0;  sonames[i];  i++)
    {
        _glfw.egl.handle = _glfw_dlopen(sonames[i]);
        if (_glfw.egl.handle)
            break;
    }

    if (!_glfw.egl.handle)
334
335
    {
        _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
336
        return GLFW_FALSE;
337
    }
338

339
340
    _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);

341
    _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
342
        _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
343
    _glfw.egl.GetConfigs = (PFN_eglGetConfigs)
344
        _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
345
    _glfw.egl.GetDisplay = (PFN_eglGetDisplay)
346
        _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
347
    _glfw.egl.GetError = (PFN_eglGetError)
348
        _glfw_dlsym(_glfw.egl.handle, "eglGetError");
349
    _glfw.egl.Initialize = (PFN_eglInitialize)
350
        _glfw_dlsym(_glfw.egl.handle, "eglInitialize");
351
    _glfw.egl.Terminate = (PFN_eglTerminate)
352
        _glfw_dlsym(_glfw.egl.handle, "eglTerminate");
353
    _glfw.egl.BindAPI = (PFN_eglBindAPI)
354
        _glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
355
    _glfw.egl.CreateContext = (PFN_eglCreateContext)
356
        _glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
357
    _glfw.egl.DestroySurface = (PFN_eglDestroySurface)
358
        _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
359
    _glfw.egl.DestroyContext = (PFN_eglDestroyContext)
360
        _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
361
    _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
362
        _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
363
    _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
364
        _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
365
    _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
366
        _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
367
    _glfw.egl.SwapInterval = (PFN_eglSwapInterval)
368
        _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
369
    _glfw.egl.QueryString = (PFN_eglQueryString)
370
        _glfw_dlsym(_glfw.egl.handle, "eglQueryString");
371
    _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
372
373
        _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");

374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
    if (!_glfw.egl.GetConfigAttrib ||
        !_glfw.egl.GetConfigs ||
        !_glfw.egl.GetDisplay ||
        !_glfw.egl.GetError ||
        !_glfw.egl.Initialize ||
        !_glfw.egl.Terminate ||
        !_glfw.egl.BindAPI ||
        !_glfw.egl.CreateContext ||
        !_glfw.egl.DestroySurface ||
        !_glfw.egl.DestroyContext ||
        !_glfw.egl.CreateWindowSurface ||
        !_glfw.egl.MakeCurrent ||
        !_glfw.egl.SwapBuffers ||
        !_glfw.egl.SwapInterval ||
        !_glfw.egl.QueryString ||
        !_glfw.egl.GetProcAddress)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "EGL: Failed to load required entry points");
393
394

        _glfwTerminateEGL();
395
396
397
        return GLFW_FALSE;
    }

398
    _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
399
    if (_glfw.egl.display == EGL_NO_DISPLAY)
Cloudef's avatar
Cloudef committed
400
    {
401
402
        _glfwInputError(GLFW_API_UNAVAILABLE,
                        "EGL: Failed to get EGL display: %s",
403
                        getEGLErrorString(eglGetError()));
404
405

        _glfwTerminateEGL();
406
        return GLFW_FALSE;
Cloudef's avatar
Cloudef committed
407
408
    }

409
    if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
Cloudef's avatar
Cloudef committed
410
    {
411
412
        _glfwInputError(GLFW_API_UNAVAILABLE,
                        "EGL: Failed to initialize EGL: %s",
413
                        getEGLErrorString(eglGetError()));
414
415

        _glfwTerminateEGL();
416
        return GLFW_FALSE;
Cloudef's avatar
Cloudef committed
417
418
    }

Camilla Berglund's avatar
Camilla Berglund committed
419
    _glfw.egl.KHR_create_context =
420
        extensionSupportedEGL("EGL_KHR_create_context");
421
    _glfw.egl.KHR_create_context_no_error =
422
        extensionSupportedEGL("EGL_KHR_create_context_no_error");
423
    _glfw.egl.KHR_gl_colorspace =
424
        extensionSupportedEGL("EGL_KHR_gl_colorspace");
425
426
    _glfw.egl.KHR_get_all_proc_addresses =
        extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
427
428
    _glfw.egl.KHR_context_flush_control =
        extensionSupportedEGL("EGL_KHR_context_flush_control");
Cloudef's avatar
Cloudef committed
429

430
    return GLFW_TRUE;
431
}
432

433
// Terminate EGL
434
//
435
void _glfwTerminateEGL(void)
436
{
437
    if (_glfw.egl.display)
438
    {
439
        eglTerminate(_glfw.egl.display);
440
441
442
443
444
        _glfw.egl.display = EGL_NO_DISPLAY;
    }

    if (_glfw.egl.handle)
    {
445
446
447
        _glfw_dlclose(_glfw.egl.handle);
        _glfw.egl.handle = NULL;
    }
Cloudef's avatar
Cloudef committed
448
449
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
450
#define setAttrib(a, v) \
451
{ \
452
    assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
453
454
    attribs[index++] = a; \
    attribs[index++] = v; \
455
}
Cloudef's avatar
Cloudef committed
456

457
// Create the OpenGL or OpenGL ES context for the window eglConfig
458
//
459
460
461
GLFWbool _glfwCreateContextForConfigEGL(_GLFWwindow* window,
                                    const _GLFWctxconfig* ctxconfig,
                                    EGLContext* context)
Cloudef's avatar
Cloudef committed
462
{
463
    EGLint attribs[40];
464
    int index = 0;
465
    EGLContext share = NULL;
Cloudef's avatar
Cloudef committed
466

467
468
469
470
471
472
    if (!_glfw.egl.display)
    {
        _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
        return GLFW_FALSE;
    }

473
    if (ctxconfig->share)
474
        share = ctxconfig->share->context.egl.handle;
Cloudef's avatar
Cloudef committed
475

476
    if (ctxconfig->client == GLFW_OPENGL_ES_API)
477
    {
478
        if (!eglBindAPI(EGL_OPENGL_ES_API))
479
        {
Camilla Berglund's avatar
Camilla Berglund committed
480
            _glfwInputError(GLFW_API_UNAVAILABLE,
481
                            "EGL: Failed to bind OpenGL ES: %s",
482
                            getEGLErrorString(eglGetError()));
483
            return GLFW_FALSE;
484
485
        }
    }
Cloudef's avatar
Cloudef committed
486
    else
487
    {
488
        if (!eglBindAPI(EGL_OPENGL_API))
489
        {
Camilla Berglund's avatar
Camilla Berglund committed
490
            _glfwInputError(GLFW_API_UNAVAILABLE,
491
                            "EGL: Failed to bind OpenGL: %s",
492
                            getEGLErrorString(eglGetError()));
493
            return GLFW_FALSE;
494
495
        }
    }
Cloudef's avatar
Cloudef committed
496

497
    if (_glfw.egl.KHR_create_context)
498
    {
499
        int mask = 0, flags = 0;
500

501
        if (ctxconfig->client == GLFW_OPENGL_API)
502
        {
503
504
505
            if (ctxconfig->forward)
                flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;

506
            if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
507
                mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
508
            else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
509
                mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
510
        }
511

512
513
514
        if (ctxconfig->debug)
            flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;

515
        if (ctxconfig->robustness)
516
        {
517
            if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
518
            {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
519
520
                setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
                          EGL_NO_RESET_NOTIFICATION_KHR);
521
            }
522
            else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
523
            {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
524
525
                setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
                          EGL_LOSE_CONTEXT_ON_RESET_KHR);
526
            }
527

528
529
530
            flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
        }

531
532
533
        if (ctxconfig->noerror)
        {
            if (_glfw.egl.KHR_create_context_no_error)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
534
                setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
535
536
        }

537
        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
538
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
539
540
            setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
            setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
541
        }
542
543

        if (mask)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
544
            setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
545
546

        if (flags)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
547
            setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
548
    }
549
550
    else
    {
551
        if (ctxconfig->client == GLFW_OPENGL_ES_API)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
552
            setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
553
    }
554

555
556
557
558
    if (_glfw.egl.KHR_context_flush_control)
    {
        if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
559
560
            setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
                      EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
561
562
563
        }
        else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
564
565
            setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
                      EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
566
        }
567
    }
Cloudef's avatar
Cloudef committed
568

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
569
    setAttrib(EGL_NONE, EGL_NONE);
570

571
    window->context.egl.handle = eglCreateContext(_glfw.egl.display,
572
                                                  window->context.egl.config, share, attribs);
573

574
    if (window->context.egl.handle == EGL_NO_CONTEXT)
Cloudef's avatar
Cloudef committed
575
    {
Camilla Berglund's avatar
Camilla Berglund committed
576
        _glfwInputError(GLFW_VERSION_UNAVAILABLE,
577
                        "EGL: Failed to create context: %s",
578
                        getEGLErrorString(eglGetError()));
579
        return GLFW_FALSE;
Cloudef's avatar
Cloudef committed
580
581
    }

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
    return GLFW_TRUE;
}

// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
{
    EGLNativeWindowType native;
    EGLint attribs[40];
    int index = 0;

    if (!chooseEGLConfig(ctxconfig, fbconfig, &window->context.egl.config))
    {
        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                        "EGL: Failed to find a suitable EGLConfig");
        return GLFW_FALSE;
    }

    if (!_glfwCreateContextForConfigEGL(window,ctxconfig,&window->context.egl.handle))
    {
        return GLFW_FALSE;
    }

607
    // Set up attributes for surface creation
608
    if (fbconfig->sRGB)
609
    {
610
611
612
        if (_glfw.egl.KHR_gl_colorspace)
            setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
    }
613

614
    setAttrib(EGL_NONE, EGL_NONE);
615

616
617
618
619
620
621
622
623
624
625
626
627
    native = _glfwPlatformGetEGLNativeWindow(window);
    // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
    //       despite reporting EGL_EXT_platform_base
    if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE)
    {
        window->context.egl.surface =
            eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, window->context.egl.config, native, attribs);
    }
    else
    {
        window->context.egl.surface =
            eglCreateWindowSurface(_glfw.egl.display, window->context.egl.config, native, attribs);
628
629
    }

630
    window->context.egl.surface =
631
632
633
        eglCreateWindowSurface(_glfw.egl.display,
                               config,
                               _GLFW_EGL_NATIVE_WINDOW,
634
                               attribs);
635
    if (window->context.egl.surface == EGL_NO_SURFACE)
636
637
638
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "EGL: Failed to create window surface: %s",
639
                        getEGLErrorString(eglGetError()));
640
641
642
        return GLFW_FALSE;
    }

Cloudef's avatar
Cloudef committed
643

644
    // Load the appropriate client library
645
    if (!_glfw.egl.KHR_get_all_proc_addresses)
646
647
648
649
650
    {
        int i;
        const char** sonames;
        const char* es1sonames[] =
        {
651
652
653
#if defined(_GLFW_GLESV1_LIBRARY)
            _GLFW_GLESV1_LIBRARY,
#elif defined(_GLFW_WIN32)
654
655
656
657
658
659
660
661
662
663
664
665
            "GLESv1_CM.dll",
            "libGLES_CM.dll",
#elif defined(_GLFW_COCOA)
            "libGLESv1_CM.dylib",
#else
            "libGLESv1_CM.so.1",
            "libGLES_CM.so.1",
#endif
            NULL
        };
        const char* es2sonames[] =
        {
666
667
668
#if defined(_GLFW_GLESV2_LIBRARY)
            _GLFW_GLESV2_LIBRARY,
#elif defined(_GLFW_WIN32)
669
670
671
672
            "GLESv2.dll",
            "libGLESv2.dll",
#elif defined(_GLFW_COCOA)
            "libGLESv2.dylib",
Camilla Löwy's avatar
Camilla Löwy committed
673
674
#elif defined(__CYGWIN__)
            "libGLESv2-2.so",
675
676
677
678
679
680
681
#else
            "libGLESv2.so.2",
#endif
            NULL
        };
        const char* glsonames[] =
        {
682
683
684
#if defined(_GLFW_OPENGL_LIBRARY)
            _GLFW_OPENGL_LIBRARY,
#elif defined(_GLFW_WIN32)
685
686
687
688
689
690
691
#elif defined(_GLFW_COCOA)
#else
            "libGL.so.1",
#endif
            NULL
        };

692
        if (ctxconfig->client == GLFW_OPENGL_ES_API)
693
694
695
696
697
698
699
700
701
702
703
        {
            if (ctxconfig->major == 1)
                sonames = es1sonames;
            else
                sonames = es2sonames;
        }
        else
            sonames = glsonames;

        for (i = 0;  sonames[i];  i++)
        {
704
705
706
707
708
            // HACK: Match presence of lib prefix to increase chance of finding
            //       a matching pair in the jungle that is Win32 EGL/GLES
            if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
                continue;

709
710
            window->context.egl.client = _glfw_dlopen(sonames[i]);
            if (window->context.egl.client)
711
712
713
                break;
        }

714
        if (!window->context.egl.client)
715
716
717
        {
            _glfwInputError(GLFW_API_UNAVAILABLE,
                            "EGL: Failed to load client library");
718
            return GLFW_FALSE;
719
720
721
        }
    }

722
723
724
725
726
727
    window->context.makeCurrent = makeContextCurrentEGL;
    window->context.swapBuffers = swapBuffersEGL;
    window->context.swapInterval = swapIntervalEGL;
    window->context.extensionSupported = extensionSupportedEGL;
    window->context.getProcAddress = getProcAddressEGL;
    window->context.destroy = destroyContextEGL;
728

729
    return GLFW_TRUE;
Cloudef's avatar
Cloudef committed
730
731
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
732
#undef setAttrib
Cloudef's avatar
Cloudef committed
733

734
735
736
// Returns the Visual and depth of the chosen EGLConfig
//
#if defined(_GLFW_X11)
737
738
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
                              const _GLFWctxconfig* ctxconfig,
739
740
                              const _GLFWfbconfig* fbconfig,
                              Visual** visual, int* depth)
741
742
743
744
745
746
747
{
    XVisualInfo* result;
    XVisualInfo desired;
    EGLConfig native;
    EGLint visualID = 0, count = 0;
    const long vimask = VisualScreenMask | VisualIDMask;

748
    if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
749
750
751
752
753
754
    {
        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                        "EGL: Failed to find a suitable EGLConfig");
        return GLFW_FALSE;
    }

755
756
    eglGetConfigAttrib(_glfw.egl.display, native,
                       EGL_NATIVE_VISUAL_ID, &visualID);
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

    desired.screen = _glfw.x11.screen;
    desired.visualid = visualID;

    result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
    if (!result)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "EGL: Failed to retrieve Visual for EGLConfig");
        return GLFW_FALSE;
    }

    *visual = result->visual;
    *depth = result->depth;

    XFree(result);
    return GLFW_TRUE;
}
#endif // _GLFW_X11
Camilla Berglund's avatar
Camilla Berglund committed
776

777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
static void _glfwMakeUserContextCurrentEGL(_GLFWusercontext* context)
{
    if(context)
    {
        if (!eglMakeCurrent(_glfw.egl.display,
                            context->window->context.egl.surface,
                            context->window->context.egl.surface,
                            context->egl.handle))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "EGL: Failed to make context current: %s",
                            getEGLErrorString(eglGetError()));
            return;
        }
    }
    else
    {
        if (!eglMakeCurrent(_glfw.egl.display,
                            EGL_NO_SURFACE,
                            EGL_NO_SURFACE,
                            EGL_NO_CONTEXT))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "EGL: Failed to clear current context: %s",
                            getEGLErrorString(eglGetError()));
            return;
        }
    }
}

static void _glfwDestroyUserContextEGL(_GLFWusercontext* context)
{
    if (context->egl.handle)
    {
        eglDestroyContext(_glfw.egl.display, context->egl.handle);
    }
    free(context);
}

816
817
_GLFWusercontext* _glfwCreateUserContextEGL(_GLFWwindow* window)
{
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
    _GLFWusercontext* context;
    _GLFWctxconfig ctxconfig;

    context = calloc(1, sizeof(_GLFWusercontext));
    context->window = window;

    ctxconfig = _glfw.hints.context;
    ctxconfig.share = window;

    if(!_glfwCreateContextForConfigEGL(window,&ctxconfig,&context->egl.handle))
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                                "EGL: Failed to create user OpenGL context");
        free(context);
        return NULL;
    }

    context->makeCurrent = _glfwMakeUserContextCurrentEGL;
    context->destroy = _glfwDestroyUserContextEGL;

    return context;
839
840
841
}


Camilla Berglund's avatar
Camilla Berglund committed
842

843
844
845
846
847
848
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
{
849
    _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
850
851
852
853
854
855
    return _glfw.egl.display;
}

GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
856
    _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
857

858
    if (window->context.client == GLFW_NO_API)
859
860
861
862
863
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return EGL_NO_CONTEXT;
    }

864
    return window->context.egl.handle;
865
866
867
868
869
}

GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
870
    _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
871

872
    if (window->context.client == GLFW_NO_API)
873
874
875
876
877
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return EGL_NO_SURFACE;
    }

878
    return window->context.egl.surface;
879
880
}