Commit f1a7c00d062c7775784fc61a0ed5a15fc75c4ca9

Alex Szpakowski 2015-05-11T21:03:36

Refactored SDL_EGL_CreateContext: It now supports context flags and OpenGL ES 3+ contexts, and its behavior more closely matches the GLX and WGL context creation code. Improved the code style consistency of SDL_egl.c. Fixes bugzilla #2865.

diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
old mode 100644
new mode 100755
index a93b7b7..7426684
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -31,6 +31,13 @@
 #include "SDL_loadso.h"
 #include "SDL_hints.h"
 
+#ifdef EGL_KHR_create_context
+/* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */
+#ifndef EGL_OPENGL_ES3_BIT_KHR
+#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
+#endif
+#endif /* EGL_KHR_create_context */
+
 #if SDL_VIDEO_DRIVER_RPI
 /* Raspbian places the OpenGL ES/EGL binaries in a non standard path */
 #define DEFAULT_EGL "/opt/vc/lib/libEGL.so"
@@ -81,19 +88,18 @@ static int SDL_EGL_HasExtension(_THIS, const char *ext)
     ext_len = SDL_strlen(ext);
     exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
 
-    if(exts) {
+    if (exts) {
         ext_word = exts;
 
-        for(i = 0; exts[i] != 0; i++) {
-            if(exts[i] == ' ') {
-                if(ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
+        for (i = 0; exts[i] != 0; i++) {
+            if (exts[i] == ' ') {
+                if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
                     return 1;
                 }
 
                 len = 0;
                 ext_word = &exts[i + 1];
-            }
-            else {
+            } else {
                 len++;
             }
         }
@@ -190,12 +196,11 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
     }
 
     if (egl_dll_handle == NULL) {
-        if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
             if (_this->gl_config.major_version > 1) {
                 path = DEFAULT_OGL_ES2;
                 egl_dll_handle = SDL_LoadObject(path);
-            }
-            else {
+            } else {
                 path = DEFAULT_OGL_ES;
                 egl_dll_handle = SDL_LoadObject(path);
                 if (egl_dll_handle == NULL) {
@@ -334,17 +339,22 @@ SDL_EGL_ChooseConfig(_THIS)
         attribs[i++] = EGL_SAMPLES;
         attribs[i++] = _this->gl_config.multisamplesamples;
     }
-    
+
     attribs[i++] = EGL_RENDERABLE_TYPE;
-    if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
-        if (_this->gl_config.major_version == 2) {
+    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+#ifdef EGL_KHR_create_context
+        if (_this->gl_config.major_version >= 3 &&
+            SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
+            attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
+        } else
+#endif
+        if (_this->gl_config.major_version >= 2) {
             attribs[i++] = EGL_OPENGL_ES2_BIT;
         } else {
             attribs[i++] = EGL_OPENGL_ES_BIT;
         }
         _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
-    }
-    else {
+    } else {
         attribs[i++] = EGL_OPENGL_BIT;
         _this->egl_data->eglBindAPI(EGL_OPENGL_API);
     }
@@ -362,7 +372,7 @@ SDL_EGL_ChooseConfig(_THIS)
     /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
     /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
 
-    for ( i=0; i<found_configs; i++ ) {
+    for (i = 0; i < found_configs; i++ ) {
         bitdiff = 0;
         for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
             if (attribs[j] == EGL_NONE) {
@@ -386,8 +396,10 @@ SDL_EGL_ChooseConfig(_THIS)
             
             best_bitdiff = bitdiff;
         }
-           
-        if (bitdiff == 0) break; /* we found an exact match! */
+
+        if (bitdiff == 0) {
+            break; /* we found an exact match! */
+        }
     }
     
     return 0;
@@ -396,82 +408,86 @@ SDL_EGL_ChooseConfig(_THIS)
 SDL_GLContext
 SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
 {
-    EGLint context_attrib_list[] = {
-        EGL_CONTEXT_CLIENT_VERSION,
-        1,
-        EGL_NONE,
-        EGL_NONE,
-        EGL_NONE,
-        EGL_NONE,
-        EGL_NONE
-    };
-    
+    /* max 14 values plus terminator. */
+    EGLint attribs[15];
+    int attr = 0;
+
     EGLContext egl_context, share_context = EGL_NO_CONTEXT;
-    
+    EGLint profile_mask = _this->gl_config.profile_mask;
+
     if (!_this->egl_data) {
         /* The EGL library wasn't loaded, SDL_GetError() should have info */
         return NULL;
     }
-    
+
     if (_this->gl_config.share_with_current_context) {
         share_context = (EGLContext)SDL_GL_GetCurrentContext();
     }
-    
-    /* Bind the API */
-    if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
-        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
-        if (_this->gl_config.major_version) {
-            context_attrib_list[1] = _this->gl_config.major_version;
+
+    /* Set the context version and other attributes. */
+    if (_this->gl_config.major_version < 3 && _this->gl_config.flags == 0 &&
+        (profile_mask == 0 || profile_mask == SDL_GL_CONTEXT_PROFILE_ES)) {
+        /* Create a context without using EGL_KHR_create_context attribs. */
+        if (profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+            attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
+            attribs[attr++] = SDL_max(_this->gl_config.major_version, 1);
         }
+    } else {
+#ifdef EGL_KHR_create_context
+        /* The Major/minor version, context profiles, and context flags can
+         * only be specified when this extension is available.
+         */
+        if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
+            attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
+            attribs[attr++] = _this->gl_config.major_version;
+            attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
+            attribs[attr++] = _this->gl_config.minor_version;
+
+            /* SDL profile bits match EGL profile bits. */
+            if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
+                attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+                attribs[attr++] = profile_mask;
+            }
 
-        egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
-                                          _this->egl_data->egl_config,
-                                          share_context, context_attrib_list);
-    }
-    else {
-        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
-#ifdef EGL_KHR_create_context        
-        if(SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
-            context_attrib_list[0] = EGL_CONTEXT_MAJOR_VERSION_KHR;
-            context_attrib_list[1] = _this->gl_config.major_version;
-            context_attrib_list[2] = EGL_CONTEXT_MINOR_VERSION_KHR;
-            context_attrib_list[3] = _this->gl_config.minor_version;
-            context_attrib_list[4] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
-            switch(_this->gl_config.profile_mask) {
-            case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY:
-                context_attrib_list[5] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
-                break;
-
-            case SDL_GL_CONTEXT_PROFILE_CORE:
-            default:
-                context_attrib_list[5] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
-                break;
+            /* SDL flags match EGL flags. */
+            if (_this->gl_config.flags != 0) {
+                attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
+                attribs[attr++] = _this->gl_config.flags;
             }
-        }
-        else {
-            context_attrib_list[0] = EGL_NONE;
-        }
-#else /* EGL_KHR_create_context */
-        context_attrib_list[0] = EGL_NONE;
+        } else
 #endif /* EGL_KHR_create_context */
-        egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
-                                          _this->egl_data->egl_config,
-                                          share_context, context_attrib_list);
+        {
+            SDL_SetError("Could not create EGL context (context attributes are not supported)");
+            return NULL;
+        }
     }
-    
+
+    attribs[attr++] = EGL_NONE;
+
+    /* Bind the API */
+    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
+        _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
+    } else {
+        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
+    }
+
+    egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
+                                      _this->egl_data->egl_config,
+                                      share_context, attribs);
+
     if (egl_context == EGL_NO_CONTEXT) {
         SDL_SetError("Could not create EGL context");
         return NULL;
     }
-    
+
     _this->egl_data->egl_swapinterval = 0;
-    
+
     if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
         SDL_EGL_DeleteContext(_this, egl_context);
         SDL_SetError("Could not make EGL context current");
         return NULL;
     }
-  
+
     return (SDL_GLContext) egl_context;
 }
 
@@ -489,8 +505,7 @@ SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
      */
     if (!egl_context || !egl_surface) {
          _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    }
-    else {
+    } else {
         if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
             egl_surface, egl_surface, egl_context)) {
             return SDL_SetError("Unable to make EGL context current");