src/video/SDL_egl.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 31 Oct 2018 15:16:51 -0700
changeset 12376 cfc65d4d49ae
parent 12269 754cd2042e21
child 12493 82f9397db3e7
permissions -rw-r--r--
Fixed bug 4349 - SDL_CreateWindow fails with KMS/DRM after upgrading Mesa to 18.2.3

Rainer Sabelka

After I did an upgrade of my arch Linux installation (resulting in an update of Mesa to version 18.2.3), all my SDL2 applications which use the KMS/DRM driver stopped working.
Reason: Creating a Window with SDL_CreateWindow failed because the call to EGL
eglCreateWindowSurface() returns an error "EGL_BAD_MATCH".
After investigating with the debugger I figured, that the configuration, which has been selected from the output of eglChooseConfig(), has an "EGL_NATIVE_VISUAL_ID" which does not match the "format" of the underlying gbm surface.

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