src/video/SDL_egl.c
author David Ludwig <dludwig@pobox.com>
Thu, 29 Dec 2016 11:49:18 -0500
changeset 10740 bb53965b659d
parent 10737 3406a0f8b041
child 10741 a32fd6b7412b
permissions -rw-r--r--
improved SDL_GetError() output generated by EGL code

This change attempts to report the EGL error codes generated by SDL's calls
into EGL, along with the name of the EGL function that failed.
     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     _this->gl_config.driver_loaded = 1;
   317 
   318     if (path) {
   319         SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
   320     } else {
   321         *_this->gl_config.driver_path = '\0';
   322     }
   323     
   324     return 0;
   325 }
   326 
   327 int
   328 SDL_EGL_ChooseConfig(_THIS) 
   329 {
   330     /* 64 seems nice. */
   331     EGLint attribs[64];
   332     EGLint found_configs = 0, value;
   333     /* 128 seems even nicer here */
   334     EGLConfig configs[128];
   335     int i, j, best_bitdiff = -1, bitdiff;
   336     
   337     if (!_this->egl_data) {
   338         /* The EGL library wasn't loaded, SDL_GetError() should have info */
   339         return -1;
   340     }
   341   
   342     /* Get a valid EGL configuration */
   343     i = 0;
   344     attribs[i++] = EGL_RED_SIZE;
   345     attribs[i++] = _this->gl_config.red_size;
   346     attribs[i++] = EGL_GREEN_SIZE;
   347     attribs[i++] = _this->gl_config.green_size;
   348     attribs[i++] = EGL_BLUE_SIZE;
   349     attribs[i++] = _this->gl_config.blue_size;
   350     
   351     if (_this->gl_config.alpha_size) {
   352         attribs[i++] = EGL_ALPHA_SIZE;
   353         attribs[i++] = _this->gl_config.alpha_size;
   354     }
   355     
   356     if (_this->gl_config.buffer_size) {
   357         attribs[i++] = EGL_BUFFER_SIZE;
   358         attribs[i++] = _this->gl_config.buffer_size;
   359     }
   360     
   361     attribs[i++] = EGL_DEPTH_SIZE;
   362     attribs[i++] = _this->gl_config.depth_size;
   363     
   364     if (_this->gl_config.stencil_size) {
   365         attribs[i++] = EGL_STENCIL_SIZE;
   366         attribs[i++] = _this->gl_config.stencil_size;
   367     }
   368     
   369     if (_this->gl_config.multisamplebuffers) {
   370         attribs[i++] = EGL_SAMPLE_BUFFERS;
   371         attribs[i++] = _this->gl_config.multisamplebuffers;
   372     }
   373     
   374     if (_this->gl_config.multisamplesamples) {
   375         attribs[i++] = EGL_SAMPLES;
   376         attribs[i++] = _this->gl_config.multisamplesamples;
   377     }
   378 
   379     if (_this->gl_config.framebuffer_srgb_capable) {
   380 #ifdef EGL_KHR_gl_colorspace
   381         if (SDL_EGL_HasExtension(_this, "EGL_KHR_gl_colorspace")) {
   382             attribs[i++] = EGL_GL_COLORSPACE_KHR;
   383             attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR;
   384         } else
   385 #endif
   386         {
   387             return SDL_SetError("EGL implementation does not support sRGB system framebuffers");
   388         }
   389     }
   390 
   391     attribs[i++] = EGL_RENDERABLE_TYPE;
   392     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   393 #ifdef EGL_KHR_create_context
   394         if (_this->gl_config.major_version >= 3 &&
   395             SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
   396             attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
   397         } else
   398 #endif
   399         if (_this->gl_config.major_version >= 2) {
   400             attribs[i++] = EGL_OPENGL_ES2_BIT;
   401         } else {
   402             attribs[i++] = EGL_OPENGL_ES_BIT;
   403         }
   404         _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
   405     } else {
   406         attribs[i++] = EGL_OPENGL_BIT;
   407         _this->egl_data->eglBindAPI(EGL_OPENGL_API);
   408     }
   409 
   410     attribs[i++] = EGL_NONE;
   411 
   412     if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
   413         attribs,
   414         configs, SDL_arraysize(configs),
   415         &found_configs) == EGL_FALSE ||
   416         found_configs == 0) {
   417         return SDL_EGL_SetError("Couldn't find matching EGL config", "eglChooseConfig");
   418     }
   419 
   420     /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
   421     /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
   422 
   423     for (i = 0; i < found_configs; i++ ) {
   424         bitdiff = 0;
   425         for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
   426             if (attribs[j] == EGL_NONE) {
   427                break;
   428             }
   429             
   430             if ( attribs[j+1] != EGL_DONT_CARE && (
   431                 attribs[j] == EGL_RED_SIZE ||
   432                 attribs[j] == EGL_GREEN_SIZE ||
   433                 attribs[j] == EGL_BLUE_SIZE ||
   434                 attribs[j] == EGL_ALPHA_SIZE ||
   435                 attribs[j] == EGL_DEPTH_SIZE ||
   436                 attribs[j] == EGL_STENCIL_SIZE)) {
   437                 _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value);
   438                 bitdiff += value - attribs[j + 1]; /* value is always >= attrib */
   439             }
   440         }
   441 
   442         if (bitdiff < best_bitdiff || best_bitdiff == -1) {
   443             _this->egl_data->egl_config = configs[i];
   444             
   445             best_bitdiff = bitdiff;
   446         }
   447 
   448         if (bitdiff == 0) {
   449             break; /* we found an exact match! */
   450         }
   451     }
   452     
   453     return 0;
   454 }
   455 
   456 SDL_GLContext
   457 SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
   458 {
   459     /* max 14 values plus terminator. */
   460     EGLint attribs[15];
   461     int attr = 0;
   462 
   463     EGLContext egl_context, share_context = EGL_NO_CONTEXT;
   464     EGLint profile_mask = _this->gl_config.profile_mask;
   465     EGLint major_version = _this->gl_config.major_version;
   466     EGLint minor_version = _this->gl_config.minor_version;
   467     SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
   468 
   469     if (!_this->egl_data) {
   470         /* The EGL library wasn't loaded, SDL_GetError() should have info */
   471         return NULL;
   472     }
   473 
   474     if (_this->gl_config.share_with_current_context) {
   475         share_context = (EGLContext)SDL_GL_GetCurrentContext();
   476     }
   477 
   478     /* Set the context version and other attributes. */
   479     if ((major_version < 3 || (minor_version == 0 && profile_es)) &&
   480         _this->gl_config.flags == 0 &&
   481         (profile_mask == 0 || profile_es)) {
   482         /* Create a context without using EGL_KHR_create_context attribs.
   483          * When creating a GLES context without EGL_KHR_create_context we can
   484          * only specify the major version. When creating a desktop GL context
   485          * we can't specify any version, so we only try in that case when the
   486          * version is less than 3.0 (matches SDL's GLX/WGL behavior.)
   487          */
   488         if (profile_es) {
   489             attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
   490             attribs[attr++] = SDL_max(major_version, 1);
   491         }
   492     } else {
   493 #ifdef EGL_KHR_create_context
   494         /* The Major/minor version, context profiles, and context flags can
   495          * only be specified when this extension is available.
   496          */
   497         if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
   498             attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
   499             attribs[attr++] = major_version;
   500             attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
   501             attribs[attr++] = minor_version;
   502 
   503             /* SDL profile bits match EGL profile bits. */
   504             if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
   505                 attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
   506                 attribs[attr++] = profile_mask;
   507             }
   508 
   509             /* SDL flags match EGL flags. */
   510             if (_this->gl_config.flags != 0) {
   511                 attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
   512                 attribs[attr++] = _this->gl_config.flags;
   513             }
   514         } else
   515 #endif /* EGL_KHR_create_context */
   516         {
   517             SDL_SetError("Could not create EGL context (context attributes are not supported)");
   518             return NULL;
   519         }
   520     }
   521 
   522     attribs[attr++] = EGL_NONE;
   523 
   524     /* Bind the API */
   525     if (profile_es) {
   526         _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
   527     } else {
   528         _this->egl_data->eglBindAPI(EGL_OPENGL_API);
   529     }
   530 
   531     egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
   532                                       _this->egl_data->egl_config,
   533                                       share_context, attribs);
   534 
   535     if (egl_context == EGL_NO_CONTEXT) {
   536         SDL_EGL_SetError("Could not create EGL context", "eglCreateContext");
   537         return NULL;
   538     }
   539 
   540     _this->egl_data->egl_swapinterval = 0;
   541 
   542     if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
   543         /* Save the SDL error set by SDL_EGL_MakeCurrent */
   544         char errorText[1024];
   545         SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText));
   546 
   547         /* Delete the context, which may alter the value returned by SDL_GetError() */
   548         SDL_EGL_DeleteContext(_this, egl_context);
   549 
   550         /* Restore the SDL error */
   551         SDL_SetError("%s", errorText);
   552 
   553         return NULL;
   554     }
   555 
   556     return (SDL_GLContext) egl_context;
   557 }
   558 
   559 int
   560 SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
   561 {
   562     EGLContext egl_context = (EGLContext) context;
   563 
   564     if (!_this->egl_data) {
   565         return SDL_SetError("OpenGL not initialized");
   566     }
   567     
   568     /* The android emulator crashes badly if you try to eglMakeCurrent 
   569      * with a valid context and invalid surface, so we have to check for both here.
   570      */
   571     if (!egl_context || !egl_surface) {
   572          _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   573     } else {
   574         if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
   575             egl_surface, egl_surface, egl_context)) {
   576             return SDL_EGL_SetError("Unable to make EGL context current", "eglMakeCurrent");
   577         }
   578     }
   579       
   580     return 0;
   581 }
   582 
   583 int
   584 SDL_EGL_SetSwapInterval(_THIS, int interval)
   585 {
   586     EGLBoolean status;
   587     
   588     if (!_this->egl_data) {
   589         return SDL_SetError("EGL not initialized");
   590     }
   591     
   592     status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
   593     if (status == EGL_TRUE) {
   594         _this->egl_data->egl_swapinterval = interval;
   595         return 0;
   596     }
   597     
   598     return SDL_EGL_SetError("Unable to set the EGL swap interval", "eglSwapInterval");
   599 }
   600 
   601 int
   602 SDL_EGL_GetSwapInterval(_THIS)
   603 {
   604     if (!_this->egl_data) {
   605         SDL_SetError("EGL not initialized");
   606         return 0;
   607     }
   608     
   609     return _this->egl_data->egl_swapinterval;
   610 }
   611 
   612 int
   613 SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
   614 {
   615     if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface)) {
   616         return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers");
   617     }
   618     return 0;
   619 }
   620 
   621 void
   622 SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
   623 {
   624     EGLContext egl_context = (EGLContext) context;
   625 
   626     /* Clean up GLES and EGL */
   627     if (!_this->egl_data) {
   628         return;
   629     }
   630     
   631     if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) {
   632         SDL_EGL_MakeCurrent(_this, NULL, NULL);
   633         _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
   634     }
   635         
   636 }
   637 
   638 EGLSurface *
   639 SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) 
   640 {
   641     EGLSurface * surface;
   642 
   643     if (SDL_EGL_ChooseConfig(_this) != 0) {
   644         return EGL_NO_SURFACE;
   645     }
   646     
   647 #if __ANDROID__
   648     {
   649         /* Android docs recommend doing this!
   650          * Ref: http://developer.android.com/reference/android/app/NativeActivity.html 
   651          */
   652         EGLint format;
   653         _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
   654                                             _this->egl_data->egl_config, 
   655                                             EGL_NATIVE_VISUAL_ID, &format);
   656 
   657         ANativeWindow_setBuffersGeometry(nw, 0, 0, format);
   658     }
   659 #endif    
   660     
   661     surface = _this->egl_data->eglCreateWindowSurface(
   662             _this->egl_data->egl_display,
   663             _this->egl_data->egl_config,
   664             nw, NULL);
   665     if (surface == EGL_NO_SURFACE) {
   666         SDL_EGL_SetError("unable to create an EGL window surface", "eglCreateWindowSurface");
   667     }
   668     return surface;
   669 }
   670 
   671 void
   672 SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface) 
   673 {
   674     if (!_this->egl_data) {
   675         return;
   676     }
   677     
   678     if (egl_surface != EGL_NO_SURFACE) {
   679         _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
   680     }
   681 }
   682 
   683 #endif /* SDL_VIDEO_OPENGL_EGL */
   684 
   685 /* vi: set ts=4 sw=4 expandtab: */
   686