src/video/SDL_egl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 27 Aug 2017 19:05:57 -0700
changeset 11363 2d3d35b2c95a
parent 11347 7f254d0b7842
child 11418 7749a3b2b343
permissions -rw-r--r--
Fixed bug 3724 - Allow Angle Static Link

Carlos

We would like to add a switch (define) that allows us to compile Angle statically with SDL. That is, getting rid of the OpenGL DLL. Usually you need OpenGL to be loaded dynamically as DLL because implementation is provided by the system but no need with Angle.

Only 2 files need modification and it shouldn't affect current behaivor:
include/SDL_egl.h and src/video/SDL_egl.c, as in here

https://github.com/native-toolkit/sdl/pull/10/files

The flag name could be SDL_VIDEO_STATIC_ANGLE (instead of NATIVE_TOOLKIT_STATIC_ANGLE) as discussed here https://github.com/native-toolkit/sdl/pull/10

We have tested this with both Windows and UWP, using NME engine (https://github.com/haxenme/nme).

Releated issue: https://bugzilla.libsdl.org/show_bug.cgi?id=1820
     1 /*
     2  *  Simple DirectMedia Layer
     3  *  Copyright (C) 1997-2017 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 #endif
    31 
    32 #include "SDL_sysvideo.h"
    33 #include "SDL_log.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 "/opt/vc/lib/libEGL.so"
    48 #define DEFAULT_OGL_ES2 "/opt/vc/lib/libGLESv2.so"
    49 #define DEFAULT_OGL_ES_PVR "/opt/vc/lib/libGLES_CM.so"
    50 #define DEFAULT_OGL_ES "/opt/vc/lib/libGLESv1_CM.so"
    51 
    52 #elif SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_VIVANTE
    53 /* Android */
    54 #define DEFAULT_EGL "libEGL.so"
    55 #define DEFAULT_OGL_ES2 "libGLESv2.so"
    56 #define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
    57 #define DEFAULT_OGL_ES "libGLESv1_CM.so"
    58 
    59 #elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
    60 /* EGL AND OpenGL ES support via ANGLE */
    61 #define DEFAULT_EGL "libEGL.dll"
    62 #define DEFAULT_OGL_ES2 "libGLESv2.dll"
    63 #define DEFAULT_OGL_ES_PVR "libGLES_CM.dll"
    64 #define DEFAULT_OGL_ES "libGLESv1_CM.dll"
    65 
    66 #else
    67 /* Desktop Linux */
    68 #define DEFAULT_OGL "libGL.so.1"
    69 #define DEFAULT_EGL "libEGL.so.1"
    70 #define DEFAULT_OGL_ES2 "libGLESv2.so.2"
    71 #define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
    72 #define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
    73 #endif /* SDL_VIDEO_DRIVER_RPI */
    74 
    75 #ifdef SDL_VIDEO_STATIC_ANGLE
    76 #define LOAD_FUNC(NAME) \
    77 _this->egl_data->NAME = (void *)NAME;
    78 #else
    79 #define LOAD_FUNC(NAME) \
    80 _this->egl_data->NAME = SDL_LoadFunction(_this->egl_data->dll_handle, #NAME); \
    81 if (!_this->egl_data->NAME) \
    82 { \
    83     return SDL_SetError("Could not retrieve EGL function " #NAME); \
    84 }
    85 #endif
    86 
    87 static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
    88 {
    89 #define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e;
    90     switch (eglErrorCode) {
    91         SDL_EGL_ERROR_TRANSLATE(EGL_SUCCESS);
    92         SDL_EGL_ERROR_TRANSLATE(EGL_NOT_INITIALIZED);
    93         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ACCESS);
    94         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ALLOC);
    95         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ATTRIBUTE);
    96         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONTEXT);
    97         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONFIG);
    98         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CURRENT_SURFACE);
    99         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_DISPLAY);
   100         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_SURFACE);
   101         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_MATCH);
   102         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_PARAMETER);
   103         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_PIXMAP);
   104         SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_WINDOW);
   105         SDL_EGL_ERROR_TRANSLATE(EGL_CONTEXT_LOST);
   106     }
   107     return "";
   108 }
   109 
   110 int SDL_EGL_SetErrorEx(const char * message, const char * eglFunctionName, EGLint eglErrorCode)
   111 {
   112     const char * errorText = SDL_EGL_GetErrorName(eglErrorCode);
   113     char altErrorText[32];
   114     if (errorText[0] == '\0') {
   115         /* An unknown-to-SDL error code was reported.  Report its hexadecimal value, instead of its name. */
   116         SDL_snprintf(altErrorText, SDL_arraysize(altErrorText), "0x%x", (unsigned int)eglErrorCode);
   117         errorText = altErrorText;
   118     }
   119     return SDL_SetError("%s (call to %s failed, reporting an error of %s)", message, eglFunctionName, errorText);
   120 }
   121 
   122 /* EGL implementation of SDL OpenGL ES support */
   123 typedef enum {
   124     SDL_EGL_DISPLAY_EXTENSION,
   125     SDL_EGL_CLIENT_EXTENSION
   126 } SDL_EGL_ExtensionType;
   127 
   128 static SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext)
   129 {
   130     size_t ext_len;
   131     const char *ext_override;
   132     const char *egl_extstr;
   133     const char *ext_start;
   134 
   135     /* Invalid extensions can be rejected early */
   136     if (ext == NULL || *ext == 0 || SDL_strchr(ext, ' ') != NULL) {
   137         /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension"); */
   138         return SDL_FALSE;
   139     }
   140 
   141     /* Extensions can be masked with an environment variable.
   142      * Unlike the OpenGL override, this will use the set bits of an integer
   143      * to disable the extension.
   144      *  Bit   Action
   145      *  0     If set, the display extension is masked and not present to SDL.
   146      *  1     If set, the client extension is masked and not present to SDL.
   147      */
   148     ext_override = SDL_getenv(ext);
   149     if (ext_override != NULL) {
   150         int disable_ext = SDL_atoi(ext_override);
   151         if (disable_ext & 0x01 && type == SDL_EGL_DISPLAY_EXTENSION) {
   152             return SDL_FALSE;
   153         } else if (disable_ext & 0x02 && type == SDL_EGL_CLIENT_EXTENSION) {
   154             return SDL_FALSE;
   155         }
   156     }
   157 
   158     ext_len = SDL_strlen(ext);
   159     switch (type) {
   160     case SDL_EGL_DISPLAY_EXTENSION:
   161         egl_extstr = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
   162         break;
   163     case SDL_EGL_CLIENT_EXTENSION:
   164         /* EGL_EXT_client_extensions modifies eglQueryString to return client extensions
   165          * if EGL_NO_DISPLAY is passed. Implementations without it are required to return NULL.
   166          * This behavior is included in EGL 1.5.
   167          */
   168         egl_extstr = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
   169         break;
   170     default:
   171         /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type"); */
   172         return SDL_FALSE;
   173     }
   174 
   175     if (egl_extstr != NULL) {
   176         ext_start = egl_extstr;
   177 
   178         while (*ext_start) {
   179             ext_start = SDL_strstr(ext_start, ext);
   180             if (ext_start == NULL) {
   181                 return SDL_FALSE;
   182             }
   183             /* Check if the match is not just a substring of one of the extensions */
   184             if (ext_start == egl_extstr || *(ext_start - 1) == ' ') {
   185                 if (ext_start[ext_len] == ' ' || ext_start[ext_len] == 0) {
   186                     return SDL_TRUE;
   187                 }
   188             }
   189             /* If the search stopped in the middle of an extension, skip to the end of it */
   190             ext_start += ext_len;
   191             while (*ext_start != ' ' && *ext_start != 0) {
   192                 ext_start++;
   193             }
   194         }
   195     }
   196 
   197     return SDL_FALSE;
   198 }
   199 
   200 void *
   201 SDL_EGL_GetProcAddress(_THIS, const char *proc)
   202 {
   203     static char procname[1024];
   204     void *retval;
   205     
   206     /* eglGetProcAddress is busted on Android http://code.google.com/p/android/issues/detail?id=7681 */
   207 #if !defined(SDL_VIDEO_DRIVER_ANDROID) && !defined(SDL_VIDEO_DRIVER_MIR) 
   208     if (_this->egl_data->eglGetProcAddress) {
   209         retval = _this->egl_data->eglGetProcAddress(proc);
   210         if (retval) {
   211             return retval;
   212         }
   213     }
   214 #endif
   215     
   216     retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
   217     if (!retval && SDL_strlen(proc) <= 1022) {
   218         procname[0] = '_';
   219         SDL_strlcpy(procname + 1, proc, 1022);
   220         retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
   221     }
   222     return retval;
   223 }
   224 
   225 void
   226 SDL_EGL_UnloadLibrary(_THIS)
   227 {
   228     if (_this->egl_data) {
   229         if (_this->egl_data->egl_display) {
   230             _this->egl_data->eglTerminate(_this->egl_data->egl_display);
   231             _this->egl_data->egl_display = NULL;
   232         }
   233 
   234         if (_this->egl_data->dll_handle) {
   235             SDL_UnloadObject(_this->egl_data->dll_handle);
   236             _this->egl_data->dll_handle = NULL;
   237         }
   238         if (_this->egl_data->egl_dll_handle) {
   239             SDL_UnloadObject(_this->egl_data->egl_dll_handle);
   240             _this->egl_data->egl_dll_handle = NULL;
   241         }
   242         
   243         SDL_free(_this->egl_data);
   244         _this->egl_data = NULL;
   245     }
   246 }
   247 
   248 int
   249 SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
   250 {
   251     void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
   252     const char *path = NULL;
   253     int egl_version_major = 0, egl_version_minor = 0;
   254 #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
   255     const char *d3dcompiler;
   256 #endif
   257 
   258     if (_this->egl_data) {
   259         return SDL_SetError("OpenGL ES context already created");
   260     }
   261 
   262     _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
   263     if (!_this->egl_data) {
   264         return SDL_OutOfMemory();
   265     }
   266 
   267 #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
   268     d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
   269     if (!d3dcompiler) {
   270         if (WIN_IsWindowsVistaOrGreater()) {
   271             d3dcompiler = "d3dcompiler_46.dll";
   272         } else {
   273             d3dcompiler = "d3dcompiler_43.dll";
   274         }
   275     }
   276     if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
   277         if (SDL_LoadObject(d3dcompiler) == NULL) {
   278             SDL_ClearError();
   279         }
   280     }
   281 #endif
   282 
   283 #ifndef SDL_VIDEO_STATIC_ANGLE
   284     /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
   285     path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
   286     if (path != NULL) {
   287         egl_dll_handle = SDL_LoadObject(path);
   288     }
   289 
   290     if (egl_dll_handle == NULL) {
   291         if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   292             if (_this->gl_config.major_version > 1) {
   293                 path = DEFAULT_OGL_ES2;
   294                 egl_dll_handle = SDL_LoadObject(path);
   295             } else {
   296                 path = DEFAULT_OGL_ES;
   297                 egl_dll_handle = SDL_LoadObject(path);
   298                 if (egl_dll_handle == NULL) {
   299                     path = DEFAULT_OGL_ES_PVR;
   300                     egl_dll_handle = SDL_LoadObject(path);
   301                 }
   302             }
   303         }
   304 #ifdef DEFAULT_OGL         
   305         else {
   306             path = DEFAULT_OGL;
   307             egl_dll_handle = SDL_LoadObject(path);
   308         }
   309 #endif        
   310     }
   311     _this->egl_data->egl_dll_handle = egl_dll_handle;
   312 
   313     if (egl_dll_handle == NULL) {
   314         return SDL_SetError("Could not initialize OpenGL / GLES library");
   315     }
   316 
   317     /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
   318     if (egl_path != NULL) {
   319         dll_handle = SDL_LoadObject(egl_path);
   320     }   
   321     /* Try loading a EGL symbol, if it does not work try the default library paths */
   322     if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
   323         if (dll_handle != NULL) {
   324             SDL_UnloadObject(dll_handle);
   325         }
   326         path = SDL_getenv("SDL_VIDEO_EGL_DRIVER");
   327         if (path == NULL) {
   328             path = DEFAULT_EGL;
   329         }
   330         dll_handle = SDL_LoadObject(path);
   331         if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
   332             if (dll_handle != NULL) {
   333                 SDL_UnloadObject(dll_handle);
   334             }
   335             return SDL_SetError("Could not load EGL library");
   336         }
   337         SDL_ClearError();
   338     }
   339 #endif
   340 
   341     _this->egl_data->dll_handle = dll_handle;
   342 
   343     /* Load new function pointers */
   344     LOAD_FUNC(eglGetDisplay);
   345     LOAD_FUNC(eglInitialize);
   346     LOAD_FUNC(eglTerminate);
   347     LOAD_FUNC(eglGetProcAddress);
   348     LOAD_FUNC(eglChooseConfig);
   349     LOAD_FUNC(eglGetConfigAttrib);
   350     LOAD_FUNC(eglCreateContext);
   351     LOAD_FUNC(eglDestroyContext);
   352     LOAD_FUNC(eglCreateWindowSurface);
   353     LOAD_FUNC(eglDestroySurface);
   354     LOAD_FUNC(eglMakeCurrent);
   355     LOAD_FUNC(eglSwapBuffers);
   356     LOAD_FUNC(eglSwapInterval);
   357     LOAD_FUNC(eglWaitNative);
   358     LOAD_FUNC(eglWaitGL);
   359     LOAD_FUNC(eglBindAPI);
   360     LOAD_FUNC(eglQueryString);
   361     LOAD_FUNC(eglGetError);
   362 
   363     if (_this->egl_data->eglQueryString) {
   364         /* EGL 1.5 allows querying for client version */
   365         const char *egl_version = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);
   366         if (egl_version != NULL) {
   367             if (SDL_sscanf(egl_version, "%d.%d", &egl_version_major, &egl_version_minor) != 2) {
   368                 egl_version_major = 0;
   369                 egl_version_minor = 0;
   370                 SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s", egl_version);
   371             }
   372         }
   373     }
   374 
   375     if (egl_version_major == 1 && egl_version_minor == 5) {
   376         LOAD_FUNC(eglGetPlatformDisplay);
   377     }
   378 
   379     _this->egl_data->egl_display = EGL_NO_DISPLAY;
   380 #if !defined(__WINRT__)
   381     if (platform) {
   382         if (egl_version_major == 1 && egl_version_minor == 5) {
   383             _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)native_display, NULL);
   384         } else {
   385             if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
   386                 _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT");
   387                 if (_this->egl_data->eglGetPlatformDisplayEXT) {
   388                     _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, (void *)native_display, NULL);
   389                 }
   390             }
   391         }
   392     }
   393     /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
   394     if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
   395         _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
   396     }
   397     if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
   398         return SDL_SetError("Could not get EGL display");
   399     }
   400     
   401     if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
   402         return SDL_SetError("Could not initialize EGL");
   403     }
   404 #endif
   405 
   406     if (path) {
   407         SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
   408     } else {
   409         *_this->gl_config.driver_path = '\0';
   410     }
   411     
   412     return 0;
   413 }
   414 
   415 int
   416 SDL_EGL_ChooseConfig(_THIS) 
   417 {
   418 /* 64 seems nice. */
   419     EGLint attribs[64];
   420     EGLint found_configs = 0, value;
   421 #ifdef SDL_VIDEO_DRIVER_KMSDRM
   422     /* Intel EGL on KMS/DRM (al least) returns invalid configs that confuse the bitdiff search used */
   423     /* later in this function, so we simply use the first one when using the KMSDRM driver for now. */
   424     EGLConfig configs[1];
   425 #else
   426     /* 128 seems even nicer here */
   427     EGLConfig configs[128];
   428 #endif
   429     int i, j, best_bitdiff = -1, bitdiff;
   430    
   431     if (!_this->egl_data) {
   432         /* The EGL library wasn't loaded, SDL_GetError() should have info */
   433         return -1;
   434     }
   435   
   436     /* Get a valid EGL configuration */
   437     i = 0;
   438     attribs[i++] = EGL_RED_SIZE;
   439     attribs[i++] = _this->gl_config.red_size;
   440     attribs[i++] = EGL_GREEN_SIZE;
   441     attribs[i++] = _this->gl_config.green_size;
   442     attribs[i++] = EGL_BLUE_SIZE;
   443     attribs[i++] = _this->gl_config.blue_size;
   444     
   445     if (_this->gl_config.alpha_size) {
   446         attribs[i++] = EGL_ALPHA_SIZE;
   447         attribs[i++] = _this->gl_config.alpha_size;
   448     }
   449     
   450     if (_this->gl_config.buffer_size) {
   451         attribs[i++] = EGL_BUFFER_SIZE;
   452         attribs[i++] = _this->gl_config.buffer_size;
   453     }
   454     
   455     attribs[i++] = EGL_DEPTH_SIZE;
   456     attribs[i++] = _this->gl_config.depth_size;
   457     
   458     if (_this->gl_config.stencil_size) {
   459         attribs[i++] = EGL_STENCIL_SIZE;
   460         attribs[i++] = _this->gl_config.stencil_size;
   461     }
   462     
   463     if (_this->gl_config.multisamplebuffers) {
   464         attribs[i++] = EGL_SAMPLE_BUFFERS;
   465         attribs[i++] = _this->gl_config.multisamplebuffers;
   466     }
   467     
   468     if (_this->gl_config.multisamplesamples) {
   469         attribs[i++] = EGL_SAMPLES;
   470         attribs[i++] = _this->gl_config.multisamplesamples;
   471     }
   472 
   473     if (_this->gl_config.framebuffer_srgb_capable) {
   474 #ifdef EGL_KHR_gl_colorspace
   475         if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
   476             attribs[i++] = EGL_GL_COLORSPACE_KHR;
   477             attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR;
   478         } else
   479 #endif
   480         {
   481             return SDL_SetError("EGL implementation does not support sRGB system framebuffers");
   482         }
   483     }
   484 
   485     attribs[i++] = EGL_RENDERABLE_TYPE;
   486     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   487 #ifdef EGL_KHR_create_context
   488         if (_this->gl_config.major_version >= 3 &&
   489             SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
   490             attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
   491         } else
   492 #endif
   493         if (_this->gl_config.major_version >= 2) {
   494             attribs[i++] = EGL_OPENGL_ES2_BIT;
   495         } else {
   496             attribs[i++] = EGL_OPENGL_ES_BIT;
   497         }
   498         _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
   499     } else {
   500         attribs[i++] = EGL_OPENGL_BIT;
   501         _this->egl_data->eglBindAPI(EGL_OPENGL_API);
   502     }
   503 
   504     attribs[i++] = EGL_NONE;
   505 
   506     if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
   507         attribs,
   508         configs, SDL_arraysize(configs),
   509         &found_configs) == EGL_FALSE ||
   510         found_configs == 0) {
   511         return SDL_EGL_SetError("Couldn't find matching EGL config", "eglChooseConfig");
   512     }
   513 
   514     /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
   515     /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
   516 
   517     for (i = 0; i < found_configs; i++ ) {
   518         bitdiff = 0;
   519         for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
   520             if (attribs[j] == EGL_NONE) {
   521                break;
   522             }
   523             
   524             if ( attribs[j+1] != EGL_DONT_CARE && (
   525                 attribs[j] == EGL_RED_SIZE ||
   526                 attribs[j] == EGL_GREEN_SIZE ||
   527                 attribs[j] == EGL_BLUE_SIZE ||
   528                 attribs[j] == EGL_ALPHA_SIZE ||
   529                 attribs[j] == EGL_DEPTH_SIZE ||
   530                 attribs[j] == EGL_STENCIL_SIZE)) {
   531                 _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value);
   532                 bitdiff += value - attribs[j + 1]; /* value is always >= attrib */
   533             }
   534         }
   535 
   536         if (bitdiff < best_bitdiff || best_bitdiff == -1) {
   537             _this->egl_data->egl_config = configs[i];
   538             
   539             best_bitdiff = bitdiff;
   540         }
   541 
   542         if (bitdiff == 0) {
   543             break; /* we found an exact match! */
   544         }
   545     }
   546     
   547     return 0;
   548 }
   549 
   550 SDL_GLContext
   551 SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
   552 {
   553     /* max 14 values plus terminator. */
   554     EGLint attribs[15];
   555     int attr = 0;
   556 
   557     EGLContext egl_context, share_context = EGL_NO_CONTEXT;
   558     EGLint profile_mask = _this->gl_config.profile_mask;
   559     EGLint major_version = _this->gl_config.major_version;
   560     EGLint minor_version = _this->gl_config.minor_version;
   561     SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
   562 
   563     if (!_this->egl_data) {
   564         /* The EGL library wasn't loaded, SDL_GetError() should have info */
   565         return NULL;
   566     }
   567 
   568     if (_this->gl_config.share_with_current_context) {
   569         share_context = (EGLContext)SDL_GL_GetCurrentContext();
   570     }
   571 
   572     /* Set the context version and other attributes. */
   573     if ((major_version < 3 || (minor_version == 0 && profile_es)) &&
   574         _this->gl_config.flags == 0 &&
   575         (profile_mask == 0 || profile_es)) {
   576         /* Create a context without using EGL_KHR_create_context attribs.
   577          * When creating a GLES context without EGL_KHR_create_context we can
   578          * only specify the major version. When creating a desktop GL context
   579          * we can't specify any version, so we only try in that case when the
   580          * version is less than 3.0 (matches SDL's GLX/WGL behavior.)
   581          */
   582         if (profile_es) {
   583             attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
   584             attribs[attr++] = SDL_max(major_version, 1);
   585         }
   586     } else {
   587 #ifdef EGL_KHR_create_context
   588         /* The Major/minor version, context profiles, and context flags can
   589          * only be specified when this extension is available.
   590          */
   591         if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
   592             attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
   593             attribs[attr++] = major_version;
   594             attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
   595             attribs[attr++] = minor_version;
   596 
   597             /* SDL profile bits match EGL profile bits. */
   598             if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
   599                 attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
   600                 attribs[attr++] = profile_mask;
   601             }
   602 
   603             /* SDL flags match EGL flags. */
   604             if (_this->gl_config.flags != 0) {
   605                 attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
   606                 attribs[attr++] = _this->gl_config.flags;
   607             }
   608         } else
   609 #endif /* EGL_KHR_create_context */
   610         {
   611             SDL_SetError("Could not create EGL context (context attributes are not supported)");
   612             return NULL;
   613         }
   614     }
   615 
   616     if (_this->gl_config.no_error) {
   617 #ifdef EGL_KHR_create_context_no_error
   618         if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context_no_error")) {
   619             attribs[attr++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
   620             attribs[attr++] = _this->gl_config.no_error;
   621         } else
   622 #endif
   623         {
   624             SDL_SetError("EGL implementation does not support no_error contexts");
   625             return NULL;
   626         }
   627     }
   628 
   629     attribs[attr++] = EGL_NONE;
   630 
   631     /* Bind the API */
   632     if (profile_es) {
   633         _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
   634     } else {
   635         _this->egl_data->eglBindAPI(EGL_OPENGL_API);
   636     }
   637 
   638     egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
   639                                       _this->egl_data->egl_config,
   640                                       share_context, attribs);
   641 
   642     if (egl_context == EGL_NO_CONTEXT) {
   643         SDL_EGL_SetError("Could not create EGL context", "eglCreateContext");
   644         return NULL;
   645     }
   646 
   647     _this->egl_data->egl_swapinterval = 0;
   648 
   649     if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
   650         /* Save the SDL error set by SDL_EGL_MakeCurrent */
   651         char errorText[1024];
   652         SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText));
   653 
   654         /* Delete the context, which may alter the value returned by SDL_GetError() */
   655         SDL_EGL_DeleteContext(_this, egl_context);
   656 
   657         /* Restore the SDL error */
   658         SDL_SetError("%s", errorText);
   659 
   660         return NULL;
   661     }
   662 
   663     return (SDL_GLContext) egl_context;
   664 }
   665 
   666 int
   667 SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
   668 {
   669     EGLContext egl_context = (EGLContext) context;
   670 
   671     if (!_this->egl_data) {
   672         return SDL_SetError("OpenGL not initialized");
   673     }
   674     
   675     /* The android emulator crashes badly if you try to eglMakeCurrent 
   676      * with a valid context and invalid surface, so we have to check for both here.
   677      */
   678     if (!egl_context || !egl_surface) {
   679          _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   680     } else {
   681         if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
   682             egl_surface, egl_surface, egl_context)) {
   683             return SDL_EGL_SetError("Unable to make EGL context current", "eglMakeCurrent");
   684         }
   685     }
   686       
   687     return 0;
   688 }
   689 
   690 int
   691 SDL_EGL_SetSwapInterval(_THIS, int interval)
   692 {
   693     EGLBoolean status;
   694     
   695     if (!_this->egl_data) {
   696         return SDL_SetError("EGL not initialized");
   697     }
   698     
   699     status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
   700     if (status == EGL_TRUE) {
   701         _this->egl_data->egl_swapinterval = interval;
   702         return 0;
   703     }
   704     
   705     return SDL_EGL_SetError("Unable to set the EGL swap interval", "eglSwapInterval");
   706 }
   707 
   708 int
   709 SDL_EGL_GetSwapInterval(_THIS)
   710 {
   711     if (!_this->egl_data) {
   712         SDL_SetError("EGL not initialized");
   713         return 0;
   714     }
   715     
   716     return _this->egl_data->egl_swapinterval;
   717 }
   718 
   719 int
   720 SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
   721 {
   722     if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface)) {
   723         return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers");
   724     }
   725     return 0;
   726 }
   727 
   728 void
   729 SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
   730 {
   731     EGLContext egl_context = (EGLContext) context;
   732 
   733     /* Clean up GLES and EGL */
   734     if (!_this->egl_data) {
   735         return;
   736     }
   737     
   738     if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) {
   739         SDL_EGL_MakeCurrent(_this, NULL, NULL);
   740         _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
   741     }
   742         
   743 }
   744 
   745 EGLSurface *
   746 SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
   747 {
   748     EGLSurface * surface;
   749 
   750     if (SDL_EGL_ChooseConfig(_this) != 0) {
   751         return EGL_NO_SURFACE;
   752     }
   753     
   754 #if SDL_VIDEO_DRIVER_ANDROID
   755     {
   756         /* Android docs recommend doing this!
   757          * Ref: http://developer.android.com/reference/android/app/NativeActivity.html 
   758          */
   759         EGLint format;
   760         _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
   761                                             _this->egl_data->egl_config, 
   762                                             EGL_NATIVE_VISUAL_ID, &format);
   763 
   764         ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
   765     }
   766 #endif    
   767     
   768     surface = _this->egl_data->eglCreateWindowSurface(
   769             _this->egl_data->egl_display,
   770             _this->egl_data->egl_config,
   771             nw, NULL);
   772     if (surface == EGL_NO_SURFACE) {
   773         SDL_EGL_SetError("unable to create an EGL window surface", "eglCreateWindowSurface");
   774     }
   775     return surface;
   776 }
   777 
   778 void
   779 SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
   780 {
   781     if (!_this->egl_data) {
   782         return;
   783     }
   784     
   785     if (egl_surface != EGL_NO_SURFACE) {
   786         _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
   787     }
   788 }
   789 
   790 #endif /* SDL_VIDEO_OPENGL_EGL */
   791 
   792 /* vi: set ts=4 sw=4 expandtab: */
   793