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