Added Direct Rendering to Evas' window instead of an FBO in Evas_GL.
authorsung <sung@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 20 Jan 2012 12:29:14 +0000 (12:29 +0000)
committersung <sung@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 20 Jan 2012 12:29:14 +0000 (12:29 +0000)
This optimization is significant for rendering to a large surface
because it'l save an extra copy overhead as well as an extra rendering pass.

To enable it, you can give EVAS_GL_OPTIONS_DIRECT hint in the surface
config options_bits. The following conditions have to be met in order
for evas to render directly into the Evas' window. If they are not met, the
engine will fallback to rendering to an FBO as it normally does.

conditions:
1.) All the GL calls have to be called using the pixel_get_callback function.
This is necessary for the evas object order to be maintained.
2.) Alpha must be disabled on the image ojbect that renders evas_gl.
3.) No rotation allowed.

One way to override above condition is to set EVAS_GL_DIRECT_OVERRIDE=1 but
there is no guarantee in its behavior.

Currently, this optimization is added for gl_x11 engine only.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@67388 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
NEWS
src/lib/canvas/evas_object_image.c
src/lib/include/evas_private.h
src/modules/engines/gl_x11/evas_engine.c
src/modules/engines/software_generic/evas_engine.c

index efae308..0242cc5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * Add evas_object_smart_callback_del_full() to allow users to
        unregister a specific smart event callback instead of all
        callbacks matching a given type and function pointer.
-        
+
 2012-01-17  Carsten Haitzler (The Rasterman)
 
         * Add EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN pointer mode
 2012-01-19  Cedric Bail
 
        * Add double buffer support to buffer engine.
+
+2012-01-20  Sung W. Park (sung_)
+
+       * Add Direct Rendering to Evas' window optimization for Evas_GL.  This 
+          optimization can be significant since it avoids and extra copy from
+          an offscreen buffer.  Normally, Evas_GL will render to a render
+          target using an FBO. This can be enabled by giving 
+          EVAS_GL_OPTIONS_DIRECT hint in the config options_bits. Direct 
+          rendering is actually done if the following conditions are met - 
+          1) All GL rendering is done in the pixel_getter callback 2) No 
+          rotation on the image object 3) Corresponding image 
+          object has alpha disabled.
+
diff --git a/NEWS b/NEWS
index 68df381..1dd6ad6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -66,6 +66,9 @@ Additions:
     * underline dashing suport to textblock
     * API to get largest image size
     * GL Cocoa engine
+    * Evas GL support in software backend through OSMesa
+    * API to new/free Evas_GL_Config rather than user declaring it
+    * Evas GL Direct rendering option hint to allow rendering to evas' window when possible
 
 Fixes:
 
index d9f6378..2553ec4 100644 (file)
@@ -2908,11 +2908,31 @@ evas_object_image_render(Evas_Object *obj, void *output, void *context, void *su
      {
        Evas_Coord idw, idh, idx, idy;
        int ix, iy, iw, ih;
+        int img_set = 0;
 
        if (o->dirty_pixels)
          {
             if (o->func.get_pixels)
               {
+                  // Set img object for direct rendering optimization
+                  // Check for image w/h against image geometry w/h
+                  // Check for image color r,g,b,a = {255,255,255,255}
+                  // Check and make sure that there are no maps.
+                  if ( (obj->cur.geometry.w == o->cur.image.w) &&
+                       (obj->cur.geometry.h == o->cur.image.h) &&
+                       (obj->cur.color.r == 255) &&
+                       (obj->cur.color.g == 255) &&
+                       (obj->cur.color.b == 255) &&
+                       (obj->cur.color.a == 255) && 
+                       (!obj->cur.map) )
+                    {
+                       if (obj->layer->evas->engine.func->gl_img_obj_set)
+                         {
+                            obj->layer->evas->engine.func->gl_img_obj_set(output, obj, o->cur.has_alpha);
+                            img_set = 1;
+                         }
+                    }
+
                  o->func.get_pixels(o->func.get_pixels_data, obj);
                  if (o->engine_data != pixels)
                    pixels = o->engine_data;
@@ -3152,7 +3172,17 @@ evas_object_image_render(Evas_Object *obj, void *output, void *context, void *su
                   idy = ydy;
                   if (dobreak_w) break;
                }
-         }
+          }
+
+        // Unset img object 
+        if (img_set)
+          {
+             if (obj->layer->evas->engine.func->gl_img_obj_set)
+               {
+                  obj->layer->evas->engine.func->gl_img_obj_set(output, NULL, 0);
+                  img_set = 0;
+               }
+          }        
      }
 }
 
