Evas GL: Skip glClear() with direct rendering & transparent color
authorJean-Philippe Andre <jp.andre@samsung.com>
Mon, 1 Sep 2014 11:22:12 +0000 (20:22 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Mon, 20 Oct 2014 03:16:07 +0000 (12:16 +0900)
When using direct rendering, glClear() should not do anything
if the ClearColor was (0,0,0,0). The application would indeed
expect a transparent output (so, see the widgets below the view),
but glClear would erase the pixels instead. So add a quick check
to skip glClear entirely in that specific case.

src/modules/evas/engines/gl_common/evas_gl_api.c
src/modules/evas/engines/gl_common/evas_gl_core.c
src/modules/evas/engines/gl_common/evas_gl_core_private.h

index 41331001bb0a25da845ca99eabf7ea5099390891..2f1ff1484a7f9406bf23734a46b1314e23f72b45 100644 (file)
@@ -307,6 +307,27 @@ compute_gl_coordinates(int win_w, int win_h, int rot, int clip_image,
    //DBG( "\e[1;32m     Img[%d %d %d %d] Original [%d %d %d %d]  Transformed[%d %d %d %d]  Clip[%d %d %d %d] Clipped[%d %d %d %d] \e[m", img_x, img_y, img_w, img_h, imgc[0], imgc[1], imgc[2], imgc[3], objc[0], objc[1], objc[2], objc[3], clip[0], clip[1], clip[2], clip[3], cc[0], cc[1], cc[2], cc[3]);
 }
 
+static void
+_evgl_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+   EVGL_Resource *rsc;
+
+   if (!(rsc=_evgl_tls_resource_get()))
+     {
+        ERR("Unable to execute GL command. Error retrieving tls");
+        return;
+     }
+
+   if (_evgl_direct_enabled())
+     {
+        rsc->clear_color.a = alpha;
+        rsc->clear_color.r = red;
+        rsc->clear_color.g = green;
+        rsc->clear_color.b = blue;
+     }
+   glClearColor(red, green, blue, alpha);
+}
+
 static void
 _evgl_glClear(GLbitfield mask)
 {
@@ -338,6 +359,29 @@ _evgl_glClear(GLbitfield mask)
      {
         if (!(rsc->current_ctx->current_fbo))
           {
+             /* Skip glClear() if clearing with transparent color
+              * Note: There will be side effects if the object itself is not
+              * marked as having an alpha channel!
+              */
+             if (ctx->current_sfc->alpha && (mask & GL_COLOR_BUFFER_BIT))
+               {
+                  if ((rsc->clear_color.a == 0) &&
+                      (rsc->clear_color.r == 0) &&
+                      (rsc->clear_color.g == 0) &&
+                      (rsc->clear_color.b == 0))
+                    {
+                       // Skip clear color as we don't want to write black
+                       mask &= ~GL_COLOR_BUFFER_BIT;
+                    }
+                  else if (rsc->clear_color.a != 1.0)
+                    {
+                       // TODO: Draw a rectangle? This will never be the perfect solution though.
+                       WRN("glClear() used with a semi-transparent color and direct rendering. "
+                           "This will erase the previous contents of the evas!");
+                    }
+                  if (!mask) return;
+               }
+
              if ((!ctx->direct_scissor))
                {
                   glEnable(GL_SCISSOR_TEST);
@@ -374,6 +418,8 @@ _evgl_glClear(GLbitfield mask)
                }
 
              glClear(mask);
+
+             // TODO/FIXME: Restore previous client-side scissors.
           }
         else
           {
@@ -887,7 +933,7 @@ void
 _evgld_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
 {
    EVGL_FUNC_BEGIN();
-   glClearColor(red, green, blue, alpha);
+   _evgl_glClearColor(red, green, blue, alpha);
    GLERR(__FUNCTION__, __FILE__, __LINE__, "");
    EVGL_FUNC_END();
 }
@@ -2386,7 +2432,7 @@ _normal_gl_api_get(Evas_GL_API *funcs)
    ORD(glBufferSubData);
    ORD(glCheckFramebufferStatus);
 //   ORD(glClear);
-   ORD(glClearColor);
+//   ORD(glClearColor);
 //   ORD(glClearDepthf);
    ORD(glClearStencil);
    ORD(glColorMask);
@@ -2525,6 +2571,7 @@ _normal_gl_api_get(Evas_GL_API *funcs)
 
    // For Direct Rendering
    ORD(glClear);
+   ORD(glClearColor);
    ORD(glDisable);
    ORD(glEnable);
    ORD(glGetIntegerv);
@@ -2551,6 +2598,7 @@ _direct_scissor_off_api_get(Evas_GL_API *funcs)
 #define ORD(f) EVAS_API_OVERRIDE(f, funcs,)
    // For Direct Rendering
    ORD(glClear);
+   ORD(glClearColor);
    ORD(glDisable);
    ORD(glEnable);
    ORD(glGetIntegerv);
@@ -2719,6 +2767,8 @@ _debug_gl_api_get(Evas_GL_API *funcs)
 void
 _evgl_api_get(Evas_GL_API *funcs, int debug)
 {
+   memset(funcs, 0, sizeof(Evas_GL_API));
+
    if (debug)
       _debug_gl_api_get(funcs);
    else
index c84017ca9febfde201d04093ca99fbbd538eabf6..710cbae0b1e921986192c0da91aa799f8ccb6011 100644 (file)
@@ -1092,10 +1092,15 @@ _internal_config_set(EVGL_Surface *sfc, Evas_GL_Config *cfg)
              sfc->depth_stencil_fmt = evgl_engine->caps.fbo_fmts[i].depth_stencil_fmt;
              sfc->msaa_samples      = evgl_engine->caps.fbo_fmts[i].samples;
 
+             // TODO: Implement surface reconfigure and add depth+stencil support
+
              // Direct Rendering Option
              if ( (!stencil_bit) || (evgl_engine->direct_override) )
                 sfc->direct_fb_opt = cfg->options_bits & EVAS_GL_OPTIONS_DIRECT;
 
+             // Extra flags for direct rendering
+             sfc->alpha = (cfg->color_format == EVAS_GL_RGBA_8888);
+
              cfg_index = i;
              break;
           }
index 46063a2b7e75972e4b43c5c19b4261679c5cf229..a6214f788410cb4d37256e432736cc6b3a5d2852 100644 (file)
@@ -93,8 +93,9 @@ struct _EVGL_Surface
    GLuint  depth_stencil_buf;
    GLenum  depth_stencil_fmt;
 
-   // Direct Rendering Option
-   int     direct_fb_opt;
+   // Direct Rendering Options
+   unsigned direct_fb_opt : 1;
+   unsigned alpha : 1;
 
    int     cfg_index;
 
@@ -237,6 +238,9 @@ struct _EVGL_Resource
 
         Eina_Bool            enabled : 1;
    } direct;
+   struct {
+        GLclampf r, g, b, a;
+   } clear_color;
 
 };