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