index 84c1d36..2e9eb79 100644 (file)
@@ -850,6 +850,7 @@ struct _Evas_Func
    void *(*gl_proc_address_get)          (void *data, const char *name);
    int  (*gl_native_surface_get)         (void *data, void *surface, void *native_surface);
    void *(*gl_api_get)                   (void *data);
+   void (*gl_img_obj_set)                (void *data, void *image, int has_alpha);
 
    int  (*image_load_error_get)          (void *data, void *image);
    int  (*font_run_end_get)              (void *data, Evas_Font_Set *font, Evas_Font_Instance **script_fi, Evas_Font_Instance **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len);
index fbbd1a2..736858b 100644 (file)
@@ -41,6 +41,17 @@ struct _Render_Engine
    int w, h;
    int vsync;
 
+   // Shader used for Evas_GL_Direct Optimization
+   GLuint   df_program;
+   GLuint   df_vtx_shader;
+   GLuint   df_fgmt_shader;   
+   GLuint   df_col_attrib;
+   GLuint   df_pos_attrib;
+
+   GLfloat  df_clear_color[4];
+   GLfloat  df_depth_value;
+
+   int      df_initialized;
 };
 
 struct _Render_Engine_GL_Surface
@@ -51,6 +62,8 @@ struct _Render_Engine_GL_Surface
    int      depth_bits;
    int      stencil_bits;
 
+   int      direct_fb_opt;
+
    // Render target texture/buffers
    GLuint   rt_tex;
    GLint    rt_internal_fmt;
@@ -60,6 +73,12 @@ struct _Render_Engine_GL_Surface
    GLuint   rb_stencil;
    GLenum   rb_stencil_fmt;
 
+#if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
+   EGLSurface  direct_sfc;
+#else
+   Window      direct_sfc;
+#endif
+
    Render_Engine_GL_Context   *current_ctx;
 };
 
@@ -74,6 +93,10 @@ struct _Render_Engine_GL_Context
    GLuint      context_fbo;
    GLuint      current_fbo;
 
+
+   int         scissor_enabled;
+   int         scissor_upated;
+
    Render_Engine_GL_Surface   *current_sfc;
 };
 
@@ -99,8 +122,11 @@ struct _Extension_Entry
 
 static int initted = 0;
 static int gl_wins = 0;
-static Render_Engine_GL_Context *current_evgl_ctx;
-static Render_Engine *current_engine;
+static int gl_direct_override = 0;
+static int gl_direct_enabled = 0;
+static Render_Engine_GL_Context *current_evgl_ctx = NULL;
+static Render_Engine *current_engine = NULL;
+static Evas_Object *gl_direct_img_obj = NULL;
 
 static char _gl_ext_string[1024];
 static char _evasgl_ext_string[1024];
@@ -2605,13 +2631,22 @@ eng_image_draw(void *data, void *context, void *surface, void *image, int src_x,
 
    re = (Render_Engine *)data;
    if (!image) return;
-   eng_window_use(re->win);
-   evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
-   re->win->gl_context->dc = context;
-   evas_gl_common_image_draw(re->win->gl_context, image,
-                             src_x, src_y, src_w, src_h,
-                             dst_x, dst_y, dst_w, dst_h,
-                             smooth);
+
+   if ((gl_direct_img_obj) && (gl_direct_enabled))
+     {
+        DBG("Rendering Directly to the window");
+        evas_object_image_pixels_dirty_set(gl_direct_img_obj, EINA_TRUE);
+     }
+   else
+     {
+        eng_window_use(re->win);
+        evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
+        re->win->gl_context->dc = context;
+        evas_gl_common_image_draw(re->win->gl_context, image,
+                                  src_x, src_y, src_w, src_h,
+                                  dst_x, dst_y, dst_w, dst_h,
+                                  smooth);
+     }
 }
 
 static void
