diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index e3d9dc6413..a850816d18 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -253,6 +253,7 @@ void test_grid_static(void *data, Evas_Object *obj, void *event_info); void test_glview_simple(void *data, Evas_Object *obj, void *event_info); void test_glview(void *data, Evas_Object *obj, void *event_info); void test_glview_manygears(void *data, Evas_Object *obj, void *event_info); +void test_glview_gles3(void *data, Evas_Object *obj, void *event_info); void test_3d(void *data, Evas_Object *obj, void *event_info); void test_naviframe(void *data, Evas_Object *obj, void *event_info); void test_naviframe2(void *data, Evas_Object *obj, void *event_info); @@ -859,6 +860,7 @@ add_tests: ADD_TEST(NULL, "3D", "GLViewSimple", test_glview_simple); ADD_TEST(NULL, "3D", "GLView Gears", test_glview); ADD_TEST(NULL, "3D", "GLView Many Gears", test_glview_manygears); + ADD_TEST(NULL, "3D", "GLView GL ES 3.x", test_glview_gles3); //------------------------------// ADD_TEST(NULL, "Web", "Web", test_web); diff --git a/src/bin/elementary/test_glview.c b/src/bin/elementary/test_glview.c index 2b68a73ca7..beb291a693 100644 --- a/src/bin/elementary/test_glview.c +++ b/src/bin/elementary/test_glview.c @@ -427,6 +427,9 @@ _init_gl(Evas_Object *obj) { GLData *gld = evas_object_data_get(obj, "gld"); + printf("GL_VERSION: %s\n", gld->glapi->glGetString(GL_VERSION)); + fflush(stdout); + gears_init(gld); } @@ -611,8 +614,8 @@ _mouse_up(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *e gld->mouse_down = 0; } -void -test_glview(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +static void +_test_glview_do(Evas_GL_Context_Version version) { Evas_Object *win, *bx, *bt, *gl, *lb; Ecore_Animator *ani; @@ -649,7 +652,7 @@ test_glview(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_in evas_object_show(bx); // Add a GLView - gl = elm_glview_add(win); + gl = elm_glview_version_add(win, version); if (gl) { evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); @@ -723,3 +726,15 @@ test_glview(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_in evas_object_resize(win, 320, 480); evas_object_show(win); } + +void +test_glview(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + _test_glview_do(EVAS_GL_GLES_2_X); +} + +void +test_glview_gles3(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + _test_glview_do(EVAS_GL_GLES_3_X); +} diff --git a/src/modules/evas/engines/gl_common/evas_gl_api.c b/src/modules/evas/engines/gl_common/evas_gl_api.c index 3ccb5b95b6..14378143e0 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_api.c +++ b/src/modules/evas/engines/gl_common/evas_gl_api.c @@ -1324,12 +1324,13 @@ _evgl_glGetString(GLenum name) { static char _version[128] = {0}; static char _glsl[128] = {0}; + const char *ret, *version_extra; EVGL_Resource *rsc; - const char *ret; + EVGL_Context *ctx; /* We wrap two values here: * - * VERSION: Since OpenGL ES 3 is not supported yet, we return OpenGL ES 2.0 + * VERSION: Since OpenGL ES 3 is not supported yet*, we return OpenGL ES 2.0 * The string is not modified on desktop GL (eg. 4.4.0 NVIDIA 343.22) * GLES 3 support is not exposed because apps can't use GLES 3 core * functions yet. @@ -1337,6 +1338,8 @@ _evgl_glGetString(GLenum name) * EXTENSIONS: This should return only the list of GL extensions supported * by Evas GL. This means as many extensions as possible should be * added to the whitelist. + * + * *: GLES 3.0/3.1 is not fully supported... we also have buggy drivers! */ /* @@ -1353,11 +1356,12 @@ _evgl_glGetString(GLenum name) if ((!(rsc = _evgl_tls_resource_get())) || !rsc->current_ctx) { ERR("Current context is NULL, not calling glGetString"); - // This sets evas_gl_error_get instead of glGetError... + // This sets evas_gl_error_get instead of eglGetError... evas_gl_common_error_set(NULL, EVAS_GL_BAD_CONTEXT); return NULL; } + ctx = rsc->current_ctx; switch (name) { case GL_VENDOR: @@ -1369,6 +1373,7 @@ _evgl_glGetString(GLenum name) ret = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); if (!ret) return NULL; #ifdef GL_GLES + // FIXME: We probably shouldn't wrap anything for EGL if (ret[18] != '1') { // We try not to remove the vendor fluff @@ -1388,20 +1393,14 @@ _evgl_glGetString(GLenum name) ret = (const char *) glGetString(GL_VERSION); if (!ret) return NULL; #ifdef GL_GLES - if ((ret[10] != '2') && (ret[10] != '3')) - { - // We try not to remove the vendor fluff - snprintf(_version, sizeof(_version), "OpenGL ES 2.0 Evas GL (%s)", ret + 10); - _version[sizeof(_version) - 1] = '\0'; - return (const GLubyte *) _version; - } - return (const GLubyte *) ret; + version_extra = ret + 10; #else - // Desktop GL, we still keep the official name - snprintf(_version, sizeof(_version), "OpenGL ES 2.0 Evas GL (%s)", (char *) ret); + version_extra = ret; +#endif + snprintf(_version, sizeof(_version), "OpenGL ES %d.%d Evas GL (%s)", + (int) ctx->version, ctx->version_minor, version_extra); _version[sizeof(_version) - 1] = '\0'; return (const GLubyte *) _version; -#endif case GL_EXTENSIONS: // Passing the version - GLESv2/GLESv3. @@ -3242,17 +3241,19 @@ _debug_gles3_api_get(Evas_GL_API *funcs, int minor_version) static Eina_Bool -_evgl_load_gles3_apis(void *dl_handle, Evas_GL_API *funcs, int minor_version) +_evgl_load_gles3_apis(void *dl_handle, Evas_GL_API *funcs, int minor_version, + void *(*get_proc_address)(const char *)) { if (!dl_handle) return EINA_FALSE; + Eina_Bool ret_value = EINA_FALSE; -#define ORD(name) \ +#define ORD(name) do { \ funcs->name = dlsym(dl_handle, #name); \ - if (!funcs->name) \ - { \ + if (!funcs->name && get_proc_address) get_proc_address(#name); \ + if (!funcs->name) { \ WRN("%s symbol not found", #name); \ - return EINA_FALSE; \ - } + return ret_value; \ + } } while (0) // Used to update extensions ORD(glGetString); @@ -3366,6 +3367,7 @@ _evgl_load_gles3_apis(void *dl_handle, Evas_GL_API *funcs, int minor_version) if (minor_version > 0) { //GLES 3.1 + ret_value = EINA_TRUE; ORD(glDispatchCompute); ORD(glDispatchComputeIndirect); ORD(glDrawArraysIndirect); @@ -3435,15 +3437,15 @@ _evgl_load_gles3_apis(void *dl_handle, Evas_GL_API *funcs, int minor_version) ORD(glVertexAttribBinding); ORD(glVertexBindingDivisor); } - #undef ORD + return EINA_TRUE; } static Eina_Bool -_evgl_gles3_api_init(int minor_version) +_evgl_gles3_api_init(int minor_version, void *(*get_proc_address)(const char *)) { static Eina_Bool _initialized = EINA_FALSE; if (_initialized) return EINA_TRUE; @@ -3475,7 +3477,7 @@ _evgl_gles3_api_init(int minor_version) return EINA_FALSE; } - if (!_evgl_load_gles3_apis(_gles3_handle, &_gles3_api, minor_version)) + if (!_evgl_load_gles3_apis(_gles3_handle, &_gles3_api, minor_version, get_proc_address)) { return EINA_FALSE; } @@ -3484,26 +3486,23 @@ _evgl_gles3_api_init(int minor_version) return EINA_TRUE; } - void -_evgl_api_gles3_get(Evas_GL_API *funcs, Eina_Bool debug) +_evgl_api_gles3_get(Evas_GL_API *funcs, void *(*get_proc_address)(const char *), + Eina_Bool debug, int minor_version) { - const char *ret = (const char *) glGetString(GL_VERSION); - int minor_version = ret[12] - '0'; + int effective_minor = minor_version; - if (minor_version > 9 || minor_version < 0) - { - ERR("OpenGL ES version is invalid."); - return; - } - - if (!_evgl_gles3_api_init(minor_version)) + if (!_evgl_gles3_api_init(minor_version, get_proc_address)) return; + // Hack for NVIDIA. See also evas_gl_core.c:_context_ext_check() + if (!_gles3_api.glVertexBindingDivisor) + effective_minor = 0; + if (debug) - _debug_gles3_api_get(funcs, minor_version); + _debug_gles3_api_get(funcs, effective_minor); else - _normal_gles3_api_get(funcs, minor_version); + _normal_gles3_api_get(funcs, effective_minor); if (evgl_engine->direct_scissor_off) _direct_scissor_off_api_get(funcs); diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index 59549efe84..d78c21a5b1 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -543,7 +543,7 @@ typedef void (*Evas_Gl_Symbols)(void *(*GetProcAddress)(const char *sym)); EAPI void __evas_gl_err(int err, const char *file, const char *func, int line, const char *op); -int evas_gl_common_version_check(void); +int evas_gl_common_version_check(int *minor_version); void evas_gl_common_tiling_start(Evas_Engine_GL_Context *gc, int rot, int gw, int gh, int cx, int cy, int cw, int ch, diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index ec8fd826b6..45ea67776b 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -493,7 +493,7 @@ matrix_ortho(GLfloat *m, } int -evas_gl_common_version_check(void) +evas_gl_common_version_check(int *minor_version) { char *version; char *tmp; @@ -506,6 +506,8 @@ evas_gl_common_version_check(void) * GL_VERSION is used to get the version of the connection */ + if (minor_version) *minor_version = 0; + version = (char *)glGetString(GL_VERSION); if (!version) { @@ -541,6 +543,12 @@ evas_gl_common_version_check(void) if (strstr(version, "OpenGL ES 3")) { /* Supported */ + if (minor_version) + { + if ((version[11] == '.') && isdigit(version[12])) + *minor_version = atoi(&version[12]); + else *minor_version = 0; + } return 3; } @@ -549,6 +557,13 @@ evas_gl_common_version_check(void) if (strstr(version, "OpenGL ES ")) { /* Supported */ + if (minor_version) + { + if ((version[10] == '2') && + (version[11] == '.') && isdigit(version[12])) + *minor_version = atoi(&version[12]); + else *minor_version = 0; + } return 2; } @@ -590,22 +605,32 @@ evas_gl_common_version_check(void) fail: free(version); - if (((major == 1) && (minor >= 4)) || (major >= 2)) + // OpenGL 4.5 is supposed to be a superset of GLES 3.1 + if ((major == 4) && (minor >= 5)) { - /* Map GL to GLES version: Refer http://en.wikipedia.org/wiki/OpenGL_ES */ - if ((major >= 4) && (minor >= 3)) - return 3; - else if ((major > 3) || ((major == 3) && (minor >= 3))) /* >= 3.3 */ - { - const char *exts = NULL; - int num = 0; - - if (_has_ext("GL_ARB_ES3_compatibility", &exts, &num)) - return 3; - } - return 2; /* emulated support */ + if (minor_version) *minor_version = 1; + return 3; } + // OpenGL 4.3 is supposed to be a superset of GLES 3.0 + if ((major == 4) && (minor >= 3)) + return 3; + + // Extension GL_ARB_ES3_compatibility means OpenGL is a superset of GLES 3.0 + if ((major > 3) || ((major == 3) && (minor >= 3))) + { + const char *exts = NULL; + int num = 0; + + if (_has_ext("GL_ARB_ES3_compatibility", &exts, &num)) + return 3; + } + + // OpenGL >= 1.4 is a superset of the features of GLES 2 (albeit not an + // exact function match) + if (((major == 1) && (minor >= 4)) || (major >= 2)) + return 2; /* emulated support */ + return 0; } @@ -787,7 +812,7 @@ evas_gl_common_context_new(void) if (!glsym_glGetStringi) glsym_glGetStringi = dlsym(RTLD_DEFAULT, "glGetStringi"); - gles_version = evas_gl_common_version_check(); + gles_version = evas_gl_common_version_check(NULL); if (!gles_version) return NULL; gc = calloc(1, sizeof(Evas_Engine_GL_Context)); diff --git a/src/modules/evas/engines/gl_common/evas_gl_core.c b/src/modules/evas/engines/gl_common/evas_gl_core.c index b50adfcfac..2c91183baf 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_core.c +++ b/src/modules/evas/engines/gl_common/evas_gl_core.c @@ -494,7 +494,7 @@ _fbo_surface_cap_test(GLint color_ifmt, GLenum color_fmt, int depth_stencil = 0; int fb_status = 0; int w = 2, h = 2; // Test it with a simple (2,2) surface. Should I test it with NPOT? - Evas_GL_Context_Version ver = evas_gl_common_version_check(); + Evas_GL_Context_Version ver = evas_gl_common_version_check(NULL); // Gen FBO glGenFramebuffers(1, &fbo); @@ -912,7 +912,7 @@ _surface_cap_init(void *eng_data) evgl_engine->caps.max_h = max_size; DBG("Max Surface Width: %d Height: %d", evgl_engine->caps.max_w, evgl_engine->caps.max_h); - gles_version = evas_gl_common_version_check(); + gles_version = evas_gl_common_version_check(NULL); // Check for MSAA support if (gles_version == 3) @@ -1019,6 +1019,20 @@ _context_ext_check(EVGL_Context *ctx) } #endif + if (ctx->version == EVAS_GL_GLES_3_X) + { + /* HACK, as of 2017/03/08: + * Some NVIDIA drivers pretend to support GLES 3.1 with EGL but in + * fact none of the new functions are available, neither through + * dlsym() nor eglGetProcAddress(). GLX/OpenGL should work though. + * This is a fixup for glGetString(GL_VERSION). + */ + if (!gles3_funcs->glVertexBindingDivisor) + ctx->version_minor = 0; + else + ctx->version_minor = 1; + } + ctx->extension_checked = 1; return 1; @@ -2315,6 +2329,7 @@ evgl_context_create(void *eng_data, EVGL_Context *share_ctx, // Set default values ctx->version = version; + ctx->version_minor = 0; ctx->scissor_coord[0] = 0; ctx->scissor_coord[1] = 0; ctx->scissor_coord[2] = evgl_engine->caps.max_w; @@ -3116,6 +3131,7 @@ Evas_GL_API * evgl_api_get(void *eng_data, Evas_GL_Context_Version version, Eina_Bool alloc_only) { Evas_GL_API *api = NULL; + int minor_version = 0; if (version == EVAS_GL_GLES_2_X) { @@ -3129,10 +3145,15 @@ evgl_api_get(void *eng_data, Evas_GL_Context_Version version, Eina_Bool alloc_on } else if (version == EVAS_GL_GLES_3_X) { + if (evas_gl_common_version_check(&minor_version) < 3) + { + ERR("OpenGL ES 3.x is not supported."); + return NULL; + } if (!gles3_funcs) gles3_funcs = calloc(1, EVAS_GL_API_STRUCT_SIZE); api = gles3_funcs; } - else return NULL; + if (!api) return NULL; if (alloc_only && (api->version == EVAS_GL_API_VERSION)) return api; @@ -3154,7 +3175,14 @@ evgl_api_get(void *eng_data, Evas_GL_Context_Version version, Eina_Bool alloc_on } else if (version == EVAS_GL_GLES_3_X) { - _evgl_api_gles3_get(api, evgl_engine->api_debug_mode); + void *(*get_proc_address)(const char *) = NULL; + const char *egl_exts; + + egl_exts = evgl_engine->funcs->ext_string_get(eng_data); + if (egl_exts && strstr(egl_exts, "EGL_KHR_get_all_proc_addresses")) + get_proc_address = evgl_engine->funcs->proc_address_get; + + _evgl_api_gles3_get(api, get_proc_address, evgl_engine->api_debug_mode, minor_version); evgl_api_gles3_ext_get(api, evgl_engine->funcs->proc_address_get, evgl_engine->funcs->ext_string_get(eng_data)); } diff --git a/src/modules/evas/engines/gl_common/evas_gl_core_private.h b/src/modules/evas/engines/gl_common/evas_gl_core_private.h index 71deebe4c4..e6afff639c 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_core_private.h +++ b/src/modules/evas/engines/gl_common/evas_gl_core_private.h @@ -163,6 +163,7 @@ struct _EVGL_Context EVGLNative_Context context; Evas_GL_Context_Version version; + int version_minor; // Context FBO GLuint surface_fbo; @@ -352,7 +353,7 @@ extern EVGL_Engine *evgl_engine; // Internally used functions extern void _evgl_api_gles2_get(Evas_GL_API *api, Eina_Bool debug); extern void _evgl_api_gles1_get(Evas_GL_API *api, Eina_Bool debug); -extern void _evgl_api_gles3_get(Evas_GL_API *api, Eina_Bool debug); +extern void _evgl_api_gles3_get(Evas_GL_API *funcs, void *(*get_proc_address)(const char *), Eina_Bool debug, int minor_version); extern EVGL_Resource *_evgl_tls_resource_get(void); extern EVGL_Resource *_evgl_tls_resource_create(void *data); extern void _evgl_tls_resource_destroy(void *data); diff --git a/src/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c index 94bfdedbb9..13929aaf19 100644 --- a/src/modules/evas/engines/gl_x11/evas_engine.c +++ b/src/modules/evas/engines/gl_x11/evas_engine.c @@ -494,6 +494,15 @@ evgl_eng_context_create(void *data, void *share_ctx, Evas_GL_Context_Version ver EGLContext context = EGL_NO_CONTEXT; int context_attrs[3]; + /* Upgrade GLES 2 to GLES 3. + * + * FIXME: Maybe we don't want to do this, unless we have no choice. + * An alternative would be to use eglCreateImage() to share the indirect + * rendering FBO between two contexts of incompatible version. For now, + * we always upgrade the real context version to GLES 3 when it's available. + * But this leads to some issues, namely that the list of extensions is + * different, and MSAA surfaces also work differently. + */ if (eng_get_ob(re)->gles3 && (version >= EVAS_GL_GLES_2_X)) version = 3;