src/video/SDL_egl.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 01 Jan 2017 19:10:36 -0800
changeset 10741 a32fd6b7412b
parent 10740 bb53965b659d
child 10878 7fa08228d9e3
permissions -rw-r--r--
Fixed bug 3529 - SDL_EGL_UnloadLibrary is not called at all on SDL_Quit

kaisyu

In case of OpenGLES, the sequences of loading and unloading driver library should be like that:

SDL_Init
...
SDL_GL_LoadLibrary
SDL_EGL_LoadLibrary
...
SDL_Quit
...
SDL_GL_UnloadLibrary
SDL_EGL_UnloadLibrary
...


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