@@ -2794,7 +2829,7 @@ static int
 _set_internal_config(Render_Engine_GL_Surface *sfc, Evas_GL_Config *cfg)
 {
    // Also initialize pixel format here as well...
-   switch(cfg->color_format)
+   switch((int)cfg->color_format)
      {
       case EVAS_GL_RGB_888:
          sfc->rt_fmt          = GL_RGB;
@@ -2849,7 +2884,12 @@ _set_internal_config(Render_Engine_GL_Surface *sfc, Evas_GL_Config *cfg)
          return 0;
      }
 
-   // Do Packed Depth24_Stencil8 Later...
+   if (cfg->options_bits)
+     {
+        if (cfg->options_bits & EVAS_GL_OPTIONS_DIRECT)
+           sfc->direct_fb_opt       = 1;
+        // Add other options here...
+     }
 
    return 1;
 }
@@ -2954,6 +2994,11 @@ eng_gl_surface_create(void *data, void *config, int w, int h)
    sfc->rb_depth     = 0;
    sfc->rb_stencil   = 0;
 
+   /* Allow alpha for evas gl direct rendering */
+   // FIXME!!!: A little out of place for for now...
+   if (!gl_direct_override)
+      if (getenv("EVAS_GL_DIRECT_OVERRIDE")) gl_direct_override = 1;
+
    // Set the internal format based on the config
    if (!_set_internal_config(sfc, cfg))
      {
@@ -2962,6 +3007,16 @@ eng_gl_surface_create(void *data, void *config, int w, int h)
         return NULL;
      }
 
+   if (sfc->direct_fb_opt)
+     {
+        DBG("Enabling Direct rendering to the Evas' window."); 
+#if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
+        sfc->direct_sfc = re->win->egl_surface[0];
+#else
+        sfc->direct_sfc = re->win->win;
+#endif
+     }
+
    // Create internal resource context if it hasn't been created already
    if ((rsc = eina_tls_get(resource_key)) == NULL)
      {
@@ -3039,6 +3094,17 @@ eng_gl_surface_destroy(void *data, void *surface)
         return 0;
      }
 
+   // Reset the Framebuffer binding point
+   if ((current_evgl_ctx) && (current_evgl_ctx->current_fbo == current_evgl_ctx->context_fbo))
+     {
+        //glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        current_evgl_ctx->current_fbo = 0;
+        current_evgl_ctx->current_sfc = NULL;
+     }
+   
+   // Clear direct rendering flag
+   gl_direct_enabled = 0;
+
    // Delete FBO/RBO and Texture here
    if (sfc->rt_tex)
       glDeleteTextures(1, &sfc->rt_tex);
@@ -3049,6 +3115,8 @@ eng_gl_surface_destroy(void *data, void *surface)
    if (sfc->rb_stencil)
       glDeleteRenderbuffers(1, &sfc->rb_stencil);
 
+
+
 #if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
    ret = eglMakeCurrent(re->win->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 #else
@@ -3158,7 +3226,7 @@ eng_gl_context_destroy(void *data, void *context)
 
    if ((rsc = eina_tls_get(resource_key)) == EINA_FALSE) return 0;
 
-   // 1. Do a make current with the given context
+   // Do a make current with the given context
 #if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
    ret = eglMakeCurrent(re->win->egl_disp, rsc->surface,
                         rsc->surface, ctx->context);
@@ -3172,11 +3240,11 @@ eng_gl_context_destroy(void *data, void *context)
         return 0;
      }
 
-   // 2. Delete the FBO
+   // Delete the FBO
    if (ctx->context_fbo)
         glDeleteFramebuffers(1, &ctx->context_fbo);
 
-   // 3. Destroy the Context
+   // Destroy the Context
 #if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
    eglDestroyContext(re->win->egl_disp, ctx->context);
 
@@ -3218,6 +3286,16 @@ eng_gl_make_current(void *data __UNUSED__, void *surface, void *context)
    sfc = (Render_Engine_GL_Surface*)surface;
    ctx = (Render_Engine_GL_Context*)context;
 
