jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=265c851a8f2ac3cd1f93d523736d4cce0454fe2c

commit 265c851a8f2ac3cd1f93d523736d4cce0454fe2c
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Wed Mar 8 11:52:59 2017 +0900

    evas gl: Fix version detection for GLES 3.1
    
    It was assumed that GLES 3 would only work with EGL but in fact
    OpenGL 4.3 & 4.5 are supersets of GLES 3.0 & 3.1 respectively. So
    GLX should also support GLES 3.0 or GLES 3.1 for evas gl, if the
    driver supports it, of course.
    
    Of course while doing this patch things didn't go like they were
    supposed to go. I'm currently using NVIDIA's proprietary driver,
    that conveniently provides EGL with GLES 3.2. But wait, there's
    a catch: GL_VERSION is "OpenGL ES 3.2 NVIDIA" except that none
    of the functions of GLES 3.1 or GLES 3.2 are actually supported.
    Those functions are only present in the GLX/OpenGL variant of the
    driver. Thanks so much for making my life easier...
    
    So yeah, this patch contains a hack for those invalid versions
    of GLES 3.x. What was supposed to be a small fix became a huge
    mess.
    
    Also add a comment about the possibly invalid auto-upgrade from
    GLES 2 to GLES 3.
    
    This adds a test case in elm_test, but only to verify that
    elm_glview_version_add(3) actually works. We need a proper GLES 3
    test case, eventually (and 3.1, 3.2 of course).
---
 src/bin/elementary/test.c                          |  2 +
 src/bin/elementary/test_glview.c                   | 21 ++++++-
 src/modules/evas/engines/gl_common/evas_gl_api.c   | 71 +++++++++++-----------
 .../evas/engines/gl_common/evas_gl_common.h        |  2 +-
 .../evas/engines/gl_common/evas_gl_context.c       | 53 +++++++++++-----
 src/modules/evas/engines/gl_common/evas_gl_core.c  | 36 +++++++++--
 .../evas/engines/gl_common/evas_gl_core_private.h  |  3 +-
 src/modules/evas/engines/gl_x11/evas_engine.c      |  9 +++
 8 files changed, 138 insertions(+), 59 deletions(-)

diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index e3d9dc6..a850816 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 2b68a73..beb291a 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 3ccb5b9..1437814 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 59549ef..d78c21a 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 ec8fd82..45ea677 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 (minor_version) *minor_version = 1;
+        return 3;
+     }
 
-             if (_has_ext("GL_ARB_ES3_compatibility", &exts, &num))
-               return 3;
-          }
-        return 2; /* emulated support */
+   // 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 b50adfc..2c91183 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 71deebe..e6afff6 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 94bfded..13929aa 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;
 

-- 


Reply via email to