src/video/SDL_egl.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 29 Aug 2017 16:30:49 -0400
changeset 11418 7749a3b2b343
parent 11363 2d3d35b2c95a
child 11462 dc5698982bac
permissions -rw-r--r--
egl: Cast to size_t, in case platform's NativeDisplayType isn't a pointer.

(fixes compiler warnings on QNX.)
     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 *)(size_t)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 *)(size_t)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