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); \
110if (!_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
121static 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
144int 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
158SDL_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
230void *
231SDL_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
267void
268SDL_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
290int
291SDL_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
468static void
469SDL_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
484int
485SDL_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
550int
551SDL_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
630void
631SDL_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
640typedef struct {
641 EGLint attribute;
642 char const* name;
643} Attribute;
644
645Attribute 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
682static 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
694int
695SDL_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
888SDL_GLContext
889SDL_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
1052int
1053SDL_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
1076int
1077SDL_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
1094int
1095SDL_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
1105int
1106SDL_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
1114void
1115SDL_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
1130EGLSurface *
1131SDL_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
1185EGLSurface
1186SDL_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
1204void
1205SDL_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