src/video/SDL_egl.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 05 Aug 2017 22:10:55 +0200
changeset 11192 3c8377f1a323
parent 11175 cbc6a8a5b701
child 11219 f94279990934
permissions -rw-r--r--
emscripten: Fixed compiler warnings about integer to pointer conversions.

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