1 | /* |
2 | * Simple DirectMedia Layer |
3 | * Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | * |
5 | * This software is provided 'as-is', without any express or implied |
6 | * warranty. In no event will the authors be held liable for any damages |
7 | * arising from the use of this software. |
8 | * |
9 | * Permission is granted to anyone to use this software for any purpose, |
10 | * including commercial applications, and to alter it and redistribute it |
11 | * freely, subject to the following restrictions: |
12 | * |
13 | * 1. The origin of this software must not be misrepresented; you must not |
14 | * claim that you wrote the original software. If you use this software |
15 | * in a product, an acknowledgment in the product documentation would be |
16 | * appreciated but is not required. |
17 | * 2. Altered source versions must be plainly marked as such, and must not be |
18 | * misrepresented as being the original software. |
19 | * 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "../SDL_internal.h" |
22 | |
23 | #if SDL_VIDEO_OPENGL_EGL |
24 | |
25 | #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT |
26 | #include "../core/windows/SDL_windows.h" |
27 | #endif |
28 | #if SDL_VIDEO_DRIVER_ANDROID |
29 | #include <android/native_window.h> |
30 | #include "../core/android/SDL_android.h" |
31 | #endif |
32 | |
33 | #include "SDL_sysvideo.h" |
34 | #include "SDL_egl_c.h" |
35 | #include "SDL_loadso.h" |
36 | #include "SDL_hints.h" |
37 | |
38 | #ifdef EGL_KHR_create_context |
39 | /* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */ |
40 | #ifndef EGL_OPENGL_ES3_BIT_KHR |
41 | #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 |
42 | #endif |
43 | #endif /* EGL_KHR_create_context */ |
44 | |
45 | #if SDL_VIDEO_DRIVER_RPI |
46 | /* Raspbian places the OpenGL ES/EGL binaries in a non standard path */ |
47 | #define DEFAULT_EGL ( vc4 ? "libEGL.so.1" : "libbrcmEGL.so" ) |
48 | #define DEFAULT_OGL_ES2 ( vc4 ? "libGLESv2.so.2" : "libbrcmGLESv2.so" ) |
49 | #define ALT_EGL "libEGL.so" |
50 | #define ALT_OGL_ES2 "libGLESv2.so" |
51 | #define DEFAULT_OGL_ES_PVR ( vc4 ? "libGLES_CM.so.1" : "libbrcmGLESv2.so" ) |
52 | #define DEFAULT_OGL_ES ( vc4 ? "libGLESv1_CM.so.1" : "libbrcmGLESv2.so" ) |
53 | |
54 | #elif SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_VIVANTE |
55 | /* Android */ |
56 | #define DEFAULT_EGL "libEGL.so" |
57 | #define DEFAULT_OGL_ES2 "libGLESv2.so" |
58 | #define DEFAULT_OGL_ES_PVR "libGLES_CM.so" |
59 | #define DEFAULT_OGL_ES "libGLESv1_CM.so" |
60 | |
61 | #elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT |
62 | /* EGL AND OpenGL ES support via ANGLE */ |
63 | #define DEFAULT_EGL "libEGL.dll" |
64 | #define DEFAULT_OGL_ES2 "libGLESv2.dll" |
65 | #define DEFAULT_OGL_ES_PVR "libGLES_CM.dll" |
66 | #define DEFAULT_OGL_ES "libGLESv1_CM.dll" |
67 | |
68 | #elif SDL_VIDEO_DRIVER_COCOA |
69 | /* EGL AND OpenGL ES support via ANGLE */ |
70 | #define DEFAULT_EGL "libEGL.dylib" |
71 | #define DEFAULT_OGL_ES2 "libGLESv2.dylib" |
72 | #define DEFAULT_OGL_ES_PVR "libGLES_CM.dylib" //??? |
73 | #define DEFAULT_OGL_ES "libGLESv1_CM.dylib" //??? |
74 | |
75 | #elif defined(__OpenBSD__) |
76 | /* OpenBSD */ |
77 | #define DEFAULT_OGL "libGL.so" |
78 | #define DEFAULT_EGL "libEGL.so" |
79 | #define DEFAULT_OGL_ES2 "libGLESv2.so" |
80 | #define DEFAULT_OGL_ES_PVR "libGLES_CM.so" |
81 | #define DEFAULT_OGL_ES "libGLESv1_CM.so" |
82 | |
83 | #else |
84 | /* Desktop Linux/Unix-like */ |
85 | #define DEFAULT_OGL "libGL.so.1" |
86 | #define DEFAULT_EGL "libEGL.so.1" |
87 | #define ALT_OGL "libOpenGL.so.0" |
88 | #define DEFAULT_OGL_ES2 "libGLESv2.so.2" |
89 | #define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1" |
90 | #define DEFAULT_OGL_ES "libGLESv1_CM.so.1" |
91 | #endif /* SDL_VIDEO_DRIVER_RPI */ |
92 | |
93 | #if SDL_VIDEO_OPENGL |
94 | #include "SDL_opengl.h" |
95 | #endif |
96 | |
97 | /** If we happen to not have this defined because of an older EGL version, just define it 0x0 |
98 | as eglGetPlatformDisplayEXT will most likely be NULL if this is missing |
99 | */ |
100 | #ifndef EGL_PLATFORM_DEVICE_EXT |
101 | #define EGL_PLATFORM_DEVICE_EXT 0x0 |
102 | #endif |
103 | |
104 | #ifdef SDL_VIDEO_STATIC_ANGLE |
105 | #define LOAD_FUNC(NAME) \ |
106 | _this->egl_data->NAME = (void *)NAME; |
107 | #else |
108 | #define LOAD_FUNC(NAME) \ |
109 | _this->egl_data->NAME = SDL_LoadFunction(_this->egl_data->dll_handle, #NAME); \ |
110 | if (!_this->egl_data->NAME) \ |
111 | { \ |
112 | return SDL_SetError("Could not retrieve EGL function " #NAME); \ |
113 | } |
114 | #endif |
115 | |
116 | /* it is allowed to not have some of the EGL extensions on start - attempts to use them will fail later. */ |
117 | #define LOAD_FUNC_EGLEXT(NAME) \ |
118 | _this->egl_data->NAME = _this->egl_data->eglGetProcAddress(#NAME); |
119 | |
120 | |
121 | static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode) |
122 | { |
123 | #define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e; |
124 | switch (eglErrorCode) { |
125 | SDL_EGL_ERROR_TRANSLATE(EGL_SUCCESS); |
126 | SDL_EGL_ERROR_TRANSLATE(EGL_NOT_INITIALIZED); |
127 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ACCESS); |
128 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ALLOC); |
129 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ATTRIBUTE); |
130 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONTEXT); |
131 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONFIG); |
132 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CURRENT_SURFACE); |
133 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_DISPLAY); |
134 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_SURFACE); |
135 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_MATCH); |
136 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_PARAMETER); |
137 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_PIXMAP); |
138 | SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_WINDOW); |
139 | SDL_EGL_ERROR_TRANSLATE(EGL_CONTEXT_LOST); |
140 | } |
141 | return "" ; |
142 | } |
143 | |
144 | int SDL_EGL_SetErrorEx(const char * message, const char * eglFunctionName, EGLint eglErrorCode) |
145 | { |
146 | const char * errorText = SDL_EGL_GetErrorName(eglErrorCode); |
147 | char altErrorText[32]; |
148 | if (errorText[0] == '\0') { |
149 | /* An unknown-to-SDL error code was reported. Report its hexadecimal value, instead of its name. */ |
150 | SDL_snprintf(altErrorText, SDL_arraysize(altErrorText), "0x%x" , (unsigned int)eglErrorCode); |
151 | errorText = altErrorText; |
152 | } |
153 | return SDL_SetError("%s (call to %s failed, reporting an error of %s)" , message, eglFunctionName, errorText); |
154 | } |
155 | |
156 | /* EGL implementation of SDL OpenGL ES support */ |
157 | |
158 | SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext) |
159 | { |
160 | size_t ext_len; |
161 | const char *ext_override; |
162 | const char *egl_extstr; |
163 | const char *ext_start; |
164 | |
165 | /* Invalid extensions can be rejected early */ |
166 | if (ext == NULL || *ext == 0 || SDL_strchr(ext, ' ') != NULL) { |
167 | /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension"); */ |
168 | return SDL_FALSE; |
169 | } |
170 | |
171 | /* Extensions can be masked with an environment variable. |
172 | * Unlike the OpenGL override, this will use the set bits of an integer |
173 | * to disable the extension. |
174 | * Bit Action |
175 | * 0 If set, the display extension is masked and not present to SDL. |
176 | * 1 If set, the client extension is masked and not present to SDL. |
177 | */ |
178 | ext_override = SDL_getenv(ext); |
179 | if (ext_override != NULL) { |
180 | int disable_ext = SDL_atoi(ext_override); |
181 | if (disable_ext & 0x01 && type == SDL_EGL_DISPLAY_EXTENSION) { |
182 | return SDL_FALSE; |
183 | } else if (disable_ext & 0x02 && type == SDL_EGL_CLIENT_EXTENSION) { |
184 | return SDL_FALSE; |
185 | } |
186 | } |
187 | |
188 | ext_len = SDL_strlen(ext); |
189 | switch (type) { |
190 | case SDL_EGL_DISPLAY_EXTENSION: |
191 | egl_extstr = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS); |
192 | break; |
193 | case SDL_EGL_CLIENT_EXTENSION: |
194 | /* EGL_EXT_client_extensions modifies eglQueryString to return client extensions |
195 | * if EGL_NO_DISPLAY is passed. Implementations without it are required to return NULL. |
196 | * This behavior is included in EGL 1.5. |
197 | */ |
198 | egl_extstr = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); |
199 | break; |
200 | default: |
201 | /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type"); */ |
202 | return SDL_FALSE; |
203 | } |
204 | |
205 | if (egl_extstr != NULL) { |
206 | ext_start = egl_extstr; |
207 | |
208 | while (*ext_start) { |
209 | ext_start = SDL_strstr(ext_start, ext); |
210 | if (ext_start == NULL) { |
211 | return SDL_FALSE; |
212 | } |
213 | /* Check if the match is not just a substring of one of the extensions */ |
214 | if (ext_start == egl_extstr || *(ext_start - 1) == ' ') { |
215 | if (ext_start[ext_len] == ' ' || ext_start[ext_len] == 0) { |
216 | return SDL_TRUE; |
217 | } |
218 | } |
219 | /* If the search stopped in the middle of an extension, skip to the end of it */ |
220 | ext_start += ext_len; |
221 | while (*ext_start != ' ' && *ext_start != 0) { |
222 | ext_start++; |
223 | } |
224 | } |
225 | } |
226 | |
227 | return SDL_FALSE; |
228 | } |
229 | |
230 | void * |
231 | SDL_EGL_GetProcAddress(_THIS, const char *proc) |
232 | { |
233 | const Uint32 eglver = (((Uint32) _this->egl_data->egl_version_major) << 16) | ((Uint32) _this->egl_data->egl_version_minor); |
234 | const SDL_bool is_egl_15_or_later = eglver >= ((((Uint32) 1) << 16) | 5); |
235 | void *retval = NULL; |
236 | |
237 | /* EGL 1.5 can use eglGetProcAddress() for any symbol. 1.4 and earlier can't use it for core entry points. */ |
238 | if (!retval && is_egl_15_or_later && _this->egl_data->eglGetProcAddress) { |
239 | retval = _this->egl_data->eglGetProcAddress(proc); |
240 | } |
241 | |
242 | #ifndef __EMSCRIPTEN__ /* LoadFunction isn't needed on Emscripten and will call dlsym(), causing other problems. */ |
243 | /* Try SDL_LoadFunction() first for EGL <= 1.4, or as a fallback for >= 1.5. */ |
244 | if (!retval) { |
245 | static char procname[64]; |
246 | retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc); |
247 | /* just in case you need an underscore prepended... */ |
248 | if (!retval && (SDL_strlen(proc) < (sizeof (procname) - 1))) { |
249 | procname[0] = '_'; |
250 | SDL_strlcpy(procname + 1, proc, sizeof (procname) - 1); |
251 | retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname); |
252 | } |
253 | } |
254 | #endif |
255 | |
256 | /* Try eglGetProcAddress if we're on <= 1.4 and still searching... */ |
257 | if (!retval && !is_egl_15_or_later && _this->egl_data->eglGetProcAddress) { |
258 | retval = _this->egl_data->eglGetProcAddress(proc); |
259 | if (retval) { |
260 | return retval; |
261 | } |
262 | } |
263 | |
264 | return retval; |
265 | } |
266 | |
267 | void |
268 | SDL_EGL_UnloadLibrary(_THIS) |
269 | { |
270 | if (_this->egl_data) { |
271 | if (_this->egl_data->egl_display) { |
272 | _this->egl_data->eglTerminate(_this->egl_data->egl_display); |
273 | _this->egl_data->egl_display = NULL; |
274 | } |
275 | |
276 | if (_this->egl_data->dll_handle) { |
277 | SDL_UnloadObject(_this->egl_data->dll_handle); |
278 | _this->egl_data->dll_handle = NULL; |
279 | } |
280 | if (_this->egl_data->egl_dll_handle) { |
281 | SDL_UnloadObject(_this->egl_data->egl_dll_handle); |
282 | _this->egl_data->egl_dll_handle = NULL; |
283 | } |
284 | |
285 | SDL_free(_this->egl_data); |
286 | _this->egl_data = NULL; |
287 | } |
288 | } |
289 | |
290 | int |
291 | SDL_EGL_LoadLibraryOnly(_THIS, const char *egl_path) |
292 | { |
293 | void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */ |
294 | const char *path = NULL; |
295 | #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT |
296 | const char *d3dcompiler; |
297 | #endif |
298 | #if SDL_VIDEO_DRIVER_RPI |
299 | SDL_bool vc4 = (0 == access("/sys/module/vc4/" , F_OK)); |
300 | #endif |
301 | |
302 | if (_this->egl_data) { |
303 | return SDL_SetError("EGL context already created" ); |
304 | } |
305 | |
306 | _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData)); |
307 | if (!_this->egl_data) { |
308 | return SDL_OutOfMemory(); |
309 | } |
310 | |
311 | #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT |
312 | d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER); |
313 | if (d3dcompiler) { |
314 | if (SDL_strcasecmp(d3dcompiler, "none" ) != 0) { |
315 | if (SDL_LoadObject(d3dcompiler) == NULL) { |
316 | SDL_ClearError(); |
317 | } |
318 | } |
319 | } else { |
320 | if (WIN_IsWindowsVistaOrGreater()) { |
321 | /* Try the newer d3d compilers first */ |
322 | const char *d3dcompiler_list[] = { |
323 | "d3dcompiler_47.dll" , "d3dcompiler_46.dll" , |
324 | }; |
325 | int i; |
326 | |
327 | for (i = 0; i < SDL_arraysize(d3dcompiler_list); ++i) { |
328 | if (SDL_LoadObject(d3dcompiler_list[i]) != NULL) { |
329 | break; |
330 | } |
331 | SDL_ClearError(); |
332 | } |
333 | } else { |
334 | if (SDL_LoadObject("d3dcompiler_43.dll" ) == NULL) { |
335 | SDL_ClearError(); |
336 | } |
337 | } |
338 | } |
339 | #endif |
340 | |
341 | #ifndef SDL_VIDEO_STATIC_ANGLE |
342 | /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */ |
343 | path = SDL_getenv("SDL_VIDEO_GL_DRIVER" ); |
344 | if (path != NULL) { |
345 | egl_dll_handle = SDL_LoadObject(path); |
346 | } |
347 | |
348 | if (egl_dll_handle == NULL) { |
349 | if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { |
350 | if (_this->gl_config.major_version > 1) { |
351 | path = DEFAULT_OGL_ES2; |
352 | egl_dll_handle = SDL_LoadObject(path); |
353 | #ifdef ALT_OGL_ES2 |
354 | if (egl_dll_handle == NULL && !vc4) { |
355 | path = ALT_OGL_ES2; |
356 | egl_dll_handle = SDL_LoadObject(path); |
357 | } |
358 | #endif |
359 | |
360 | } else { |
361 | path = DEFAULT_OGL_ES; |
362 | egl_dll_handle = SDL_LoadObject(path); |
363 | if (egl_dll_handle == NULL) { |
364 | path = DEFAULT_OGL_ES_PVR; |
365 | egl_dll_handle = SDL_LoadObject(path); |
366 | } |
367 | #ifdef ALT_OGL_ES2 |
368 | if (egl_dll_handle == NULL && !vc4) { |
369 | path = ALT_OGL_ES2; |
370 | egl_dll_handle = SDL_LoadObject(path); |
371 | } |
372 | #endif |
373 | } |
374 | } |
375 | #ifdef DEFAULT_OGL |
376 | else { |
377 | path = DEFAULT_OGL; |
378 | egl_dll_handle = SDL_LoadObject(path); |
379 | #ifdef ALT_OGL |
380 | if (egl_dll_handle == NULL) { |
381 | path = ALT_OGL; |
382 | egl_dll_handle = SDL_LoadObject(path); |
383 | } |
384 | #endif |
385 | } |
386 | #endif |
387 | } |
388 | _this->egl_data->egl_dll_handle = egl_dll_handle; |
389 | |
390 | if (egl_dll_handle == NULL) { |
391 | return SDL_SetError("Could not initialize OpenGL / GLES library" ); |
392 | } |
393 | |
394 | /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */ |
395 | if (egl_path != NULL) { |
396 | dll_handle = SDL_LoadObject(egl_path); |
397 | } |
398 | /* Try loading a EGL symbol, if it does not work try the default library paths */ |
399 | if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig" ) == NULL) { |
400 | if (dll_handle != NULL) { |
401 | SDL_UnloadObject(dll_handle); |
402 | } |
403 | path = SDL_getenv("SDL_VIDEO_EGL_DRIVER" ); |
404 | if (path == NULL) { |
405 | path = DEFAULT_EGL; |
406 | } |
407 | dll_handle = SDL_LoadObject(path); |
408 | |
409 | #ifdef ALT_EGL |
410 | if (dll_handle == NULL && !vc4) { |
411 | path = ALT_EGL; |
412 | dll_handle = SDL_LoadObject(path); |
413 | } |
414 | #endif |
415 | |
416 | if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig" ) == NULL) { |
417 | if (dll_handle != NULL) { |
418 | SDL_UnloadObject(dll_handle); |
419 | } |
420 | return SDL_SetError("Could not load EGL library" ); |
421 | } |
422 | SDL_ClearError(); |
423 | } |
424 | #endif |
425 | |
426 | _this->egl_data->dll_handle = dll_handle; |
427 | |
428 | /* Load new function pointers */ |
429 | LOAD_FUNC(eglGetDisplay); |
430 | LOAD_FUNC(eglInitialize); |
431 | LOAD_FUNC(eglTerminate); |
432 | LOAD_FUNC(eglGetProcAddress); |
433 | LOAD_FUNC(eglChooseConfig); |
434 | LOAD_FUNC(eglGetConfigAttrib); |
435 | LOAD_FUNC(eglCreateContext); |
436 | LOAD_FUNC(eglDestroyContext); |
437 | LOAD_FUNC(eglCreatePbufferSurface); |
438 | LOAD_FUNC(eglCreateWindowSurface); |
439 | LOAD_FUNC(eglDestroySurface); |
440 | LOAD_FUNC(eglMakeCurrent); |
441 | LOAD_FUNC(eglSwapBuffers); |
442 | LOAD_FUNC(eglSwapInterval); |
443 | LOAD_FUNC(eglWaitNative); |
444 | LOAD_FUNC(eglWaitGL); |
445 | LOAD_FUNC(eglBindAPI); |
446 | LOAD_FUNC(eglQueryAPI); |
447 | LOAD_FUNC(eglQueryString); |
448 | LOAD_FUNC(eglGetError); |
449 | LOAD_FUNC_EGLEXT(eglQueryDevicesEXT); |
450 | LOAD_FUNC_EGLEXT(eglGetPlatformDisplayEXT); |
451 | /* Atomic functions */ |
452 | LOAD_FUNC_EGLEXT(eglCreateSyncKHR); |
453 | LOAD_FUNC_EGLEXT(eglDestroySyncKHR); |
454 | LOAD_FUNC_EGLEXT(eglDupNativeFenceFDANDROID); |
455 | LOAD_FUNC_EGLEXT(eglWaitSyncKHR); |
456 | LOAD_FUNC_EGLEXT(eglClientWaitSyncKHR); |
457 | /* Atomic functions end */ |
458 | |
459 | if (path) { |
460 | SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1); |
461 | } else { |
462 | *_this->gl_config.driver_path = '\0'; |
463 | } |
464 | |
465 | return 0; |
466 | } |
467 | |
468 | static void |
469 | SDL_EGL_GetVersion(_THIS) { |
470 | if (_this->egl_data->eglQueryString) { |
471 | const char *egl_version = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_VERSION); |
472 | if (egl_version) { |
473 | int major = 0, minor = 0; |
474 | if (SDL_sscanf(egl_version, "%d.%d" , &major, &minor) == 2) { |
475 | _this->egl_data->egl_version_major = major; |
476 | _this->egl_data->egl_version_minor = minor; |
477 | } else { |
478 | SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s" , egl_version); |
479 | } |
480 | } |
481 | } |
482 | } |
483 | |
484 | int |
485 | SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform) |
486 | { |
487 | int egl_version_major, egl_version_minor; |
488 | int library_load_retcode = SDL_EGL_LoadLibraryOnly(_this, egl_path); |
489 | if (library_load_retcode != 0) { |
490 | return library_load_retcode; |
491 | } |
492 | |
493 | /* EGL 1.5 allows querying for client version with EGL_NO_DISPLAY */ |
494 | SDL_EGL_GetVersion(_this); |
495 | |
496 | egl_version_major = _this->egl_data->egl_version_major; |
497 | egl_version_minor = _this->egl_data->egl_version_minor; |
498 | |
499 | if (egl_version_major == 1 && egl_version_minor == 5) { |
500 | LOAD_FUNC(eglGetPlatformDisplay); |
501 | } |
502 | |
503 | _this->egl_data->egl_display = EGL_NO_DISPLAY; |
504 | #if !defined(__WINRT__) |
505 | if (platform) { |
506 | if (egl_version_major == 1 && egl_version_minor == 5) { |
507 | _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(size_t)native_display, NULL); |
508 | } else { |
509 | if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base" )) { |
510 | _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT" ); |
511 | if (_this->egl_data->eglGetPlatformDisplayEXT) { |
512 | _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, (void *)(size_t)native_display, NULL); |
513 | } |
514 | } |
515 | } |
516 | } |
517 | /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */ |
518 | if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { |
519 | _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display); |
520 | } |
521 | if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { |
522 | _this->gl_config.driver_loaded = 0; |
523 | *_this->gl_config.driver_path = '\0'; |
524 | return SDL_SetError("Could not get EGL display" ); |
525 | } |
526 | |
527 | if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { |
528 | _this->gl_config.driver_loaded = 0; |
529 | *_this->gl_config.driver_path = '\0'; |
530 | return SDL_SetError("Could not initialize EGL" ); |
531 | } |
532 | #endif |
533 | |
534 | /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */ |
535 | SDL_EGL_GetVersion(_this); |
536 | |
537 | _this->egl_data->is_offscreen = 0; |
538 | |
539 | return 0; |
540 | } |
541 | |
542 | /** |
543 | On multi GPU machines EGL device 0 is not always the first valid GPU. |
544 | Container environments can restrict access to some GPUs that are still listed in the EGL |
545 | device list. If the requested device is a restricted GPU and cannot be used |
546 | (eglInitialize() will fail) then attempt to automatically and silently select the next |
547 | valid available GPU for EGL to use. |
548 | */ |
549 | |
550 | int |
551 | SDL_EGL_InitializeOffscreen(_THIS, int device) |
552 | { |
553 | void *egl_devices[SDL_EGL_MAX_DEVICES]; |
554 | EGLint num_egl_devices = 0; |
555 | const char *egl_device_hint; |
556 | |
557 | if (_this->gl_config.driver_loaded != 1) { |
558 | return SDL_SetError("SDL_EGL_LoadLibraryOnly() has not been called or has failed." ); |
559 | } |
560 | |
561 | /* Check for all extensions that are optional until used and fail if any is missing */ |
562 | if (_this->egl_data->eglQueryDevicesEXT == NULL) { |
563 | return SDL_SetError("eglQueryDevicesEXT is missing (EXT_device_enumeration not supported by the drivers?)" ); |
564 | } |
565 | |
566 | if (_this->egl_data->eglGetPlatformDisplayEXT == NULL) { |
567 | return SDL_SetError("eglGetPlatformDisplayEXT is missing (EXT_platform_base not supported by the drivers?)" ); |
568 | } |
569 | |
570 | if (_this->egl_data->eglQueryDevicesEXT(SDL_EGL_MAX_DEVICES, egl_devices, &num_egl_devices) != EGL_TRUE) { |
571 | return SDL_SetError("eglQueryDevicesEXT() failed" ); |
572 | } |
573 | |
574 | egl_device_hint = SDL_GetHint("SDL_HINT_EGL_DEVICE" ); |
575 | if (egl_device_hint) { |
576 | device = SDL_atoi(egl_device_hint); |
577 | |
578 | if (device >= num_egl_devices) { |
579 | return SDL_SetError("Invalid EGL device is requested." ); |
580 | } |
581 | |
582 | _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[device], NULL); |
583 | |
584 | if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { |
585 | return SDL_SetError("eglGetPlatformDisplayEXT() failed." ); |
586 | } |
587 | |
588 | if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { |
589 | return SDL_SetError("Could not initialize EGL" ); |
590 | } |
591 | } |
592 | else { |
593 | int i; |
594 | SDL_bool found = SDL_FALSE; |
595 | EGLDisplay attempted_egl_display; |
596 | |
597 | /* If no hint is provided lets look for the first device/display that will allow us to eglInit */ |
598 | for (i = 0; i < num_egl_devices; i++) { |
599 | attempted_egl_display = _this->egl_data->eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[i], NULL); |
600 | |
601 | if (attempted_egl_display == EGL_NO_DISPLAY) { |
602 | continue; |
603 | } |
604 | |
605 | if (_this->egl_data->eglInitialize(attempted_egl_display, NULL, NULL) != EGL_TRUE) { |
606 | _this->egl_data->eglTerminate(attempted_egl_display); |
607 | continue; |
608 | } |
609 | |
610 | /* We did not fail, we'll pick this one! */ |
611 | _this->egl_data->egl_display = attempted_egl_display; |
612 | found = SDL_TRUE; |
613 | |
614 | break; |
615 | } |
616 | |
617 | if (!found) { |
618 | return SDL_SetError("Could not find a valid EGL device to initialize" ); |
619 | } |
620 | } |
621 | |
622 | /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */ |
623 | SDL_EGL_GetVersion(_this); |
624 | |
625 | _this->egl_data->is_offscreen = 1; |
626 | |
627 | return 0; |
628 | } |
629 | |
630 | void |
631 | SDL_EGL_SetRequiredVisualId(_THIS, int visual_id) |
632 | { |
633 | _this->egl_data->egl_required_visual_id=visual_id; |
634 | } |
635 | |
636 | #ifdef DUMP_EGL_CONFIG |
637 | |
638 | #define ATTRIBUTE(_attr) { _attr, #_attr } |
639 | |
640 | typedef struct { |
641 | EGLint attribute; |
642 | char const* name; |
643 | } Attribute; |
644 | |
645 | Attribute attributes[] = { |
646 | ATTRIBUTE( EGL_BUFFER_SIZE ), |
647 | ATTRIBUTE( EGL_ALPHA_SIZE ), |
648 | ATTRIBUTE( EGL_BLUE_SIZE ), |
649 | ATTRIBUTE( EGL_GREEN_SIZE ), |
650 | ATTRIBUTE( EGL_RED_SIZE ), |
651 | ATTRIBUTE( EGL_DEPTH_SIZE ), |
652 | ATTRIBUTE( EGL_STENCIL_SIZE ), |
653 | ATTRIBUTE( EGL_CONFIG_CAVEAT ), |
654 | ATTRIBUTE( EGL_CONFIG_ID ), |
655 | ATTRIBUTE( EGL_LEVEL ), |
656 | ATTRIBUTE( EGL_MAX_PBUFFER_HEIGHT ), |
657 | ATTRIBUTE( EGL_MAX_PBUFFER_WIDTH ), |
658 | ATTRIBUTE( EGL_MAX_PBUFFER_PIXELS ), |
659 | ATTRIBUTE( EGL_NATIVE_RENDERABLE ), |
660 | ATTRIBUTE( EGL_NATIVE_VISUAL_ID ), |
661 | ATTRIBUTE( EGL_NATIVE_VISUAL_TYPE ), |
662 | ATTRIBUTE( EGL_SAMPLES ), |
663 | ATTRIBUTE( EGL_SAMPLE_BUFFERS ), |
664 | ATTRIBUTE( EGL_SURFACE_TYPE ), |
665 | ATTRIBUTE( EGL_TRANSPARENT_TYPE ), |
666 | ATTRIBUTE( EGL_TRANSPARENT_BLUE_VALUE ), |
667 | ATTRIBUTE( EGL_TRANSPARENT_GREEN_VALUE ), |
668 | ATTRIBUTE( EGL_TRANSPARENT_RED_VALUE ), |
669 | ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGB ), |
670 | ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGBA ), |
671 | ATTRIBUTE( EGL_MIN_SWAP_INTERVAL ), |
672 | ATTRIBUTE( EGL_MAX_SWAP_INTERVAL ), |
673 | ATTRIBUTE( EGL_LUMINANCE_SIZE ), |
674 | ATTRIBUTE( EGL_ALPHA_MASK_SIZE ), |
675 | ATTRIBUTE( EGL_COLOR_BUFFER_TYPE ), |
676 | ATTRIBUTE( EGL_RENDERABLE_TYPE ), |
677 | ATTRIBUTE( EGL_MATCH_NATIVE_PIXMAP ), |
678 | ATTRIBUTE( EGL_CONFORMANT ), |
679 | }; |
680 | |
681 | |
682 | static void dumpconfig(_THIS, EGLConfig config) |
683 | { |
684 | int attr; |
685 | for (attr = 0 ; attr<sizeof(attributes)/sizeof(Attribute) ; attr++) { |
686 | EGLint value; |
687 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, config, attributes[attr].attribute, &value); |
688 | SDL_Log("\t%-32s: %10d (0x%08x)\n" , attributes[attr].name, value, value); |
689 | } |
690 | } |
691 | |
692 | #endif /* DUMP_EGL_CONFIG */ |
693 | |
694 | int |
695 | SDL_EGL_ChooseConfig(_THIS) |
696 | { |
697 | /* 64 seems nice. */ |
698 | EGLint attribs[64]; |
699 | EGLint found_configs = 0, value; |
700 | /* 128 seems even nicer here */ |
701 | EGLConfig configs[128]; |
702 | SDL_bool has_matching_format = SDL_FALSE; |
703 | int i, j, best_bitdiff = -1, best_truecolor_bitdiff = -1; |
704 | int truecolor_config_idx = -1; |
705 | |
706 | if (!_this->egl_data) { |
707 | /* The EGL library wasn't loaded, SDL_GetError() should have info */ |
708 | return -1; |
709 | } |
710 | |
711 | /* Get a valid EGL configuration */ |
712 | i = 0; |
713 | attribs[i++] = EGL_RED_SIZE; |
714 | attribs[i++] = _this->gl_config.red_size; |
715 | attribs[i++] = EGL_GREEN_SIZE; |
716 | attribs[i++] = _this->gl_config.green_size; |
717 | attribs[i++] = EGL_BLUE_SIZE; |
718 | attribs[i++] = _this->gl_config.blue_size; |
719 | |
720 | if (_this->gl_config.alpha_size) { |
721 | attribs[i++] = EGL_ALPHA_SIZE; |
722 | attribs[i++] = _this->gl_config.alpha_size; |
723 | } |
724 | |
725 | if (_this->gl_config.buffer_size) { |
726 | attribs[i++] = EGL_BUFFER_SIZE; |
727 | attribs[i++] = _this->gl_config.buffer_size; |
728 | } |
729 | |
730 | attribs[i++] = EGL_DEPTH_SIZE; |
731 | attribs[i++] = _this->gl_config.depth_size; |
732 | |
733 | if (_this->gl_config.stencil_size) { |
734 | attribs[i++] = EGL_STENCIL_SIZE; |
735 | attribs[i++] = _this->gl_config.stencil_size; |
736 | } |
737 | |
738 | if (_this->gl_config.multisamplebuffers) { |
739 | attribs[i++] = EGL_SAMPLE_BUFFERS; |
740 | attribs[i++] = _this->gl_config.multisamplebuffers; |
741 | } |
742 | |
743 | if (_this->gl_config.multisamplesamples) { |
744 | attribs[i++] = EGL_SAMPLES; |
745 | attribs[i++] = _this->gl_config.multisamplesamples; |
746 | } |
747 | |
748 | if (_this->egl_data->is_offscreen) { |
749 | attribs[i++] = EGL_SURFACE_TYPE; |
750 | attribs[i++] = EGL_PBUFFER_BIT; |
751 | } |
752 | |
753 | attribs[i++] = EGL_RENDERABLE_TYPE; |
754 | if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { |
755 | #ifdef EGL_KHR_create_context |
756 | if (_this->gl_config.major_version >= 3 && |
757 | SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context" )) { |
758 | attribs[i++] = EGL_OPENGL_ES3_BIT_KHR; |
759 | } else |
760 | #endif |
761 | if (_this->gl_config.major_version >= 2) { |
762 | attribs[i++] = EGL_OPENGL_ES2_BIT; |
763 | } else { |
764 | attribs[i++] = EGL_OPENGL_ES_BIT; |
765 | } |
766 | _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); |
767 | } else { |
768 | attribs[i++] = EGL_OPENGL_BIT; |
769 | _this->egl_data->eglBindAPI(EGL_OPENGL_API); |
770 | } |
771 | |
772 | if (_this->egl_data->egl_surfacetype) { |
773 | attribs[i++] = EGL_SURFACE_TYPE; |
774 | attribs[i++] = _this->egl_data->egl_surfacetype; |
775 | } |
776 | |
777 | attribs[i++] = EGL_NONE; |
778 | |
779 | SDL_assert(i < SDL_arraysize(attribs)); |
780 | |
781 | if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display, |
782 | attribs, |
783 | configs, SDL_arraysize(configs), |
784 | &found_configs) == EGL_FALSE || |
785 | found_configs == 0) { |
786 | return SDL_EGL_SetError("Couldn't find matching EGL config" , "eglChooseConfig" ); |
787 | } |
788 | |
789 | /* first ensure that a found config has a matching format, or the function will fall through. */ |
790 | if (_this->egl_data->egl_required_visual_id) |
791 | { |
792 | for (i = 0; i < found_configs; i++ ) { |
793 | EGLint format; |
794 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, |
795 | configs[i], |
796 | EGL_NATIVE_VISUAL_ID, &format); |
797 | if (_this->egl_data->egl_required_visual_id == format) { |
798 | has_matching_format = SDL_TRUE; |
799 | break; |
800 | } |
801 | } |
802 | } |
803 | |
804 | /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */ |
805 | /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */ |
806 | |
807 | for (i = 0; i < found_configs; i++ ) { |
808 | SDL_bool is_truecolor = SDL_FALSE; |
809 | int bitdiff = 0; |
810 | |
811 | if (has_matching_format && _this->egl_data->egl_required_visual_id) { |
812 | EGLint format; |
813 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, |
814 | configs[i], |
815 | EGL_NATIVE_VISUAL_ID, &format); |
816 | if (_this->egl_data->egl_required_visual_id != format) { |
817 | continue; |
818 | } |
819 | } |
820 | |
821 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], EGL_RED_SIZE, &value); |
822 | if (value == 8) { |
823 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], EGL_GREEN_SIZE, &value); |
824 | if (value == 8) { |
825 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], EGL_BLUE_SIZE, &value); |
826 | if (value == 8) { |
827 | is_truecolor = SDL_TRUE; |
828 | } |
829 | } |
830 | } |
831 | |
832 | for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) { |
833 | if (attribs[j] == EGL_NONE) { |
834 | break; |
835 | } |
836 | |
837 | if ( attribs[j+1] != EGL_DONT_CARE && ( |
838 | attribs[j] == EGL_RED_SIZE || |
839 | attribs[j] == EGL_GREEN_SIZE || |
840 | attribs[j] == EGL_BLUE_SIZE || |
841 | attribs[j] == EGL_ALPHA_SIZE || |
842 | attribs[j] == EGL_DEPTH_SIZE || |
843 | attribs[j] == EGL_STENCIL_SIZE)) { |
844 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value); |
845 | bitdiff += value - attribs[j + 1]; /* value is always >= attrib */ |
846 | } |
847 | } |
848 | |
849 | if ((bitdiff < best_bitdiff) || (best_bitdiff == -1)) { |
850 | _this->egl_data->egl_config = configs[i]; |
851 | best_bitdiff = bitdiff; |
852 | } |
853 | |
854 | if (is_truecolor && ((bitdiff < best_truecolor_bitdiff) || (best_truecolor_bitdiff == -1))) { |
855 | truecolor_config_idx = i; |
856 | best_truecolor_bitdiff = bitdiff; |
857 | } |
858 | } |
859 | |
860 | #define FAVOR_TRUECOLOR 1 |
861 | #if FAVOR_TRUECOLOR |
862 | /* Some apps request a low color depth, either because they _assume_ |
863 | they'll get a larger one but don't want to fail if only smaller ones |
864 | are available, or they just never called SDL_GL_SetAttribute at all and |
865 | got a tiny default. For these cases, a game that would otherwise run |
866 | at 24-bit color might get dithered down to something smaller, which is |
867 | worth avoiding. If the app requested <= 16 bit color and an exact 24-bit |
868 | match is available, favor that. Otherwise, we look for the closest |
869 | match. Note that while the API promises what you request _or better_, |
870 | it's feasible this can be disastrous for performance for custom software |
871 | on small hardware that all expected to actually get 16-bit color. In this |
872 | case, turn off FAVOR_TRUECOLOR (and maybe send a patch to make this more |
873 | flexible). */ |
874 | if ( ((_this->gl_config.red_size + _this->gl_config.blue_size + _this->gl_config.green_size) <= 16) ) { |
875 | if (truecolor_config_idx != -1) { |
876 | _this->egl_data->egl_config = configs[truecolor_config_idx]; |
877 | } |
878 | } |
879 | #endif |
880 | |
881 | #ifdef DUMP_EGL_CONFIG |
882 | dumpconfig(_this, _this->egl_data->egl_config); |
883 | #endif |
884 | |
885 | return 0; |
886 | } |
887 | |
888 | SDL_GLContext |
889 | SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) |
890 | { |
891 | /* max 14 values plus terminator. */ |
892 | EGLint attribs[15]; |
893 | int attr = 0; |
894 | |
895 | EGLContext egl_context, share_context = EGL_NO_CONTEXT; |
896 | EGLint profile_mask = _this->gl_config.profile_mask; |
897 | EGLint major_version = _this->gl_config.major_version; |
898 | EGLint minor_version = _this->gl_config.minor_version; |
899 | SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES); |
900 | |
901 | if (!_this->egl_data) { |
902 | /* The EGL library wasn't loaded, SDL_GetError() should have info */ |
903 | return NULL; |
904 | } |
905 | |
906 | if (_this->gl_config.share_with_current_context) { |
907 | share_context = (EGLContext)SDL_GL_GetCurrentContext(); |
908 | } |
909 | |
910 | #if SDL_VIDEO_DRIVER_ANDROID |
911 | if ((_this->gl_config.flags & SDL_GL_CONTEXT_DEBUG_FLAG) != 0) { |
912 | /* If SDL_GL_CONTEXT_DEBUG_FLAG is set but EGL_KHR_debug unsupported, unset. |
913 | * This is required because some Android devices like to complain about it |
914 | * by "silently" failing, logging a hint which could be easily overlooked: |
915 | * E/libEGL (26984): validate_display:255 error 3008 (EGL_BAD_DISPLAY) |
916 | * The following explicitly checks for EGL_KHR_debug before EGL 1.5 |
917 | */ |
918 | int egl_version_major = _this->egl_data->egl_version_major; |
919 | int egl_version_minor = _this->egl_data->egl_version_minor; |
920 | if (((egl_version_major < 1) || (egl_version_major == 1 && egl_version_minor < 5)) && |
921 | !SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_debug" )) { |
922 | /* SDL profile bits match EGL profile bits. */ |
923 | _this->gl_config.flags &= ~SDL_GL_CONTEXT_DEBUG_FLAG; |
924 | } |
925 | } |
926 | #endif |
927 | |
928 | /* Set the context version and other attributes. */ |
929 | if ((major_version < 3 || (minor_version == 0 && profile_es)) && |
930 | _this->gl_config.flags == 0 && |
931 | (profile_mask == 0 || profile_es)) { |
932 | /* Create a context without using EGL_KHR_create_context attribs. |
933 | * When creating a GLES context without EGL_KHR_create_context we can |
934 | * only specify the major version. When creating a desktop GL context |
935 | * we can't specify any version, so we only try in that case when the |
936 | * version is less than 3.0 (matches SDL's GLX/WGL behavior.) |
937 | */ |
938 | if (profile_es) { |
939 | attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION; |
940 | attribs[attr++] = SDL_max(major_version, 1); |
941 | } |
942 | } else { |
943 | #ifdef EGL_KHR_create_context |
944 | /* The Major/minor version, context profiles, and context flags can |
945 | * only be specified when this extension is available. |
946 | */ |
947 | if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context" )) { |
948 | attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR; |
949 | attribs[attr++] = major_version; |
950 | attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR; |
951 | attribs[attr++] = minor_version; |
952 | |
953 | /* SDL profile bits match EGL profile bits. */ |
954 | if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) { |
955 | attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; |
956 | attribs[attr++] = profile_mask; |
957 | } |
958 | |
959 | /* SDL flags match EGL flags. */ |
960 | if (_this->gl_config.flags != 0) { |
961 | attribs[attr++] = EGL_CONTEXT_FLAGS_KHR; |
962 | attribs[attr++] = _this->gl_config.flags; |
963 | } |
964 | } else |
965 | #endif /* EGL_KHR_create_context */ |
966 | { |
967 | SDL_SetError("Could not create EGL context (context attributes are not supported)" ); |
968 | return NULL; |
969 | } |
970 | } |
971 | |
972 | if (_this->gl_config.no_error) { |
973 | #ifdef EGL_KHR_create_context_no_error |
974 | if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context_no_error" )) { |
975 | attribs[attr++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; |
976 | attribs[attr++] = _this->gl_config.no_error; |
977 | } else |
978 | #endif |
979 | { |
980 | SDL_SetError("EGL implementation does not support no_error contexts" ); |
981 | return NULL; |
982 | } |
983 | } |
984 | |
985 | attribs[attr++] = EGL_NONE; |
986 | |
987 | /* Bind the API */ |
988 | if (profile_es) { |
989 | _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); |
990 | } else { |
991 | _this->egl_data->eglBindAPI(EGL_OPENGL_API); |
992 | } |
993 | |
994 | egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display, |
995 | _this->egl_data->egl_config, |
996 | share_context, attribs); |
997 | |
998 | if (egl_context == EGL_NO_CONTEXT) { |
999 | SDL_EGL_SetError("Could not create EGL context" , "eglCreateContext" ); |
1000 | return NULL; |
1001 | } |
1002 | |
1003 | _this->egl_data->egl_swapinterval = 0; |
1004 | |
1005 | if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) { |
1006 | /* Save the SDL error set by SDL_EGL_MakeCurrent */ |
1007 | char errorText[1024]; |
1008 | SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText)); |
1009 | |
1010 | /* Delete the context, which may alter the value returned by SDL_GetError() */ |
1011 | SDL_EGL_DeleteContext(_this, egl_context); |
1012 | |
1013 | /* Restore the SDL error */ |
1014 | SDL_SetError("%s" , errorText); |
1015 | |
1016 | return NULL; |
1017 | } |
1018 | |
1019 | /* Check whether making contexts current without a surface is supported. |
1020 | * First condition: EGL must support it. That's the case for EGL 1.5 |
1021 | * or later, or if the EGL_KHR_surfaceless_context extension is present. */ |
1022 | if ((_this->egl_data->egl_version_major > 1) || |
1023 | ((_this->egl_data->egl_version_major == 1) && (_this->egl_data->egl_version_minor >= 5)) || |
1024 | SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_surfaceless_context" )) |
1025 | { |
1026 | /* Secondary condition: The client API must support it. */ |
1027 | if (profile_es) { |
1028 | /* On OpenGL ES, the GL_OES_surfaceless_context extension must be |
1029 | * present. */ |
1030 | if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context" )) { |
1031 | _this->gl_allow_no_surface = SDL_TRUE; |
1032 | } |
1033 | #if SDL_VIDEO_OPENGL |
1034 | } else { |
1035 | /* Desktop OpenGL supports it by default from version 3.0 on. */ |
1036 | void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); |
1037 | glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv" ); |
1038 | if (glGetIntegervFunc) { |
1039 | GLint v = 0; |
1040 | glGetIntegervFunc(GL_MAJOR_VERSION, &v); |
1041 | if (v >= 3) { |
1042 | _this->gl_allow_no_surface = SDL_TRUE; |
1043 | } |
1044 | } |
1045 | #endif |
1046 | } |
1047 | } |
1048 | |
1049 | return (SDL_GLContext) egl_context; |
1050 | } |
1051 | |
1052 | int |
1053 | SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context) |
1054 | { |
1055 | EGLContext egl_context = (EGLContext) context; |
1056 | |
1057 | if (!_this->egl_data) { |
1058 | return SDL_SetError("OpenGL not initialized" ); |
1059 | } |
1060 | |
1061 | /* The android emulator crashes badly if you try to eglMakeCurrent |
1062 | * with a valid context and invalid surface, so we have to check for both here. |
1063 | */ |
1064 | if (!egl_context || (!egl_surface && !_this->gl_allow_no_surface)) { |
1065 | _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
1066 | } else { |
1067 | if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, |
1068 | egl_surface, egl_surface, egl_context)) { |
1069 | return SDL_EGL_SetError("Unable to make EGL context current" , "eglMakeCurrent" ); |
1070 | } |
1071 | } |
1072 | |
1073 | return 0; |
1074 | } |
1075 | |
1076 | int |
1077 | SDL_EGL_SetSwapInterval(_THIS, int interval) |
1078 | { |
1079 | EGLBoolean status; |
1080 | |
1081 | if (!_this->egl_data) { |
1082 | return SDL_SetError("EGL not initialized" ); |
1083 | } |
1084 | |
1085 | status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval); |
1086 | if (status == EGL_TRUE) { |
1087 | _this->egl_data->egl_swapinterval = interval; |
1088 | return 0; |
1089 | } |
1090 | |
1091 | return SDL_EGL_SetError("Unable to set the EGL swap interval" , "eglSwapInterval" ); |
1092 | } |
1093 | |
1094 | int |
1095 | SDL_EGL_GetSwapInterval(_THIS) |
1096 | { |
1097 | if (!_this->egl_data) { |
1098 | SDL_SetError("EGL not initialized" ); |
1099 | return 0; |
1100 | } |
1101 | |
1102 | return _this->egl_data->egl_swapinterval; |
1103 | } |
1104 | |
1105 | int |
1106 | SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface) |
1107 | { |
1108 | if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface)) { |
1109 | return SDL_EGL_SetError("unable to show color buffer in an OS-native window" , "eglSwapBuffers" ); |
1110 | } |
1111 | return 0; |
1112 | } |
1113 | |
1114 | void |
1115 | SDL_EGL_DeleteContext(_THIS, SDL_GLContext context) |
1116 | { |
1117 | EGLContext egl_context = (EGLContext) context; |
1118 | |
1119 | /* Clean up GLES and EGL */ |
1120 | if (!_this->egl_data) { |
1121 | return; |
1122 | } |
1123 | |
1124 | if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) { |
1125 | _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context); |
1126 | } |
1127 | |
1128 | } |
1129 | |
1130 | EGLSurface * |
1131 | SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) |
1132 | { |
1133 | /* max 2 values plus terminator. */ |
1134 | EGLint attribs[3]; |
1135 | int attr = 0; |
1136 | |
1137 | EGLSurface * surface; |
1138 | |
1139 | if (SDL_EGL_ChooseConfig(_this) != 0) { |
1140 | return EGL_NO_SURFACE; |
1141 | } |
1142 | |
1143 | #if SDL_VIDEO_DRIVER_ANDROID |
1144 | { |
1145 | /* Android docs recommend doing this! |
1146 | * Ref: http://developer.android.com/reference/android/app/NativeActivity.html |
1147 | */ |
1148 | EGLint format; |
1149 | _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, |
1150 | _this->egl_data->egl_config, |
1151 | EGL_NATIVE_VISUAL_ID, &format); |
1152 | |
1153 | ANativeWindow_setBuffersGeometry(nw, 0, 0, format); |
1154 | |
1155 | /* Update SurfaceView holder format. |
1156 | * May triggers a sequence surfaceDestroyed(), surfaceCreated(), surfaceChanged(). */ |
1157 | Android_JNI_SetSurfaceViewFormat(format); |
1158 | } |
1159 | #endif |
1160 | if (_this->gl_config.framebuffer_srgb_capable) { |
1161 | #ifdef EGL_KHR_gl_colorspace |
1162 | if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace" )) { |
1163 | attribs[attr++] = EGL_GL_COLORSPACE_KHR; |
1164 | attribs[attr++] = EGL_GL_COLORSPACE_SRGB_KHR; |
1165 | } else |
1166 | #endif |
1167 | { |
1168 | SDL_SetError("EGL implementation does not support sRGB system framebuffers" ); |
1169 | return EGL_NO_SURFACE; |
1170 | } |
1171 | } |
1172 | |
1173 | attribs[attr++] = EGL_NONE; |
1174 | |
1175 | surface = _this->egl_data->eglCreateWindowSurface( |
1176 | _this->egl_data->egl_display, |
1177 | _this->egl_data->egl_config, |
1178 | nw, &attribs[0]); |
1179 | if (surface == EGL_NO_SURFACE) { |
1180 | SDL_EGL_SetError("unable to create an EGL window surface" , "eglCreateWindowSurface" ); |
1181 | } |
1182 | return surface; |
1183 | } |
1184 | |
1185 | EGLSurface |
1186 | SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height) |
1187 | { |
1188 | EGLint attributes[] = { |
1189 | EGL_WIDTH, width, |
1190 | EGL_HEIGHT, height, |
1191 | EGL_NONE |
1192 | }; |
1193 | |
1194 | if (SDL_EGL_ChooseConfig(_this) != 0) { |
1195 | return EGL_NO_SURFACE; |
1196 | } |
1197 | |
1198 | return _this->egl_data->eglCreatePbufferSurface( |
1199 | _this->egl_data->egl_display, |
1200 | _this->egl_data->egl_config, |
1201 | attributes); |
1202 | } |
1203 | |
1204 | void |
1205 | SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) |
1206 | { |
1207 | if (!_this->egl_data) { |
1208 | return; |
1209 | } |
1210 | |
1211 | if (egl_surface != EGL_NO_SURFACE) { |
1212 | _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface); |
1213 | } |
1214 | } |
1215 | |
1216 | #endif /* SDL_VIDEO_OPENGL_EGL */ |
1217 | |
1218 | /* vi: set ts=4 sw=4 expandtab: */ |
1219 | |
1220 | |