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.
authorAlex Szpakowski <slime73@gmail.com>
Mon, 11 May 2015 21:03:36 -0300
changeset 95956027a65e8528
parent 9594 0285b5e1c5ab
child 9596 ac646c8a73ae
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.
src/video/SDL_egl.c
     1.1 --- a/src/video/SDL_egl.c	Sat May 09 22:42:23 2015 +0200
     1.2 +++ b/src/video/SDL_egl.c	Mon May 11 21:03:36 2015 -0300
     1.3 @@ -31,6 +31,13 @@
     1.4  #include "SDL_loadso.h"
     1.5  #include "SDL_hints.h"
     1.6  
     1.7 +#ifdef EGL_KHR_create_context
     1.8 +/* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */
     1.9 +#ifndef EGL_OPENGL_ES3_BIT_KHR
    1.10 +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
    1.11 +#endif
    1.12 +#endif /* EGL_KHR_create_context */
    1.13 +
    1.14  #if SDL_VIDEO_DRIVER_RPI
    1.15  /* Raspbian places the OpenGL ES/EGL binaries in a non standard path */
    1.16  #define DEFAULT_EGL "/opt/vc/lib/libEGL.so"
    1.17 @@ -81,19 +88,18 @@
    1.18      ext_len = SDL_strlen(ext);
    1.19      exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
    1.20  
    1.21 -    if(exts) {
    1.22 +    if (exts) {
    1.23          ext_word = exts;
    1.24  
    1.25 -        for(i = 0; exts[i] != 0; i++) {
    1.26 -            if(exts[i] == ' ') {
    1.27 -                if(ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
    1.28 +        for (i = 0; exts[i] != 0; i++) {
    1.29 +            if (exts[i] == ' ') {
    1.30 +                if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
    1.31                      return 1;
    1.32                  }
    1.33  
    1.34                  len = 0;
    1.35                  ext_word = &exts[i + 1];
    1.36 -            }
    1.37 -            else {
    1.38 +            } else {
    1.39                  len++;
    1.40              }
    1.41          }
    1.42 @@ -190,12 +196,11 @@
    1.43      }
    1.44  
    1.45      if (egl_dll_handle == NULL) {
    1.46 -        if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    1.47 +        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    1.48              if (_this->gl_config.major_version > 1) {
    1.49                  path = DEFAULT_OGL_ES2;
    1.50                  egl_dll_handle = SDL_LoadObject(path);
    1.51 -            }
    1.52 -            else {
    1.53 +            } else {
    1.54                  path = DEFAULT_OGL_ES;
    1.55                  egl_dll_handle = SDL_LoadObject(path);
    1.56                  if (egl_dll_handle == NULL) {
    1.57 @@ -334,17 +339,22 @@
    1.58          attribs[i++] = EGL_SAMPLES;
    1.59          attribs[i++] = _this->gl_config.multisamplesamples;
    1.60      }
    1.61 -    
    1.62 +
    1.63      attribs[i++] = EGL_RENDERABLE_TYPE;
    1.64 -    if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    1.65 -        if (_this->gl_config.major_version == 2) {
    1.66 +    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    1.67 +#ifdef EGL_KHR_create_context
    1.68 +        if (_this->gl_config.major_version >= 3 &&
    1.69 +            SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
    1.70 +            attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
    1.71 +        } else
    1.72 +#endif
    1.73 +        if (_this->gl_config.major_version >= 2) {
    1.74              attribs[i++] = EGL_OPENGL_ES2_BIT;
    1.75          } else {
    1.76              attribs[i++] = EGL_OPENGL_ES_BIT;
    1.77          }
    1.78          _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
    1.79 -    }
    1.80 -    else {
    1.81 +    } else {
    1.82          attribs[i++] = EGL_OPENGL_BIT;
    1.83          _this->egl_data->eglBindAPI(EGL_OPENGL_API);
    1.84      }
    1.85 @@ -362,7 +372,7 @@
    1.86      /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
    1.87      /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
    1.88  
    1.89 -    for ( i=0; i<found_configs; i++ ) {
    1.90 +    for (i = 0; i < found_configs; i++ ) {
    1.91          bitdiff = 0;
    1.92          for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
    1.93              if (attribs[j] == EGL_NONE) {
    1.94 @@ -386,8 +396,10 @@
    1.95              
    1.96              best_bitdiff = bitdiff;
    1.97          }
    1.98 -           
    1.99 -        if (bitdiff == 0) break; /* we found an exact match! */
   1.100 +
   1.101 +        if (bitdiff == 0) {
   1.102 +            break; /* we found an exact match! */
   1.103 +        }
   1.104      }
   1.105      
   1.106      return 0;
   1.107 @@ -396,82 +408,86 @@
   1.108  SDL_GLContext
   1.109  SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
   1.110  {
   1.111 -    EGLint context_attrib_list[] = {
   1.112 -        EGL_CONTEXT_CLIENT_VERSION,
   1.113 -        1,
   1.114 -        EGL_NONE,
   1.115 -        EGL_NONE,
   1.116 -        EGL_NONE,
   1.117 -        EGL_NONE,
   1.118 -        EGL_NONE
   1.119 -    };
   1.120 -    
   1.121 +    /* max 14 values plus terminator. */
   1.122 +    EGLint attribs[15];
   1.123 +    int attr = 0;
   1.124 +
   1.125      EGLContext egl_context, share_context = EGL_NO_CONTEXT;
   1.126 -    
   1.127 +    EGLint profile_mask = _this->gl_config.profile_mask;
   1.128 +
   1.129      if (!_this->egl_data) {
   1.130          /* The EGL library wasn't loaded, SDL_GetError() should have info */
   1.131          return NULL;
   1.132      }
   1.133 -    
   1.134 +
   1.135      if (_this->gl_config.share_with_current_context) {
   1.136          share_context = (EGLContext)SDL_GL_GetCurrentContext();
   1.137      }
   1.138 -    
   1.139 +
   1.140 +    /* Set the context version and other attributes. */
   1.141 +    if (_this->gl_config.major_version < 3 && _this->gl_config.flags == 0 &&
   1.142 +        (profile_mask == 0 || profile_mask == SDL_GL_CONTEXT_PROFILE_ES)) {
   1.143 +        /* Create a context without using EGL_KHR_create_context attribs. */
   1.144 +        if (profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   1.145 +            attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
   1.146 +            attribs[attr++] = SDL_max(_this->gl_config.major_version, 1);
   1.147 +        }
   1.148 +    } else {
   1.149 +#ifdef EGL_KHR_create_context
   1.150 +        /* The Major/minor version, context profiles, and context flags can
   1.151 +         * only be specified when this extension is available.
   1.152 +         */
   1.153 +        if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
   1.154 +            attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
   1.155 +            attribs[attr++] = _this->gl_config.major_version;
   1.156 +            attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
   1.157 +            attribs[attr++] = _this->gl_config.minor_version;
   1.158 +
   1.159 +            /* SDL profile bits match EGL profile bits. */
   1.160 +            if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
   1.161 +                attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
   1.162 +                attribs[attr++] = profile_mask;
   1.163 +            }
   1.164 +
   1.165 +            /* SDL flags match EGL flags. */
   1.166 +            if (_this->gl_config.flags != 0) {
   1.167 +                attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
   1.168 +                attribs[attr++] = _this->gl_config.flags;
   1.169 +            }
   1.170 +        } else
   1.171 +#endif /* EGL_KHR_create_context */
   1.172 +        {
   1.173 +            SDL_SetError("Could not create EGL context (context attributes are not supported)");
   1.174 +            return NULL;
   1.175 +        }
   1.176 +    }
   1.177 +
   1.178 +    attribs[attr++] = EGL_NONE;
   1.179 +
   1.180      /* Bind the API */
   1.181 -    if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   1.182 +    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
   1.183          _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
   1.184 -        if (_this->gl_config.major_version) {
   1.185 -            context_attrib_list[1] = _this->gl_config.major_version;
   1.186 -        }
   1.187 +    } else {
   1.188 +        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
   1.189 +    }
   1.190  
   1.191 -        egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
   1.192 -                                          _this->egl_data->egl_config,
   1.193 -                                          share_context, context_attrib_list);
   1.194 -    }
   1.195 -    else {
   1.196 -        _this->egl_data->eglBindAPI(EGL_OPENGL_API);
   1.197 -#ifdef EGL_KHR_create_context        
   1.198 -        if(SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) {
   1.199 -            context_attrib_list[0] = EGL_CONTEXT_MAJOR_VERSION_KHR;
   1.200 -            context_attrib_list[1] = _this->gl_config.major_version;
   1.201 -            context_attrib_list[2] = EGL_CONTEXT_MINOR_VERSION_KHR;
   1.202 -            context_attrib_list[3] = _this->gl_config.minor_version;
   1.203 -            context_attrib_list[4] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
   1.204 -            switch(_this->gl_config.profile_mask) {
   1.205 -            case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY:
   1.206 -                context_attrib_list[5] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
   1.207 -                break;
   1.208 +    egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
   1.209 +                                      _this->egl_data->egl_config,
   1.210 +                                      share_context, attribs);
   1.211  
   1.212 -            case SDL_GL_CONTEXT_PROFILE_CORE:
   1.213 -            default:
   1.214 -                context_attrib_list[5] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
   1.215 -                break;
   1.216 -            }
   1.217 -        }
   1.218 -        else {
   1.219 -            context_attrib_list[0] = EGL_NONE;
   1.220 -        }
   1.221 -#else /* EGL_KHR_create_context */
   1.222 -        context_attrib_list[0] = EGL_NONE;
   1.223 -#endif /* EGL_KHR_create_context */
   1.224 -        egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
   1.225 -                                          _this->egl_data->egl_config,
   1.226 -                                          share_context, context_attrib_list);
   1.227 -    }
   1.228 -    
   1.229      if (egl_context == EGL_NO_CONTEXT) {
   1.230          SDL_SetError("Could not create EGL context");
   1.231          return NULL;
   1.232      }
   1.233 -    
   1.234 +
   1.235      _this->egl_data->egl_swapinterval = 0;
   1.236 -    
   1.237 +
   1.238      if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
   1.239          SDL_EGL_DeleteContext(_this, egl_context);
   1.240          SDL_SetError("Could not make EGL context current");
   1.241          return NULL;
   1.242      }
   1.243 -  
   1.244 +
   1.245      return (SDL_GLContext) egl_context;
   1.246  }
   1.247  
   1.248 @@ -489,8 +505,7 @@
   1.249       */
   1.250      if (!egl_context || !egl_surface) {
   1.251           _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   1.252 -    }
   1.253 -    else {
   1.254 +    } else {
   1.255          if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
   1.256              egl_surface, egl_surface, egl_context)) {
   1.257              return SDL_SetError("Unable to make EGL context current");