1 | //======================================================================== |
2 | // GLFW 3.2 EGL - www.glfw.org |
3 | //------------------------------------------------------------------------ |
4 | // Copyright (c) 2002-2006 Marcus Geelnard |
5 | // Copyright (c) 2006-2016 Camilla Berglund <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 <stdlib.h> |
32 | #include <assert.h> |
33 | |
34 | |
35 | // Return a description of the specified EGL error |
36 | // |
37 | static const char* getErrorString(EGLint error) |
38 | { |
39 | switch (error) |
40 | { |
41 | case EGL_SUCCESS: |
42 | return "Success" ; |
43 | case EGL_NOT_INITIALIZED: |
44 | return "EGL is not or could not be initialized" ; |
45 | case EGL_BAD_ACCESS: |
46 | return "EGL cannot access a requested resource" ; |
47 | case EGL_BAD_ALLOC: |
48 | return "EGL failed to allocate resources for the requested operation" ; |
49 | case EGL_BAD_ATTRIBUTE: |
50 | return "An unrecognized attribute or attribute value was passed in the attribute list" ; |
51 | case EGL_BAD_CONTEXT: |
52 | return "An EGLContext argument does not name a valid EGL rendering context" ; |
53 | case EGL_BAD_CONFIG: |
54 | return "An EGLConfig argument does not name a valid EGL frame buffer configuration" ; |
55 | case EGL_BAD_CURRENT_SURFACE: |
56 | return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid" ; |
57 | case EGL_BAD_DISPLAY: |
58 | return "An EGLDisplay argument does not name a valid EGL display connection" ; |
59 | case EGL_BAD_SURFACE: |
60 | return "An EGLSurface argument does not name a valid surface configured for GL rendering" ; |
61 | case EGL_BAD_MATCH: |
62 | return "Arguments are inconsistent" ; |
63 | case EGL_BAD_PARAMETER: |
64 | return "One or more argument values are invalid" ; |
65 | case EGL_BAD_NATIVE_PIXMAP: |
66 | return "A NativePixmapType argument does not refer to a valid native pixmap" ; |
67 | case EGL_BAD_NATIVE_WINDOW: |
68 | return "A NativeWindowType argument does not refer to a valid native window" ; |
69 | case EGL_CONTEXT_LOST: |
70 | return "The application must destroy all contexts and reinitialise" ; |
71 | default: |
72 | return "ERROR: UNKNOWN EGL ERROR" ; |
73 | } |
74 | } |
75 | |
76 | // Returns the specified attribute of the specified EGLConfig |
77 | // |
78 | static int getConfigAttrib(EGLConfig config, int attrib) |
79 | { |
80 | int value; |
81 | eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); |
82 | return value; |
83 | } |
84 | |
85 | // Return a list of available and usable framebuffer configs |
86 | // |
87 | static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, |
88 | const _GLFWfbconfig* desired, |
89 | EGLConfig* result) |
90 | { |
91 | EGLConfig* nativeConfigs; |
92 | _GLFWfbconfig* usableConfigs; |
93 | const _GLFWfbconfig* closest; |
94 | int i, nativeCount, usableCount; |
95 | |
96 | eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); |
97 | if (!nativeCount) |
98 | { |
99 | _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned" ); |
100 | return GLFW_FALSE; |
101 | } |
102 | |
103 | nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); |
104 | eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); |
105 | |
106 | usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); |
107 | usableCount = 0; |
108 | |
109 | for (i = 0; i < nativeCount; i++) |
110 | { |
111 | const EGLConfig n = nativeConfigs[i]; |
112 | _GLFWfbconfig* u = usableConfigs + usableCount; |
113 | |
114 | // Only consider RGB(A) EGLConfigs |
115 | if (!(getConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER)) |
116 | continue; |
117 | |
118 | // Only consider window EGLConfigs |
119 | if (!(getConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) |
120 | continue; |
121 | |
122 | #if defined(_GLFW_X11) |
123 | // Only consider EGLConfigs with associated Visuals |
124 | if (!getConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) |
125 | continue; |
126 | #endif // _GLFW_X11 |
127 | |
128 | if (ctxconfig->client == GLFW_OPENGL_ES_API) |
129 | { |
130 | if (ctxconfig->major == 1) |
131 | { |
132 | if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) |
133 | continue; |
134 | } |
135 | else |
136 | { |
137 | if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT)) |
138 | continue; |
139 | } |
140 | } |
141 | else if (ctxconfig->client == GLFW_OPENGL_API) |
142 | { |
143 | if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) |
144 | continue; |
145 | } |
146 | |
147 | u->redBits = getConfigAttrib(n, EGL_RED_SIZE); |
148 | u->greenBits = getConfigAttrib(n, EGL_GREEN_SIZE); |
149 | u->blueBits = getConfigAttrib(n, EGL_BLUE_SIZE); |
150 | |
151 | u->alphaBits = getConfigAttrib(n, EGL_ALPHA_SIZE); |
152 | u->depthBits = getConfigAttrib(n, EGL_DEPTH_SIZE); |
153 | u->stencilBits = getConfigAttrib(n, EGL_STENCIL_SIZE); |
154 | |
155 | u->samples = getConfigAttrib(n, EGL_SAMPLES); |
156 | u->doublebuffer = GLFW_TRUE; |
157 | |
158 | u->handle = (uintptr_t) n; |
159 | usableCount++; |
160 | } |
161 | |
162 | closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); |
163 | if (closest) |
164 | *result = (EGLConfig) closest->handle; |
165 | |
166 | free(nativeConfigs); |
167 | free(usableConfigs); |
168 | |
169 | return closest != NULL; |
170 | } |
171 | |
172 | static void makeContextCurrent(_GLFWwindow* window) |
173 | { |
174 | if (window) |
175 | { |
176 | if (!eglMakeCurrent(_glfw.egl.display, |
177 | window->context.egl.surface, |
178 | window->context.egl.surface, |
179 | window->context.egl.handle)) |
180 | { |
181 | _glfwInputError(GLFW_PLATFORM_ERROR, |
182 | "EGL: Failed to make context current: %s" , |
183 | getErrorString(eglGetError())); |
184 | return; |
185 | } |
186 | } |
187 | else |
188 | { |
189 | if (!eglMakeCurrent(_glfw.egl.display, |
190 | EGL_NO_SURFACE, |
191 | EGL_NO_SURFACE, |
192 | EGL_NO_CONTEXT)) |
193 | { |
194 | _glfwInputError(GLFW_PLATFORM_ERROR, |
195 | "EGL: Failed to clear current context: %s" , |
196 | getErrorString(eglGetError())); |
197 | return; |
198 | } |
199 | } |
200 | |
201 | _glfwPlatformSetCurrentContext(window); |
202 | } |
203 | |
204 | static void swapBuffers(_GLFWwindow* window) |
205 | { |
206 | if (window != _glfwPlatformGetCurrentContext()) |
207 | { |
208 | _glfwInputError(GLFW_PLATFORM_ERROR, |
209 | "EGL: The context must be current on the calling thread when swapping buffers" ); |
210 | return; |
211 | } |
212 | |
213 | eglSwapBuffers(_glfw.egl.display, window->context.egl.surface); |
214 | } |
215 | |
216 | static void swapInterval(int interval) |
217 | { |
218 | eglSwapInterval(_glfw.egl.display, interval); |
219 | } |
220 | |
221 | static int extensionSupported(const char* extension) |
222 | { |
223 | const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); |
224 | if (extensions) |
225 | { |
226 | if (_glfwStringInExtensionString(extension, extensions)) |
227 | return GLFW_TRUE; |
228 | } |
229 | |
230 | return GLFW_FALSE; |
231 | } |
232 | |
233 | static GLFWglproc getProcAddress(const char* procname) |
234 | { |
235 | _GLFWwindow* window = _glfwPlatformGetCurrentContext(); |
236 | |
237 | if (window->context.egl.client) |
238 | { |
239 | GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client, |
240 | procname); |
241 | if (proc) |
242 | return proc; |
243 | } |
244 | |
245 | return eglGetProcAddress(procname); |
246 | } |
247 | |
248 | static void destroyContext(_GLFWwindow* window) |
249 | { |
250 | #if defined(_GLFW_X11) |
251 | // NOTE: Do not unload libGL.so.1 while the X11 display is still open, |
252 | // as it will make XCloseDisplay segfault |
253 | if (window->context.client != GLFW_OPENGL_API) |
254 | #endif // _GLFW_X11 |
255 | { |
256 | if (window->context.egl.client) |
257 | { |
258 | _glfw_dlclose(window->context.egl.client); |
259 | window->context.egl.client = NULL; |
260 | } |
261 | } |
262 | |
263 | if (window->context.egl.surface) |
264 | { |
265 | eglDestroySurface(_glfw.egl.display, window->context.egl.surface); |
266 | window->context.egl.surface = EGL_NO_SURFACE; |
267 | } |
268 | |
269 | if (window->context.egl.handle) |
270 | { |
271 | eglDestroyContext(_glfw.egl.display, window->context.egl.handle); |
272 | window->context.egl.handle = EGL_NO_CONTEXT; |
273 | } |
274 | } |
275 | |
276 | |
277 | ////////////////////////////////////////////////////////////////////////// |
278 | ////// GLFW internal API ////// |
279 | ////////////////////////////////////////////////////////////////////////// |
280 | |
281 | // Initialize EGL |
282 | // |
283 | GLFWbool _glfwInitEGL(void) |
284 | { |
285 | int i; |
286 | const char* sonames[] = |
287 | { |
288 | #if defined(_GLFW_WIN32) |
289 | "libEGL.dll" , |
290 | "EGL.dll" , |
291 | #elif defined(_GLFW_COCOA) |
292 | "libEGL.dylib" , |
293 | #else |
294 | "libEGL.so.1" , |
295 | #endif |
296 | NULL |
297 | }; |
298 | |
299 | for (i = 0; sonames[i]; i++) |
300 | { |
301 | _glfw.egl.handle = _glfw_dlopen(sonames[i]); |
302 | if (_glfw.egl.handle) |
303 | break; |
304 | } |
305 | |
306 | if (!_glfw.egl.handle) |
307 | return GLFW_FALSE; |
308 | |
309 | _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) |
310 | _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib" ); |
311 | _glfw.egl.GetConfigs = (PFNEGLGETCONFIGSPROC) |
312 | _glfw_dlsym(_glfw.egl.handle, "eglGetConfigs" ); |
313 | _glfw.egl.GetDisplay = (PFNEGLGETDISPLAYPROC) |
314 | _glfw_dlsym(_glfw.egl.handle, "eglGetDisplay" ); |
315 | _glfw.egl.GetError = (PFNEGLGETERRORPROC) |
316 | _glfw_dlsym(_glfw.egl.handle, "eglGetError" ); |
317 | _glfw.egl.Initialize = (PFNEGLINITIALIZEPROC) |
318 | _glfw_dlsym(_glfw.egl.handle, "eglInitialize" ); |
319 | _glfw.egl.Terminate = (PFNEGLTERMINATEPROC) |
320 | _glfw_dlsym(_glfw.egl.handle, "eglTerminate" ); |
321 | _glfw.egl.BindAPI = (PFNEGLBINDAPIPROC) |
322 | _glfw_dlsym(_glfw.egl.handle, "eglBindAPI" ); |
323 | _glfw.egl.CreateContext = (PFNEGLCREATECONTEXTPROC) |
324 | _glfw_dlsym(_glfw.egl.handle, "eglCreateContext" ); |
325 | _glfw.egl.DestroySurface = (PFNEGLDESTROYSURFACEPROC) |
326 | _glfw_dlsym(_glfw.egl.handle, "eglDestroySurface" ); |
327 | _glfw.egl.DestroyContext = (PFNEGLDESTROYCONTEXTPROC) |
328 | _glfw_dlsym(_glfw.egl.handle, "eglDestroyContext" ); |
329 | _glfw.egl.CreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) |
330 | _glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface" ); |
331 | _glfw.egl.MakeCurrent = (PFNEGLMAKECURRENTPROC) |
332 | _glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent" ); |
333 | _glfw.egl.SwapBuffers = (PFNEGLSWAPBUFFERSPROC) |
334 | _glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers" ); |
335 | _glfw.egl.SwapInterval = (PFNEGLSWAPINTERVALPROC) |
336 | _glfw_dlsym(_glfw.egl.handle, "eglSwapInterval" ); |
337 | _glfw.egl.QueryString = (PFNEGLQUERYSTRINGPROC) |
338 | _glfw_dlsym(_glfw.egl.handle, "eglQueryString" ); |
339 | _glfw.egl.GetProcAddress = (PFNEGLGETPROCADDRESSPROC) |
340 | _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress" ); |
341 | |
342 | _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); |
343 | if (_glfw.egl.display == EGL_NO_DISPLAY) |
344 | { |
345 | _glfwInputError(GLFW_API_UNAVAILABLE, |
346 | "EGL: Failed to get EGL display: %s" , |
347 | getErrorString(eglGetError())); |
348 | |
349 | _glfwTerminateEGL(); |
350 | return GLFW_FALSE; |
351 | } |
352 | |
353 | if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) |
354 | { |
355 | _glfwInputError(GLFW_API_UNAVAILABLE, |
356 | "EGL: Failed to initialize EGL: %s" , |
357 | getErrorString(eglGetError())); |
358 | |
359 | _glfwTerminateEGL(); |
360 | return GLFW_FALSE; |
361 | } |
362 | |
363 | _glfw.egl.KHR_create_context = |
364 | extensionSupported("EGL_KHR_create_context" ); |
365 | _glfw.egl.KHR_create_context_no_error = |
366 | extensionSupported("EGL_KHR_create_context_no_error" ); |
367 | _glfw.egl.KHR_gl_colorspace = |
368 | extensionSupported("EGL_KHR_gl_colorspace" ); |
369 | |
370 | return GLFW_TRUE; |
371 | } |
372 | |
373 | // Terminate EGL |
374 | // |
375 | void _glfwTerminateEGL(void) |
376 | { |
377 | if (_glfw.egl.display) |
378 | { |
379 | eglTerminate(_glfw.egl.display); |
380 | _glfw.egl.display = EGL_NO_DISPLAY; |
381 | } |
382 | |
383 | if (_glfw.egl.handle) |
384 | { |
385 | _glfw_dlclose(_glfw.egl.handle); |
386 | _glfw.egl.handle = NULL; |
387 | } |
388 | } |
389 | |
390 | #define setEGLattrib(attribName, attribValue) \ |
391 | { \ |
392 | attribs[index++] = attribName; \ |
393 | attribs[index++] = attribValue; \ |
394 | assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ |
395 | } |
396 | |
397 | // Create the OpenGL or OpenGL ES context |
398 | // |
399 | GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, |
400 | const _GLFWctxconfig* ctxconfig, |
401 | const _GLFWfbconfig* fbconfig) |
402 | { |
403 | EGLint attribs[40]; |
404 | EGLConfig config; |
405 | EGLContext share = NULL; |
406 | |
407 | if (!_glfw.egl.display) |
408 | { |
409 | _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available" ); |
410 | return GLFW_FALSE; |
411 | } |
412 | |
413 | if (ctxconfig->share) |
414 | share = ctxconfig->share->context.egl.handle; |
415 | |
416 | if (!chooseFBConfigs(ctxconfig, fbconfig, &config)) |
417 | { |
418 | _glfwInputError(GLFW_FORMAT_UNAVAILABLE, |
419 | "EGL: Failed to find a suitable EGLConfig" ); |
420 | return GLFW_FALSE; |
421 | } |
422 | |
423 | if (ctxconfig->client == GLFW_OPENGL_ES_API) |
424 | { |
425 | if (!eglBindAPI(EGL_OPENGL_ES_API)) |
426 | { |
427 | _glfwInputError(GLFW_API_UNAVAILABLE, |
428 | "EGL: Failed to bind OpenGL ES: %s" , |
429 | getErrorString(eglGetError())); |
430 | return GLFW_FALSE; |
431 | } |
432 | } |
433 | else |
434 | { |
435 | if (!eglBindAPI(EGL_OPENGL_API)) |
436 | { |
437 | _glfwInputError(GLFW_API_UNAVAILABLE, |
438 | "EGL: Failed to bind OpenGL: %s" , |
439 | getErrorString(eglGetError())); |
440 | return GLFW_FALSE; |
441 | } |
442 | } |
443 | |
444 | if (_glfw.egl.KHR_create_context) |
445 | { |
446 | int index = 0, mask = 0, flags = 0; |
447 | |
448 | if (ctxconfig->client == GLFW_OPENGL_API) |
449 | { |
450 | if (ctxconfig->forward) |
451 | flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; |
452 | |
453 | if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) |
454 | mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; |
455 | else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) |
456 | mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; |
457 | |
458 | if (_glfw.egl.KHR_create_context_no_error) |
459 | { |
460 | if (ctxconfig->noerror) |
461 | flags |= EGL_CONTEXT_OPENGL_NO_ERROR_KHR; |
462 | } |
463 | } |
464 | |
465 | if (ctxconfig->debug) |
466 | flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; |
467 | |
468 | if (ctxconfig->robustness) |
469 | { |
470 | if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) |
471 | { |
472 | setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, |
473 | EGL_NO_RESET_NOTIFICATION_KHR); |
474 | } |
475 | else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) |
476 | { |
477 | setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, |
478 | EGL_LOSE_CONTEXT_ON_RESET_KHR); |
479 | } |
480 | |
481 | flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; |
482 | } |
483 | |
484 | if (ctxconfig->major != 1 || ctxconfig->minor != 0) |
485 | { |
486 | setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); |
487 | setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); |
488 | } |
489 | |
490 | if (mask) |
491 | setEGLattrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); |
492 | |
493 | if (flags) |
494 | setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags); |
495 | |
496 | setEGLattrib(EGL_NONE, EGL_NONE); |
497 | } |
498 | else |
499 | { |
500 | int index = 0; |
501 | |
502 | if (ctxconfig->client == GLFW_OPENGL_ES_API) |
503 | setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); |
504 | |
505 | setEGLattrib(EGL_NONE, EGL_NONE); |
506 | } |
507 | |
508 | // Context release behaviors (GL_KHR_context_flush_control) are not yet |
509 | // supported on EGL but are not a hard constraint, so ignore and continue |
510 | |
511 | window->context.egl.handle = eglCreateContext(_glfw.egl.display, |
512 | config, share, attribs); |
513 | |
514 | if (window->context.egl.handle == EGL_NO_CONTEXT) |
515 | { |
516 | _glfwInputError(GLFW_VERSION_UNAVAILABLE, |
517 | "EGL: Failed to create context: %s" , |
518 | getErrorString(eglGetError())); |
519 | return GLFW_FALSE; |
520 | } |
521 | |
522 | // Set up attributes for surface creation |
523 | { |
524 | int index = 0; |
525 | |
526 | if (fbconfig->sRGB) |
527 | { |
528 | if (_glfw.egl.KHR_gl_colorspace) |
529 | { |
530 | setEGLattrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); |
531 | } |
532 | } |
533 | |
534 | setEGLattrib(EGL_NONE, EGL_NONE); |
535 | } |
536 | |
537 | window->context.egl.surface = |
538 | eglCreateWindowSurface(_glfw.egl.display, |
539 | config, |
540 | _GLFW_EGL_NATIVE_WINDOW, |
541 | attribs); |
542 | if (window->context.egl.surface == EGL_NO_SURFACE) |
543 | { |
544 | _glfwInputError(GLFW_PLATFORM_ERROR, |
545 | "EGL: Failed to create window surface: %s" , |
546 | getErrorString(eglGetError())); |
547 | return GLFW_FALSE; |
548 | } |
549 | |
550 | window->context.egl.config = config; |
551 | |
552 | // Load the appropriate client library |
553 | { |
554 | int i; |
555 | const char** sonames; |
556 | const char* es1sonames[] = |
557 | { |
558 | #if defined(_GLFW_WIN32) |
559 | "GLESv1_CM.dll" , |
560 | "libGLES_CM.dll" , |
561 | #elif defined(_GLFW_COCOA) |
562 | "libGLESv1_CM.dylib" , |
563 | #else |
564 | "libGLESv1_CM.so.1" , |
565 | "libGLES_CM.so.1" , |
566 | #endif |
567 | NULL |
568 | }; |
569 | const char* es2sonames[] = |
570 | { |
571 | #if defined(_GLFW_WIN32) |
572 | "GLESv2.dll" , |
573 | "libGLESv2.dll" , |
574 | #elif defined(_GLFW_COCOA) |
575 | "libGLESv2.dylib" , |
576 | #else |
577 | "libGLESv2.so.2" , |
578 | #endif |
579 | NULL |
580 | }; |
581 | const char* glsonames[] = |
582 | { |
583 | #if defined(_GLFW_WIN32) |
584 | #elif defined(_GLFW_COCOA) |
585 | #else |
586 | "libGL.so.1" , |
587 | #endif |
588 | NULL |
589 | }; |
590 | |
591 | if (ctxconfig->client == GLFW_OPENGL_ES_API) |
592 | { |
593 | if (ctxconfig->major == 1) |
594 | sonames = es1sonames; |
595 | else |
596 | sonames = es2sonames; |
597 | } |
598 | else |
599 | sonames = glsonames; |
600 | |
601 | for (i = 0; sonames[i]; i++) |
602 | { |
603 | window->context.egl.client = _glfw_dlopen(sonames[i]); |
604 | if (window->context.egl.client) |
605 | break; |
606 | } |
607 | |
608 | if (!window->context.egl.client) |
609 | { |
610 | _glfwInputError(GLFW_API_UNAVAILABLE, |
611 | "EGL: Failed to load client library" ); |
612 | return GLFW_FALSE; |
613 | } |
614 | } |
615 | |
616 | window->context.makeCurrent = makeContextCurrent; |
617 | window->context.swapBuffers = swapBuffers; |
618 | window->context.swapInterval = swapInterval; |
619 | window->context.extensionSupported = extensionSupported; |
620 | window->context.getProcAddress = getProcAddress; |
621 | window->context.destroy = destroyContext; |
622 | |
623 | return GLFW_TRUE; |
624 | } |
625 | |
626 | #undef setEGLattrib |
627 | |
628 | // Returns the Visual and depth of the chosen EGLConfig |
629 | // |
630 | #if defined(_GLFW_X11) |
631 | GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, |
632 | const _GLFWfbconfig* fbconfig, |
633 | Visual** visual, int* depth) |
634 | { |
635 | XVisualInfo* result; |
636 | XVisualInfo desired; |
637 | EGLConfig native; |
638 | EGLint visualID = 0, count = 0; |
639 | const long vimask = VisualScreenMask | VisualIDMask; |
640 | |
641 | if (!chooseFBConfigs(ctxconfig, fbconfig, &native)) |
642 | { |
643 | _glfwInputError(GLFW_FORMAT_UNAVAILABLE, |
644 | "EGL: Failed to find a suitable EGLConfig" ); |
645 | return GLFW_FALSE; |
646 | } |
647 | |
648 | eglGetConfigAttrib(_glfw.egl.display, native, |
649 | EGL_NATIVE_VISUAL_ID, &visualID); |
650 | |
651 | desired.screen = _glfw.x11.screen; |
652 | desired.visualid = visualID; |
653 | |
654 | result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count); |
655 | if (!result) |
656 | { |
657 | _glfwInputError(GLFW_PLATFORM_ERROR, |
658 | "EGL: Failed to retrieve Visual for EGLConfig" ); |
659 | return GLFW_FALSE; |
660 | } |
661 | |
662 | *visual = result->visual; |
663 | *depth = result->depth; |
664 | |
665 | XFree(result); |
666 | return GLFW_TRUE; |
667 | } |
668 | #endif // _GLFW_X11 |
669 | |
670 | |
671 | ////////////////////////////////////////////////////////////////////////// |
672 | ////// GLFW native API ////// |
673 | ////////////////////////////////////////////////////////////////////////// |
674 | |
675 | GLFWAPI EGLDisplay glfwGetEGLDisplay(void) |
676 | { |
677 | _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY); |
678 | return _glfw.egl.display; |
679 | } |
680 | |
681 | GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) |
682 | { |
683 | _GLFWwindow* window = (_GLFWwindow*) handle; |
684 | _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); |
685 | |
686 | if (window->context.client == GLFW_NO_API) |
687 | { |
688 | _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); |
689 | return EGL_NO_CONTEXT; |
690 | } |
691 | |
692 | return window->context.egl.handle; |
693 | } |
694 | |
695 | GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) |
696 | { |
697 | _GLFWwindow* window = (_GLFWwindow*) handle; |
698 | _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); |
699 | |
700 | if (window->context.client == GLFW_NO_API) |
701 | { |
702 | _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); |
703 | return EGL_NO_SURFACE; |
704 | } |
705 | |
706 | return window->context.egl.surface; |
707 | } |
708 | |
709 | |