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 //
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 * fbconfig,EGLConfig * result)88 static 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
makeContextCurrentEGL(_GLFWwindow * window)243 static 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
swapBuffersEGL(_GLFWwindow * window)275 static 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
swapIntervalEGL(int interval)296 static void swapIntervalEGL(int interval)
297 {
298 eglSwapInterval(_glfw.egl.display, interval);
299 }
300
extensionSupportedEGL(const char * extension)301 static 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
getProcAddressEGL(const char * procname)313 static 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
destroyContextEGL(_GLFWwindow * window)329 static 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 //
_glfwInitEGL(void)363 GLFWbool _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 //
_glfwTerminateEGL(void)550 void _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 //
_glfwCreateContextEGL(_GLFWwindow * window,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)574 GLFWbool _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)
_glfwChooseVisualEGL(const _GLFWwndconfig * wndconfig,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig,Visual ** visual,int * depth)862 GLFWbool _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
glfwGetEGLDisplay(void)903 GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
904 {
905 _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
906 return _glfw.egl.display;
907 }
908
glfwGetEGLContext(GLFWwindow * handle)909 GLFWAPI 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
glfwGetEGLSurface(GLFWwindow * handle)929 GLFWAPI 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