Applying direct rendering
authorPark SangHee <sh15.park@samsung.com>
Thu, 9 Feb 2012 07:25:13 +0000 (16:25 +0900)
committerPark SangHee <sh15.park@samsung.com>
Thu, 9 Feb 2012 07:34:57 +0000 (16:34 +0900)
src/lib/Evas_GL.h
src/lib/canvas/evas_gl.c
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 39f6ada..b8e28ef 100644 (file)
@@ -43,11 +43,18 @@ typedef enum _Evas_GL_Stencil_Bits
     EVAS_GL_STENCIL_BIT_16 = 5,
 } Evas_GL_Stencil_Bits;
 
+typedef enum _Evas_GL_Options_Bits
+{
+   EVAS_GL_OPTIONS_NONE    = 0,
+   EVAS_GL_OPTIONS_DIRECT  = (1<<0)
+} Evas_GL_Options_Bits;
+
 struct _Evas_GL_Config
 {
-    Evas_GL_Color_Format     color_format;
-    Evas_GL_Depth_Bits       depth_bits;
-    Evas_GL_Stencil_Bits     stencil_bits;
+   Evas_GL_Color_Format     color_format;
+   Evas_GL_Depth_Bits       depth_bits;
+   Evas_GL_Stencil_Bits     stencil_bits;
+   Evas_GL_Options_Bits     options_bits;
 };
 
 #define EVAS_GL_EXTENSIONS       1
