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.
Alex Szpakowski 2015-05-11 21:03:36 -03:00
parent 5919a859b4
commit f1a7c00d06
1 changed files with 87 additions and 72 deletions

159
src/video/SDL_egl.c Normal file → Executable file
View File

@ -31,6 +31,13 @@
#include "SDL_loadso.h" #include "SDL_loadso.h"
#include "SDL_hints.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 #if SDL_VIDEO_DRIVER_RPI
/* Raspbian places the OpenGL ES/EGL binaries in a non standard path */ /* Raspbian places the OpenGL ES/EGL binaries in a non standard path */
#define DEFAULT_EGL "/opt/vc/lib/libEGL.so" #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); ext_len = SDL_strlen(ext);
exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS); exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
if(exts) { if (exts) {
ext_word = exts; ext_word = exts;
for(i = 0; exts[i] != 0; i++) { for (i = 0; exts[i] != 0; i++) {
if(exts[i] == ' ') { if (exts[i] == ' ') {
if(ext_len == len && !SDL_strncmp(ext_word, ext, len)) { if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) {
return 1; return 1;
} }
len = 0; len = 0;
ext_word = &exts[i + 1]; ext_word = &exts[i + 1];
} } else {
else {
len++; len++;
} }
} }
@ -190,12 +196,11 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
} }
if (egl_dll_handle == NULL) { 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) { if (_this->gl_config.major_version > 1) {
path = DEFAULT_OGL_ES2; path = DEFAULT_OGL_ES2;
egl_dll_handle = SDL_LoadObject(path); egl_dll_handle = SDL_LoadObject(path);
} } else {
else {
path = DEFAULT_OGL_ES; path = DEFAULT_OGL_ES;
egl_dll_handle = SDL_LoadObject(path); egl_dll_handle = SDL_LoadObject(path);
if (egl_dll_handle == NULL) { if (egl_dll_handle == NULL) {
@ -334,17 +339,22 @@ SDL_EGL_ChooseConfig(_THIS)
attribs[i++] = EGL_SAMPLES; attribs[i++] = EGL_SAMPLES;
attribs[i++] = _this->gl_config.multisamplesamples; attribs[i++] = _this->gl_config.multisamplesamples;
} }
attribs[i++] = EGL_RENDERABLE_TYPE; attribs[i++] = EGL_RENDERABLE_TYPE;
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 == 2) { #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; attribs[i++] = EGL_OPENGL_ES2_BIT;
} else { } else {
attribs[i++] = EGL_OPENGL_ES_BIT; attribs[i++] = EGL_OPENGL_ES_BIT;
} }
_this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
} } else {
else {
attribs[i++] = EGL_OPENGL_BIT; attribs[i++] = EGL_OPENGL_BIT;
_this->egl_data->eglBindAPI(EGL_OPENGL_API); _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. */ /* 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 */ /* 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; bitdiff = 0;
for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) { for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
if (attribs[j] == EGL_NONE) { if (attribs[j] == EGL_NONE) {
@ -386,8 +396,10 @@ SDL_EGL_ChooseConfig(_THIS)
best_bitdiff = bitdiff; best_bitdiff = bitdiff;
} }
if (bitdiff == 0) break; /* we found an exact match! */ if (bitdiff == 0) {
break; /* we found an exact match! */
}
} }
return 0; return 0;
@ -396,82 +408,86 @@ SDL_EGL_ChooseConfig(_THIS)
SDL_GLContext SDL_GLContext
SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
{ {
EGLint context_attrib_list[] = { /* max 14 values plus terminator. */
EGL_CONTEXT_CLIENT_VERSION, EGLint attribs[15];
1, int attr = 0;
EGL_NONE,
EGL_NONE,
EGL_NONE,
EGL_NONE,
EGL_NONE
};
EGLContext egl_context, share_context = EGL_NO_CONTEXT; EGLContext egl_context, share_context = EGL_NO_CONTEXT;
EGLint profile_mask = _this->gl_config.profile_mask;
if (!_this->egl_data) { if (!_this->egl_data) {
/* The EGL library wasn't loaded, SDL_GetError() should have info */ /* The EGL library wasn't loaded, SDL_GetError() should have info */
return NULL; return NULL;
} }
if (_this->gl_config.share_with_current_context) { if (_this->gl_config.share_with_current_context) {
share_context = (EGLContext)SDL_GL_GetCurrentContext(); share_context = (EGLContext)SDL_GL_GetCurrentContext();
} }
/* Bind the API */ /* Set the context version and other attributes. */
if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { if (_this->gl_config.major_version < 3 && _this->gl_config.flags == 0 &&
_this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); (profile_mask == 0 || profile_mask == SDL_GL_CONTEXT_PROFILE_ES)) {
if (_this->gl_config.major_version) { /* Create a context without using EGL_KHR_create_context attribs. */
context_attrib_list[1] = _this->gl_config.major_version; 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;
egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display, /* SDL profile bits match EGL profile bits. */
_this->egl_data->egl_config, if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
share_context, context_attrib_list); attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
} attribs[attr++] = profile_mask;
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;
} }
}
else { /* SDL flags match EGL flags. */
context_attrib_list[0] = EGL_NONE; if (_this->gl_config.flags != 0) {
} attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
#else /* EGL_KHR_create_context */ attribs[attr++] = _this->gl_config.flags;
context_attrib_list[0] = EGL_NONE; }
} else
#endif /* EGL_KHR_create_context */ #endif /* EGL_KHR_create_context */
egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display, {
_this->egl_data->egl_config, SDL_SetError("Could not create EGL context (context attributes are not supported)");
share_context, context_attrib_list); 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) { if (egl_context == EGL_NO_CONTEXT) {
SDL_SetError("Could not create EGL context"); SDL_SetError("Could not create EGL context");
return NULL; return NULL;
} }
_this->egl_data->egl_swapinterval = 0; _this->egl_data->egl_swapinterval = 0;
if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) { if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
SDL_EGL_DeleteContext(_this, egl_context); SDL_EGL_DeleteContext(_this, egl_context);
SDL_SetError("Could not make EGL context current"); SDL_SetError("Could not make EGL context current");
return NULL; return NULL;
} }
return (SDL_GLContext) egl_context; return (SDL_GLContext) egl_context;
} }
@ -489,8 +505,7 @@ SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
*/ */
if (!egl_context || !egl_surface) { if (!egl_context || !egl_surface) {
_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); _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, if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
egl_surface, egl_surface, egl_context)) { egl_surface, egl_surface, egl_context)) {
return SDL_SetError("Unable to make EGL context current"); return SDL_SetError("Unable to make EGL context current");