+   // Check if direct rendering is possible:
+   //    It's possible when direct_fb_opt is on and either current image 
+   //    object is valid or gl_direct_override is on.  Override allows 
+   //    rendering outside of pixel getter but it doesn't guarantee 
+   //    correct rendering.
+   if ((sfc->direct_fb_opt) && (gl_direct_img_obj || gl_direct_override))
+      gl_direct_enabled = 1;
+   else
+      gl_direct_enabled = 0;
+
    // Unset surface/context
    if ((!sfc) || (!ctx))
      {
@@ -3239,67 +3317,117 @@ eng_gl_make_current(void *data __UNUSED__, void *surface, void *context)
         return 1;
      }
 
-   // Do a make current only if it's not already current
+   if (gl_direct_enabled)
+     {
+        // Do a make current only if it's not already current
 #if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
-   if ((rsc = eina_tls_get(resource_key)) == EINA_FALSE) return 0;
+        if ((eglGetCurrentContext() != ctx->context) || 
+            (eglGetCurrentSurface(EGL_READ) != sfc->direct_sfc) ||
+            (eglGetCurrentSurface(EGL_DRAW) != sfc->direct_sfc) ) 
+          {
+             int curr_fbo = 0;
+             DBG("Rendering Directly to the window\n");
 
-   if ((eglGetCurrentContext() != ctx->context) ||
-       (eglGetCurrentSurface(EGL_READ) != rsc->surface) ||
-       (eglGetCurrentSurface(EGL_DRAW) != rsc->surface) )
-     {
-        // Flush remainder of what's in Evas' pipeline
-        if (re->win) eng_window_use(NULL);
+             // Flush remainder of what's in Evas' pipeline
+             if (re->win) eng_window_use(NULL);
 
-        // Do a make current
-        ret = eglMakeCurrent(re->win->egl_disp, rsc->surface,
-                             rsc->surface, ctx->context);
-        if (!ret)
+             // Do a make current
+             ret = eglMakeCurrent(re->win->egl_disp, sfc->direct_sfc,
+                                  sfc->direct_sfc, ctx->context);
+             if (!ret)
+               {
+                  ERR("xxxMakeCurrent() failed! code=%#x", eglGetError());
+                  //ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
+
+             glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo);
+             if (ctx->context_fbo == curr_fbo)
+               {
+                  ctx->current_fbo = 0;
+                  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+               }
+          }
+#else
+        if ((glXGetCurrentContext() != ctx->context))
           {
-             ERR("xxxMakeCurrent() failed!");
-             return 0;
+             // Flush remainder of what's in Evas' pipeline
+             if (re->win) eng_window_use(NULL);
+
+             // Do a make current
+             ret = glXMakeCurrent(re->info->info.display, sfc->direct_sfc, ctx->context);
+             if (!ret) 
+               {
+                  ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
           }
+#endif
      }
-#else
-   if ((glXGetCurrentContext() != ctx->context) ||
-       (glXGetCurrentDrawable() != re->win->win) )
+   else
      {
-        // Flush remainder of what's in Evas' pipeline
-        if (re->win) eng_window_use(NULL);
+        // Do a make current only if it's not already current
+#if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
+        if ((rsc = eina_tls_get(resource_key)) == EINA_FALSE) return 0;
 
-        // Do a make current
-        ret = glXMakeCurrent(re->info->info.display, re->win->win, ctx->context);
-        if (!ret)
+        if ((eglGetCurrentContext() != ctx->context) || 
+            (eglGetCurrentSurface(EGL_READ) != rsc->surface) ||
+            (eglGetCurrentSurface(EGL_DRAW) != rsc->surface) ) 
           {
-             ERR("xxxMakeCurrent() failed!");
-             return 0;
+             // Flush remainder of what's in Evas' pipeline
+             if (re->win) eng_window_use(NULL);
+
+             // Do a make current
+             ret = eglMakeCurrent(re->win->egl_disp, rsc->surface,
+                                  rsc->surface, ctx->context);
+             if (!ret)
+               {
+                  ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
           }
-     }
-#endif
+#else
+        if ((glXGetCurrentContext() != ctx->context) ||
+            (glXGetCurrentDrawable() != re->win->win) )
+          {
+             // Flush remainder of what's in Evas' pipeline
+             if (re->win) eng_window_use(NULL);
 
-   // Create FBO if not already created
-   if (!ctx->initialized)
-     {
-        glGenFramebuffers(1, &ctx->context_fbo);
-        ctx->initialized = 1;
-     }
+             // Do a make current
+             ret = glXMakeCurrent(re->info->info.display, re->win->win, ctx->context);
+             if (!ret) 
+               {
+                  ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
+          }
+#endif
 
-   // Attach FBO if it hasn't been attached or if surface changed
-   if ((!sfc->fbo_attached) || (ctx->current_sfc != sfc))
-     {
-        if (!_attach_fbo_surface(re, sfc, ctx))
+        // Create FBO if not already created
+        if (!ctx->initialized)
           {
-             ERR("_attach_fbo_surface() failed.");
-             return 0;
+             glGenFramebuffers(1, &ctx->context_fbo);
+             ctx->initialized = 1;
           }
 
-        if (ctx->current_fbo)
-           // Bind to the previously bound buffer
-           glBindFramebuffer(GL_FRAMEBUFFER, ctx->current_fbo);
-        else
-           // Bind FBO
-           glBindFramebuffer(GL_FRAMEBUFFER, ctx->context_fbo);
+        // Attach FBO if it hasn't been attached or if surface changed
+        if ((!sfc->fbo_attached) || (ctx->current_sfc != sfc))
+          {
+             if (!_attach_fbo_surface(re, sfc, ctx))
+               {
+                  ERR("_attach_fbo_surface() failed.");
+                  return 0;
+               }
 
-        sfc->fbo_attached = 1;
+             if (ctx->current_fbo)
+                // Bind to the previously bound buffer
+                glBindFramebuffer(GL_FRAMEBUFFER, ctx->current_fbo);
+             else
+                // Bind FBO
+                glBindFramebuffer(GL_FRAMEBUFFER, ctx->context_fbo);
+
+             sfc->fbo_attached = 1;
+          }
      }
 
    // Set the current surface/context
@@ -3345,13 +3473,28 @@ eng_gl_native_surface_get(void *data, void *surface, void *native_surface)
    sfc = (Render_Engine_GL_Surface*)surface;
    ns  = (Evas_Native_Surface*)native_surface;
 
-   ns->type = EVAS_NATIVE_SURFACE_OPENGL;
-   ns->version = EVAS_NATIVE_SURFACE_VERSION;
-   ns->data.opengl.texture_id = sfc->rt_tex;
-   ns->data.opengl.x = 0;
-   ns->data.opengl.y = 0;
-   ns->data.opengl.w = sfc->w;
-   ns->data.opengl.h = sfc->h;
+   if (sfc->direct_fb_opt)
+     {
+        ns->type = EVAS_NATIVE_SURFACE_OPENGL;
+        ns->version = EVAS_NATIVE_SURFACE_VERSION;
+        ns->data.opengl.texture_id = sfc->rt_tex;
+        ns->data.opengl.framebuffer_id = 0;
+        ns->data.opengl.x = 0;
+        ns->data.opengl.y = 0;
+        ns->data.opengl.w = sfc->w;
+        ns->data.opengl.h = sfc->h;
+     }
+   else
+     {
+        ns->type = EVAS_NATIVE_SURFACE_OPENGL;
+        ns->version = EVAS_NATIVE_SURFACE_VERSION;
+        ns->data.opengl.texture_id = sfc->rt_tex;
+        ns->data.opengl.framebuffer_id = sfc->rt_tex;
+        ns->data.opengl.x = 0;
+        ns->data.opengl.y = 0;
+        ns->data.opengl.w = sfc->w;
+        ns->data.opengl.h = sfc->h;
+     }
 
    return 1;
 }
@@ -3374,7 +3517,9 @@ evgl_glBindFramebuffer(GLenum target, GLuint framebuffer)
    // Take care of BindFramebuffer 0 issue
    if (framebuffer==0)
      {
-        if (ctx)
+        if (gl_direct_enabled)
+           glBindFramebuffer(target, 0);
+        else if (ctx)
           {
              glBindFramebuffer(target, ctx->context_fbo);
              ctx->current_fbo = 0;
@@ -3398,6 +3543,228 @@ evgl_glBindRenderbuffer(GLenum target, GLuint renderbuffer)
    glBindRenderbuffer(target, renderbuffer);
 }
 
+// Transform from Evas Coordinat to GL Coordinate
+// returns: oc[4] original image object dimension in gl coord
+// returns: nc[4] tranformed  (x, y, width, heigth) in gl coord
+static void
+compute_gl_coordinates(Evas_Object *obj, int rot, int clip, 
+                       int x, int y, int width, int height, 
+                       int imgc[4], int objc[4])
+{
+   int nx1, ny1, nx2, ny2;
+   int ox1, oy1, ox2, oy2;
+
+   if (rot == 0)
+     {
+        // oringinal image object coordinate in gl coordinate
+        imgc[0] = obj->cur.geometry.x; 
+        imgc[1] = obj->layer->evas->output.h - obj->cur.geometry.y - obj->cur.geometry.h;
+        imgc[2] = imgc[0] + obj->cur.geometry.w;
+        imgc[3] = imgc[1] + obj->cur.geometry.h;
+
+        // transformed (x,y,width,height) in gl coordinate
+        objc[0] = imgc[0] + x;
+        objc[1] = imgc[1] + y;
+        objc[2] = objc[0] + width;
+        objc[3] = objc[1] + height;
+     }
+   else if (rot == 180)
+     {
+        // oringinal image object coordinate in gl coordinate
+        imgc[0] = obj->layer->evas->output.w - obj->cur.geometry.x - obj->cur.geometry.w;
+        imgc[1] = obj->cur.geometry.y;
+        imgc[2] = imgc[0] + obj->cur.geometry.w;
+        imgc[3] = imgc[1] + obj->cur.geometry.h;
+
+        // transformed (x,y,width,height) in gl coordinate
+        objc[0] = imgc[0] + obj->cur.geometry.w - x - width;
+        objc[1] = imgc[1] + obj->cur.geometry.h - y - height;
+        objc[2] = objc[0] + width;
+        objc[3] = objc[1] + height;
+
+     }
+   else if (rot == 90)
+     {
+        // oringinal image object coordinate in gl coordinate
+        imgc[0] = obj->cur.geometry.y;
+        imgc[1] = obj->cur.geometry.x;
+        imgc[2] = imgc[0] + obj->cur.geometry.h;
+        imgc[3] = imgc[1] + obj->cur.geometry.w;
+
+        // transformed (x,y,width,height) in gl coordinate
+        objc[0] = imgc[0] + obj->cur.geometry.h - y - height;
+        objc[1] = imgc[1] + x;
+        objc[2] = objc[0] + height;
+        objc[3] = objc[1] + width;
+     }
+   else if (rot == 270)
+     {
+        // oringinal image object coordinate in gl coordinate
+        imgc[0] = obj->layer->evas->output.h - obj->cur.geometry.y - obj->cur.geometry.h;
+        imgc[1] = obj->layer->evas->output.w - obj->cur.geometry.x - obj->cur.geometry.w;
+        imgc[2] = imgc[0] + obj->cur.geometry.h;
+        imgc[3] = imgc[1] + obj->cur.geometry.w;
+
+        // transformed (x,y,width,height) in gl coordinate
+        objc[0] = imgc[0] + y;
+        objc[1] = imgc[1] + obj->cur.geometry.w - x - width;
+        objc[2] = objc[0] + height;
+        objc[3] = objc[1] + width;
+     }
+   else
+     {
+        ERR("Invalid rotation angle %d.", rot);
+        return;
+     }
+
+   if (clip)
+     {
+        // Clip against original image object
+        if (objc[0] < imgc[0]) objc[0] = imgc[0];
+        if (objc[0] > imgc[2]) objc[0] = 0;
+
+        if (objc[1] < imgc[1]) objc[1] = imgc[1];
+        if (objc[1] > imgc[3]) objc[1] = 0;
+
+        if (objc[2] < imgc[0]) objc[0] = 0;
+        if (objc[2] > imgc[2]) objc[2] = imgc[2];
+
+        if (objc[3] < imgc[1]) objc[1] = 0;
+        if (objc[3] > imgc[3]) objc[3] = imgc[3];
+     }
+
+   imgc[2] = imgc[2]-imgc[0];     // width
+   imgc[3] = imgc[3]-imgc[1];     // height
+
+   objc[2] = objc[2]-objc[0];     // width
+   objc[3] = objc[3]-objc[1];     // height
+}
+
+static void
+evgl_glClear(GLbitfield mask)
+{
+   Render_Engine_GL_Context *ctx = current_evgl_ctx;
+   int rot = 0;
+   int oc[4], nc[4];
+
+   if ((gl_direct_img_obj) && (gl_direct_enabled) && (ctx) && (!ctx->current_fbo))
+     {
+        if ((current_engine) && (current_engine->win) && (current_engine->win->gl_context))
+           rot = current_engine->win->gl_context->rot;
+        else
+           ERR("Unable to retrieve rotation angle: %d", rot);
+
+        compute_gl_coordinates(gl_direct_img_obj, rot, 0, 0, 0, 0, 0, oc, nc);
+        glScissor(oc[0], oc[1], oc[2], oc[3]);
+        glClear(mask);
+     }
+   else
+      glClear(mask);
+}
+
+static void
+evgl_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+   current_engine->df_clear_color[0] = red;
+   current_engine->df_clear_color[1] = green;
+   current_engine->df_clear_color[2] = blue;
+   current_engine->df_clear_color[3] = alpha;
+
+   glClearColor(red, green, blue, alpha);
+
+}
+
+static void 
+evgl_glEnable(GLenum cap)
+{
+   Render_Engine_GL_Context *ctx = current_evgl_ctx;
+
+   if (cap == GL_SCISSOR_TEST)
+      if (ctx) ctx->scissor_enabled = 1;
+   glEnable(cap);
+}
+
+static void
+evgl_glDisable(GLenum cap)
+{
+   Render_Engine_GL_Context *ctx = current_evgl_ctx;
+
+   if (cap == GL_SCISSOR_TEST)
+      if (ctx) ctx->scissor_enabled = 0;
+   glDisable(cap);
+}
+
+
+static void
+evgl_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+{
+   Render_Engine_GL_Context *ctx = current_evgl_ctx;
+   int rot = 0;
+   int oc[4], nc[4];
+
+   if ((gl_direct_img_obj) && (gl_direct_enabled) && (ctx) && (!ctx->current_fbo))
+     {
+        if ((current_engine) && (current_engine->win) && (current_engine->win->gl_context))
+           rot = current_engine->win->gl_context->rot;
+        else
+           ERR("Unable to retrieve rotation angle: %d", rot);
+
+        compute_gl_coordinates(gl_direct_img_obj, rot, 1, x, y, width, height, oc, nc);
+        glReadPixels(nc[0], nc[1], nc[2], nc[3], format, type, pixels);
+     }
+   else
+      glReadPixels(x, y, width, height, format, type, pixels);
+}
+
+static void
+evgl_glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   Render_Engine_GL_Context *ctx = current_evgl_ctx;
+   int rot = 0;
+   int oc[4], nc[4];
+
+   if ((gl_direct_img_obj) && (gl_direct_enabled) && (ctx) && (!ctx->current_fbo))
+     {
+        if ((current_engine) && (current_engine->win) && (current_engine->win->gl_context))
+           rot = current_engine->win->gl_context->rot;
+        else
+           ERR("Unable to retrieve rotation angle: %d", rot);
+
+        compute_gl_coordinates(gl_direct_img_obj, rot, 1, x, y, width, height, oc, nc);
+        glScissor(nc[0], nc[1], nc[2], nc[3]);
+        ctx->scissor_upated = 1;
+     }
+   else
+      glScissor(x, y, width, height);
+}
+
+static void
+evgl_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   Render_Engine_GL_Context *ctx = current_evgl_ctx;
+   int rot = 0;
+   int oc[4], nc[4];
+
+   if ((gl_direct_img_obj) && (gl_direct_enabled) && (ctx) && (!ctx->current_fbo))
+     {
+        if ((current_engine) && (current_engine->win) && (current_engine->win->gl_context))
+           rot = current_engine->win->gl_context->rot;
+        else
+           ERR("Unable to retrieve rotation angle: %d", rot);
+
+        compute_gl_coordinates(gl_direct_img_obj, rot, 0, x, y, width, height, oc, nc);
+        glEnable(GL_SCISSOR_TEST);
+        glScissor(oc[0], oc[1], oc[2], oc[3]);
+        glViewport(nc[0], nc[1], nc[2], nc[3]);
+     }
+   else
+      glViewport(x, y, width, height);
+
+}
+
+
+//----------------------------------------------//
+
 static void
 evgl_glClearDepthf(GLclampf depth)
 {
@@ -3531,8 +3898,8 @@ eng_gl_api_get(void *data)
    ORD(glBufferData);
    ORD(glBufferSubData);
    ORD(glCheckFramebufferStatus);
-   ORD(glClear);
-   ORD(glClearColor);
+//   ORD(glClear);
+//   ORD(glClearColor);
 //   ORD(glClearDepthf);
    ORD(glClearStencil);
    ORD(glColorMask);
@@ -3554,11 +3921,11 @@ eng_gl_api_get(void *data)
    ORD(glDepthMask);
 //   ORD(glDepthRangef);
    ORD(glDetachShader);
-   ORD(glDisable);
+//   ORD(glDisable);
    ORD(glDisableVertexAttribArray);
    ORD(glDrawArrays);
    ORD(glDrawElements);
-   ORD(glEnable);
+//   ORD(glEnable);
    ORD(glEnableVertexAttribArray);
    ORD(glFinish);
    ORD(glFlush);
@@ -3612,7 +3979,7 @@ eng_gl_api_get(void *data)
 //   ORD(glReleaseShaderCompiler);
    ORD(glRenderbufferStorage);
    ORD(glSampleCoverage);
-   ORD(glScissor);
+//   ORD(glScissor);
 //   ORD(glShaderBinary);
    ORD(glShaderSource);
    ORD(glStencilFunc);
@@ -3657,7 +4024,7 @@ eng_gl_api_get(void *data)
    ORD(glVertexAttrib4f);
    ORD(glVertexAttrib4fv);
    ORD(glVertexAttribPointer);
-   ORD(glViewport);
+//   ORD(glViewport);
 #undef ORD
 
 #define ORD(f) EVAS_API_OVERRIDE(f, &gl_funcs, glsym_)
@@ -3717,6 +4084,14 @@ eng_gl_api_get(void *data)
    ORD(glBindFramebuffer);
    ORD(glBindRenderbuffer);
 
+   ORD(glClear);
+   ORD(glClearColor);
+   ORD(glEnable);
+   ORD(glDisable);
+   ORD(glReadPixels);
+   ORD(glScissor);
+   ORD(glViewport);
+
    // GLES2.0 API compat on top of desktop gl
    ORD(glClearDepthf);
    ORD(glDepthRangef);
@@ -3739,6 +4114,24 @@ eng_gl_api_get(void *data)
    return &gl_funcs;
 }
 
+static void
+eng_gl_img_obj_set(void *data, void *image, int has_alpha)
+{
+   Render_Engine *re = (Render_Engine *)data;
+
+   gl_direct_img_obj = NULL;
+
+   // Normally direct rendering isn't allowed if alpha is on and
+   // rotation is not 0.  BUT, if override is on, allow it. 
+   if ((has_alpha) && (re->win->gl_context->rot!=0)) 
+     {
+        if (gl_direct_override)
+           gl_direct_img_obj = image;
+     }
+   else 
+      gl_direct_img_obj = image;   
+}
+
 static int
 eng_image_load_error_get(void *data __UNUSED__, void *image)
 {
@@ -3877,6 +4270,9 @@ module_open(Evas_Module *em)
         EINA_LOG_ERR("Can not create a module log domain.");
         return 0;
      }
+   /* Allow alpha for evas gl direct rendering */
+   if (getenv("EVAS_GL_DIRECT_OVERRIDE")) gl_direct_override = 1;
+
    /* store it for later use */
    func = pfunc;
    /* now to override methods */
@@ -3961,6 +4357,7 @@ module_open(Evas_Module *em)
    ORD(gl_proc_address_get);
    ORD(gl_native_surface_get);
    ORD(gl_api_get);
+   ORD(gl_img_obj_set);
 
    ORD(image_load_error_get);
 
index b7b9888..817b87d 100644 (file)
@@ -1778,6 +1778,7 @@ static Evas_Func func =
      NULL, // need software mesa for gl rendering <- gl_proc_address_get
      NULL, // need software mesa for gl rendering <- gl_native_surface_get
      NULL, // need software mesa for gl rendering <- gl_api_get
+     NULL, // need software mesa for gl rendering <- gl_img_obj_set
      eng_image_load_error_get,
      eng_font_run_font_end_get,
      eng_image_animated_get,