@@ -75,6 +82,7 @@ typedef struct _GLData
 {
    Evas_GL_Context *ctx;
    Evas_GL_Surface *sfc;
+   Evas_GL_Config  *cfg;
    Evas_GL         *evasgl;
    Evas_GL_API     *glapi;
    GLuint           program;
@@ -95,13 +103,6 @@ static GLuint    load_shader  (GLData *gld, GLenum type, const char *shader_src)
 int
 main(int argc, char **argv)
 {
-   // config for the surface for evas_gl
-   Evas_GL_Config config =
-     {
-        EVAS_GL_RGBA_8888,
-        EVAS_GL_DEPTH_NONE,
-        EVAS_GL_STENCIL_NONE
-     };
    // a size by default
    int w = 256, h = 256;
    // some variables we will use
@@ -126,8 +127,16 @@ main(int argc, char **argv)
    // get the evas gl handle for doing gl things
    gld->evasgl = evas_gl_new(canvas);
    gld->glapi = evas_gl_api_get(gld->evasgl);
+
+   // Set a surface config
+   gld->cfg = evas_gl_config_new();
+   gld->cfg->color_format = EVAS_GL_RGBA_8888;
+   //gld->cfg->depth_bits   = EVAS_GL_DEPTH_NONE;        // Othe config options
+   //gld->cfg->stencil_bits = EVAS_GL_STENCIL_NONE;
+   //gld->cfg->options_bits = EVAS_GL_OPTIONS_NONE;
+
    // create a surface and context
-   gld->sfc = evas_gl_surface_create(gld->evasgl, &config, w, h);
+   gld->sfc = evas_gl_surface_create(gld->evasgl, gld->cfg, w, h);
    gld->ctx = evas_gl_context_create(gld->evasgl, NULL);
    //-//
    //-//-//-// END GL INIT BLOB
@@ -209,6 +218,7 @@ on_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
 
    evas_gl_surface_destroy(gld->evasgl, gld->sfc);
    evas_gl_context_destroy(gld->evasgl, gld->ctx);
+   evas_gl_config_free(gld->cfg);
    evas_gl_free(gld->evasgl);
    free(gld);
 }
@@ -391,6 +401,22 @@ EAPI Evas_GL                 *evas_gl_new                (Evas *e) EINA_WARN_UNU
 EAPI void                     evas_gl_free               (Evas_GL *evas_gl) EINA_ARG_NONNULL(1);
 
 /**
+ * Allocates a new config object for the user to fill out.
+ *
+ * As long as the Evas creates a config object for the user, it takes care
+ * of the backward compatibility issue.
+ */
+EAPI Evas_GL_Config          *evas_gl_config_new         ();
+
+/**
+ * Frees a config object created from evas_gl_config_new.
+ *
+ * As long as the Evas creates a config object for the user, it takes care
+ * of the backward compatibility issue.
+ */
+EAPI void                     evas_gl_config_free        (Evas_GL_Config *cfg) EINA_ARG_NONNULL(1);
+
+/**
  * Creates and returns new Evas_GL_Surface object for GL Rendering.
  *
  * @param evas_gl The given Evas_GL object.
index 08edbc4..85ed851 100644 (file)
@@ -37,6 +37,13 @@ evas_gl_new(Evas *e)
    evas_gl->magic = MAGIC_EVAS_GL;
    evas_gl->evas = e;
 
+   if (!evas_gl->evas->engine.func->gl_context_create)
+     {
+        ERR("GL engine not available\n");
+        free(evas_gl);
+        return NULL;
+     }
+
    return evas_gl;
 }
 
@@ -60,6 +67,24 @@ evas_gl_free(Evas_GL *evas_gl)
    free(evas_gl);
 }
 
+EAPI Evas_GL_Config *
+evas_gl_config_new()
+{
+   Evas_GL_Config *cfg;
+
+   cfg = calloc(1, sizeof(Evas_GL_Config));
+
+   if (!cfg) return NULL;
+
+   return cfg;
+}
+
+EAPI void
+evas_gl_config_free(Evas_GL_Config *cfg)
+{
+   if (cfg) free(cfg);
+}
+
 EAPI Evas_GL_Surface *
 evas_gl_surface_create(Evas_GL *evas_gl, Evas_GL_Config *config, int width, int height)
 {
@@ -77,6 +102,8 @@ evas_gl_surface_create(Evas_GL *evas_gl, Evas_GL_Config *config, int width, int
 
    surf = calloc(1, sizeof(Evas_GL_Surface));
 
+   if (!surf) return NULL;
+
    surf->data = evas_gl->evas->engine.func->gl_surface_create(evas_gl->evas->engine.data.output, config, width, height);
 
    if (!surf->data)
@@ -135,12 +162,6 @@ evas_gl_context_create(Evas_GL *evas_gl, Evas_GL_Context *share_ctx)
         return NULL;
      }
 
-   if (!evas_gl->evas->engine.func->gl_context_create)
-     {
-        ERR("GL engine not available\n");
-        return NULL;
-     }
-
    // Call engine->gl_create_context
    if (share_ctx)
      {
index 4f61ea6..818dc5d 100755 (executable)
@@ -2918,11 +2918,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;
@@ -3162,7 +3182,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 ed27ce2..e74c83b 100644 (file)
@@ -849,6 +849,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 c1bdfee..9c83c21 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];
@@ -2500,13 +2526,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
@@ -2689,7 +2724,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;
@@ -2744,7 +2779,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;
 }
@@ -2849,6 +2889,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))
      {
@@ -2857,6 +2902,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)
      {
@@ -2934,6 +2989,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))
+     {
+        //glsym_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)
       glsym_glDeleteTextures(1, &sfc->rt_tex);
@@ -3136,67 +3202,152 @@ 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 defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
-   if ((rsc = eina_tls_get(resource_key)) == EINA_FALSE) return 0;
+   // 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;
 
-   if ((glsym_eglGetCurrentContext() != ctx->context) ||
-       (glsym_eglGetCurrentSurface(EGL_READ) != rsc->surface) ||
-       (glsym_eglGetCurrentSurface(EGL_DRAW) != rsc->surface) )
+   if (gl_direct_enabled)
      {
-        // Flush remainder of what's in Evas' pipeline
-        if (re->win) eng_window_use(NULL);
+        int curr_fbo = 0;
 
-        // Do a make current
-        ret = glsym_eglMakeCurrent(re->win->egl_disp, rsc->surface,
-                             rsc->surface, ctx->context);
-        if (!ret)
+        // Do a make current only if it's not already current
+#if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
+        if ((glsym_eglGetCurrentContext() != ctx->context) || 
+            (glsym_eglGetCurrentSurface(EGL_READ) != sfc->direct_sfc) ||
+            (glsym_eglGetCurrentSurface(EGL_DRAW) != sfc->direct_sfc) ) 
           {
-             ERR("xxxMakeCurrent() failed!");
-             return 0;
+             DBG("Rendering Directly to the window\n");
+
+             // Flush remainder of what's in Evas' pipeline
+             if (re->win) eng_window_use(NULL);
+
+             // Do a make current
+             ret = glsym_eglMakeCurrent(re->win->egl_disp, sfc->direct_sfc,
+                                        sfc->direct_sfc, ctx->context);
+             if (!ret)
+               {
+                  ERR("xxxMakeCurrent() failed! code=%#x", glsym_eglGetError());
+                  //ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
+
           }
-     }
 #else
-   if ((glsym_glXGetCurrentContext() != ctx->context) ||
-       (glsym_glXGetCurrentDrawable() != re->win->win) )
-     {
-        // Flush remainder of what's in Evas' pipeline
-        if (re->win) eng_window_use(NULL);
-
-        // Do a make current
-        ret = glsym_glXMakeCurrent(re->info->info.display, re->win->win, ctx->context);
-        if (!ret)
+        if ((glsym_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 = glsym_glXMakeCurrent(re->info->info.display, sfc->direct_sfc, ctx->context);
+             if (!ret)
+               {
+                  ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
           }
-     }
 #endif
+        glsym_glGetIntegerv(GL_FRAMEBUFFER_BINDING, &curr_fbo);
+        if (ctx->context_fbo == curr_fbo)
+          {
+             ctx->current_fbo = 0;
+             glsym_glBindFramebuffer(GL_FRAMEBUFFER, 0);
+          }
 
-   // Create FBO if not already created
-   if (!ctx->initialized)
-     {
-        glsym_glGenFramebuffers(1, &ctx->context_fbo);
-        ctx->initialized = 1;
      }
-
-   // Attach FBO if it hasn't been attached or if surface changed
-   if ((!sfc->fbo_attached) || (ctx->current_sfc != sfc))
+   else
      {
-        if (!_attach_fbo_surface(re, sfc, ctx))
+        // Do a make current only if it's not already current
+#if defined (GLES_VARIETY_S3C6410) || defined (GLES_VARIETY_SGX)
+        if (eina_main_loop_is())
           {
-             ERR("_attach_fbo_surface() failed.");
-             return 0;
-          }
+             if ((glsym_eglGetCurrentContext() != ctx->context) ||
+                 (glsym_eglGetCurrentSurface(EGL_READ) != re->win->egl_surface[0]) ||
+                 (glsym_eglGetCurrentSurface(EGL_DRAW) != re->win->egl_surface[0]) )
+               {
 
-        if (ctx->current_fbo)
-           // Bind to the previously bound buffer
-           glsym_glBindFramebuffer(GL_FRAMEBUFFER, ctx->current_fbo);
+                  // Flush remainder of what's in Evas' pipeline
+                  if (re->win) eng_window_use(NULL);
+
+                  // Do a make current
+                  ret = glsym_eglMakeCurrent(re->win->egl_disp, re->win->egl_surface[0],
+                                             re->win->egl_surface[0], ctx->context);
+                  if (!ret)
+                    {
+                       ERR("xxxMakeCurrent() failed! code=%#x", glsym_eglGetError());
+                       return 0;
+                    }
+               }
+          }
         else
-           // Bind FBO
-           glsym_glBindFramebuffer(GL_FRAMEBUFFER, ctx->context_fbo);
+          {
+             if ((rsc = eina_tls_get(resource_key)) == EINA_FALSE) return 0;
+
+             if ((glsym_eglGetCurrentContext() != ctx->context) ||
+                 (glsym_eglGetCurrentSurface(EGL_READ) != rsc->surface) ||
+                 (glsym_eglGetCurrentSurface(EGL_DRAW) != rsc->surface) )
+               {
+                  // Flush remainder of what's in Evas' pipeline
+                  if (re->win) eng_window_use(NULL);
+
+                  // Do a make current
+                  ret = glsym_eglMakeCurrent(re->win->egl_disp, rsc->surface,
+                                             rsc->surface, ctx->context);
+                  if (!ret)
+                    {
+                       ERR("xxxMakeCurrent() failed!");
+                       return 0;
+                    }
+               }
+          }
+#else
+        if ((glsym_glXGetCurrentContext() != ctx->context) ||
+            (glsym_glXGetCurrentDrawable() != re->win->win) )
+          {
+             // Flush remainder of what's in Evas' pipeline
+             if (re->win) eng_window_use(NULL);
+
+             // Do a make current
+             ret = glsym_glXMakeCurrent(re->info->info.display, re->win->win, ctx->context);
+             if (!ret) 
+               {
+                  ERR("xxxMakeCurrent() failed!");
+                  return 0;
+               }
+          }
+#endif
+
+        // Create FBO if not already created
+        if (!ctx->initialized)
+          {
+             glsym_glGenFramebuffers(1, &ctx->context_fbo);
+             ctx->initialized = 1;
+          }
 
-        sfc->fbo_attached = 1;
+        // 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;
+               }
+
+             if (ctx->current_fbo)
+                // Bind to the previously bound buffer
+                glsym_glBindFramebuffer(GL_FRAMEBUFFER, ctx->current_fbo);
+             else
+                // Bind FBO
+                glsym_glBindFramebuffer(GL_FRAMEBUFFER, ctx->context_fbo);
+
+             sfc->fbo_attached = 1;
+          }
      }
 
    // Set the current surface/context
@@ -3232,23 +3383,36 @@ eng_gl_proc_address_get(void *data __UNUSED__, const char *name)
 }
 
 static int
-eng_gl_native_surface_get(void *data, void *surface, void *native_surface)
+eng_gl_native_surface_get(void *data __UNUSED__, void *surface, void *native_surface)
 {
-   Render_Engine *re;
    Render_Engine_GL_Surface *sfc;
    Evas_Native_Surface *ns;
 
-   re  = (Render_Engine *)data;
    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;
 }
@@ -3268,22 +3432,27 @@ evgl_glBindFramebuffer(GLenum target, GLuint framebuffer)
 {
    Render_Engine_GL_Context *ctx = current_evgl_ctx;
 
+   if (!ctx)
+     {
+        ERR("Current context NULL.\n");
+        return;
+     }
+
    // Take care of BindFramebuffer 0 issue
    if (framebuffer==0)
      {
-        if (ctx)
-          {
-             glsym_glBindFramebuffer(target, ctx->context_fbo);
-             ctx->current_fbo = 0;
-          }
+        if (gl_direct_enabled)
+           glsym_glBindFramebuffer(target, 0);
+        else
+           glsym_glBindFramebuffer(target, ctx->context_fbo);
+        ctx->current_fbo = 0;
      }
    else
      {
         glsym_glBindFramebuffer(target, framebuffer);
 
         // Save this for restore when doing make current
-        if (ctx)
-           ctx->current_fbo = framebuffer;
+        ctx->current_fbo = framebuffer;
      }
 }
 
@@ -3295,6 +3464,225 @@ evgl_glBindRenderbuffer(GLenum target, GLuint renderbuffer)
    glsym_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])
+{
+   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);
+        glsym_glScissor(oc[0], oc[1], oc[2], oc[3]);
+        glsym_glClear(mask);
+     }
+   else
+      glsym_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;
+
+   glsym_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;
+   glsym_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;
+   glsym_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);
+        glsym_glReadPixels(nc[0], nc[1], nc[2], nc[3], format, type, pixels);
+     }
+   else
+      glsym_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);
+        glsym_glScissor(nc[0], nc[1], nc[2], nc[3]);
+        ctx->scissor_upated = 1;
+     }
+   else
+      glsym_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);
+        glsym_glEnable(GL_SCISSOR_TEST);
+        glsym_glScissor(oc[0], oc[1], oc[2], oc[3]);
+        glsym_glViewport(nc[0], nc[1], nc[2], nc[3]);
+     }
+   else
+      glsym_glViewport(x, y, width, height);
+
+}
+
+
+//----------------------------------------------//
+
 static void
 evgl_glClearDepthf(GLclampf depth)
 {
@@ -3331,7 +3719,9 @@ evgl_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint*
         precision[0] = 24; // floor(-log2((1.0/16777218.0)));
      }
    return;
+   /*
    shadertype = precisiontype = 0;
+   */
 #endif
 }
 
@@ -3372,7 +3762,10 @@ evgl_evasglCreateImage(int target, void* buffer, int *attrib_list)
                                     attrib_list);
      }
    else
-      ERR("Invalid Engine... (Can't acccess EGL Display)\n");
+     {
+        ERR("Invalid Engine... (Can't acccess EGL Display)\n");
+        return NULL;
+     }
 }
 
 static void
@@ -3425,8 +3818,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);
@@ -3448,11 +3841,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);
@@ -3506,7 +3899,7 @@ eng_gl_api_get(void *data)
 //   ORD(glReleaseShaderCompiler);
    ORD(glRenderbufferStorage);
    ORD(glSampleCoverage);
-   ORD(glScissor);
+//   ORD(glScissor);
 //   ORD(glShaderBinary);
    ORD(glShaderSource);
    ORD(glStencilFunc);
@@ -3551,7 +3944,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_)
@@ -3611,6 +4004,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);
@@ -3633,6 +4034,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)
 {
@@ -3771,6 +4190,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 */
@@ -3855,6 +4277,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 2381a8d..e1f4c2a 100644 (file)
@@ -1784,6 +1784,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,