Add new wayland_egl engine that does buffer age, double/triple
authorChris Michael <cp.michael@samsung.com>
Fri, 31 May 2013 07:39:15 +0000 (08:39 +0100)
committerChris Michael <cp.michael@samsung.com>
Fri, 31 May 2013 08:43:23 +0000 (09:43 +0100)
buffering, etc, and uses evas gl_common (so glview/simple tests in elm work).

Signed-off-by: Chris Michael <cp.michael@samsung.com>
src/modules/evas/engines/wayland_egl/evas_engine.c
src/modules/evas/engines/wayland_egl/evas_engine.h

index 3d8b881..ae4c037 100644 (file)
@@ -34,15 +34,22 @@ struct _Render_Engine
 
    Evas_GL_Wl_Window *win;
    Evas_Engine_Info_Wayland_Egl *info;
-   Evas *Evas;
+   Evas *evas;
 
-   int w, h;
-   int end, mode, vsync;
-   int lost_back, prev_age;
+   int w, h, mode, vsync, prev_age;
 
+   Eina_Bool lost_back : 1;
+   Eina_Bool end : 1;
    Eina_Bool evgl_initted : 1;
 };
 
+typedef struct _Native Native;
+struct _Native
+{
+   Evas_Native_Surface ns;
+   void *egl_surface;
+};
+
 /* local function prototypes */
 typedef void (*_eng_fn) (void);
 typedef _eng_fn (*glsym_func_eng_fn) ();
@@ -52,16 +59,58 @@ typedef int (*glsym_func_int) ();
 typedef unsigned int (*glsym_func_uint) ();
 typedef const char *(*glsym_func_const_char_ptr) ();
 
-static int evgl_init(Render_Engine *re);
+static Eina_Bool evgl_init(Render_Engine *re);
+static void evgl_symbols(void);
+static void evgl_extn_veto(Render_Engine *re);
+static void *evgl_eng_display_get(void *data);
+static void *evgl_eng_evas_surface_get(void *data);
+static int evgl_eng_make_current(void *data, void *surface, void *context, int flush);
+static void *evgl_eng_native_window_create(void *data);
+static int evgl_eng_native_window_destroy(void *data, void *native_window);
+static void *evgl_eng_window_surface_create(void *data, void *native_window);
+static int evgl_eng_window_surface_destroy(void *data, void *surface);
+static void *evgl_eng_context_create(void *data, void *share_context);
+static int evgl_eng_context_destroy(void *data, void *context);
+static const char *evgl_eng_string_get(void *data);
+static void *evgl_eng_proc_address_get(const char *name);
+static int evgl_eng_rotation_angle_get(void *data);
+
+static Eina_Bool _re_wincheck(Render_Engine *re);
+static void _re_winfree(Render_Engine *re);
+static Tilebuf_Rect *_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3);
+static void _native_bind_cb(void *data EINA_UNUSED, void *image);
+static void _native_unbind_cb(void *data EINA_UNUSED, void *image);
+static void _native_free_cb(void *data, void *image);
+
+static int eng_image_colorspace_get(void *data EINA_UNUSED, void *image);
+static int eng_image_alpha_get(void *data EINA_UNUSED, void *image);
+
 #define EVGLINIT(_re, _ret) if (!evgl_init(_re)) return _ret;
 
 /* local variables */
-static int initted = 0;
+static Eina_Bool initted = EINA_FALSE;
 static int gl_wins = 0;
-static int have_buffer_age = 1;
+static Eina_Bool extn_have_buffer_age = EINA_TRUE;
+static int safe_native = -1;
+static int partial_rect_union_mode = -1;
 
 /* function tables - filled in later (func and parent func) */
 static Evas_Func func, pfunc;
+static EVGL_Interface evgl_funcs = 
+{
+   evgl_eng_display_get,
+   evgl_eng_evas_surface_get,
+   evgl_eng_native_window_create,
+   evgl_eng_native_window_destroy,
+   evgl_eng_window_surface_create,
+   evgl_eng_window_surface_destroy,
+   evgl_eng_context_create,
+   evgl_eng_context_destroy,
+   evgl_eng_make_current,
+   evgl_eng_proc_address_get,
+   evgl_eng_string_get,
+   evgl_eng_rotation_angle_get
+};
 
 /* external variables */
 int _evas_engine_wl_egl_log_dom = -1;
@@ -83,11 +132,469 @@ void (*glsym_glEGLImageTargetTexture2DOES) (int a, void *b)  = NULL;
 void *(*glsym_eglMapImageSEC) (void *a, void *b, int c, int d) = NULL;
 unsigned int (*glsym_eglUnmapImageSEC) (void *a, void *b, int c) = NULL;
 const char *(*glsym_eglQueryString) (EGLDisplay a, int name) = NULL;
-void (*glsym_eglSwapBuffersRegion) (EGLDisplay a, void *b, EGLint c, const EGLint *d) = NULL;
+unsigned int (*glsym_eglSwapBuffersRegion) (EGLDisplay a, EGLSurface *b, EGLint c, const EGLint *d) = NULL;
 
 #endif
 
 /* local functions */
+static Eina_Bool 
+evgl_init(Render_Engine *re)
+{
+   if (!re) return EINA_FALSE;
+   if (re->evgl_initted) return EINA_TRUE;
+   if (!evgl_engine_init(re, &evgl_funcs)) return EINA_FALSE;
+   re->evgl_initted = EINA_TRUE;
+   return EINA_TRUE;
+}
+
+static void 
+evgl_symbols(void)
+{
+   static Eina_Bool done = EINA_FALSE;
+
+   if (done) return;
+
+#define FINDSYM(dst, sym, typ) \
+   if (glsym_eglGetProcAddress) { \
+      if (!dst) dst = (typ)glsym_eglGetProcAddress(sym); \
+   } \
+   if (!dst) dst = (typ)dlsym(RTLD_DEFAULT, sym);
+
+   FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressKHR", glsym_func_eng_fn);
+   FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressEXT", glsym_func_eng_fn);
+   FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddressARB", glsym_func_eng_fn);
+   FINDSYM(glsym_eglGetProcAddress, "eglGetProcAddress", glsym_func_eng_fn);
+
+   FINDSYM(glsym_eglCreateImage, "eglCreateImageKHR", glsym_func_void_ptr);
+   FINDSYM(glsym_eglCreateImage, "eglCreateImageEXT", glsym_func_void_ptr);
+   FINDSYM(glsym_eglCreateImage, "eglCreateImageARB", glsym_func_void_ptr);
+   FINDSYM(glsym_eglCreateImage, "eglCreateImage", glsym_func_void_ptr);
+
+   FINDSYM(glsym_eglDestroyImage, "eglDestroyImageKHR", glsym_func_void);
+   FINDSYM(glsym_eglDestroyImage, "eglDestroyImageEXT", glsym_func_void);
+   FINDSYM(glsym_eglDestroyImage, "eglDestroyImageARB", glsym_func_void);
+   FINDSYM(glsym_eglDestroyImage, "eglDestroyImage", glsym_func_void);
+
+   FINDSYM(glsym_glEGLImageTargetTexture2DOES, 
+           "glEGLImageTargetTexture2DOES", glsym_func_void);
+
+   FINDSYM(glsym_eglMapImageSEC, "eglMapImageSEC", glsym_func_void_ptr);
+   FINDSYM(glsym_eglUnmapImageSEC, "eglUnmapImageSEC", glsym_func_uint);
+
+   FINDSYM(glsym_eglQueryString, "eglQueryString", glsym_func_const_char_ptr);
+
+   FINDSYM(glsym_eglSwapBuffersRegion, 
+           "eglSwapBuffersRegionSEC", glsym_func_uint);
+   FINDSYM(glsym_eglSwapBuffersRegion, 
+           "eglSwapBuffersRegion", glsym_func_uint);
+
+   done = EINA_TRUE;
+}
+
+static void 
+evgl_extn_veto(Render_Engine *re)
+{
+   const char *str = NULL;
+
+   if ((!re) || (!re->win)) return;
+
+   if (glsym_eglQueryString)
+     str = glsym_eglQueryString(re->win->egl_disp, EGL_EXTENSIONS);
+   if (str)
+     {
+        if (getenv("EVAS_GL_INFO")) printf("EGL EXTENSION:\n%s\n", str);
+        if (!strstr(str, "EGL_EXT_buffer_age"))
+          extn_have_buffer_age = EINA_FALSE;
+     }
+   else
+     {
+        if (getenv("EVAS_GL_INFO")) printf("NO EGL EXTENSIONS !!\n");
+        extn_have_buffer_age = EINA_FALSE;
+     }
+}
+
+static void *
+evgl_eng_display_get(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   EVGLINIT(re, NULL);
+   if (re->win) return re->win->egl_disp;
+   return NULL;
+}
+
+static void *
+evgl_eng_evas_surface_get(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   EVGLINIT(re, NULL);
+   if (re->win) return re->win->egl_surface[0];
+   return NULL;
+}
+
+static int 
+evgl_eng_make_current(void *data, void *surface, void *context, int flush)
+{
+   Render_Engine *re;
+   EGLContext ctx;
+   EGLSurface sfc;
+   EGLDisplay dpy;
+   int ret = 0;
+
+   if (!(re = (Render_Engine *)data)) return 0;
+
+   EVGLINIT(re, 0);
+
+   dpy = re->win->egl_disp;
+   ctx = (EGLContext)context;
+   sfc = (EGLSurface)surface;
+
+   if ((!context) && (!surface))
+     {
+        ret = eglMakeCurrent(dpy, EGL_NO_SURFACE, 
+                             EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        if (!ret)
+          {
+             ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError());
+             return 0;
+          }
+
+        return 1;
+     }
+
+   if ((eglGetCurrentContext() != ctx) || 
+       (eglGetCurrentSurface(EGL_READ) != sfc) ||
+       (eglGetCurrentSurface(EGL_DRAW) != sfc) )
+     {
+
+        //!!!! Does it need to be flushed with it's set to NULL above??
+        // Flush remainder of what's in Evas' pipeline
+        if (flush) eng_window_use(NULL);
+
+        // Do a make current
+        ret = eglMakeCurrent(dpy, sfc, sfc, ctx);
+        if (!ret)
+          {
+             ERR("eglMakeCurrent() failed! Error Code=%#x", eglGetError());
+             return 0;
+          }
+     }
+
+   return 1;
+}
+
+static void *
+evgl_eng_native_window_create(void *data)
+{
+   Render_Engine *re;
+   struct wl_egl_window *win;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   if (!re->info) return NULL;
+
+   EVGLINIT(re, NULL);
+
+   win = wl_egl_window_create(re->info->info.surface, 1, 1);
+
+   return win;
+}
+
+static int 
+evgl_eng_native_window_destroy(void *data, void *native_window)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return 0;
+
+   EVGLINIT(re, 0);
+
+   wl_egl_window_destroy((struct wl_egl_window *)native_window);
+
+   return 1;
+}
+
+static void *
+evgl_eng_window_surface_create(void *data, void *native_window)
+{
+   Render_Engine *re;
+   EGLSurface surface = EGL_NO_SURFACE;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   EVGLINIT(re, NULL);
+
+   surface = 
+     eglCreateWindowSurface(re->win->egl_disp, re->win->egl_config,
+                            (EGLNativeWindowType)native_window, NULL);
+   if (!surface)
+     {
+        ERR("Creating window surface failed. Error: %#x.", eglGetError());
+        return NULL;
+     }
+
+   return surface;
+}
+
+static int 
+evgl_eng_window_surface_destroy(void *data, void *surface)
+{
+   Render_Engine *re;
+   EGLBoolean ret = EGL_FALSE;
+
+   if (!(re = (Render_Engine *)data)) return 0;
+   if (!surface) return 0;
+
+   ret = eglDestroySurface(re->win->egl_disp, (EGLSurface)surface);
+   if (ret == EGL_TRUE) return 1;
+
+   return 0;
+}
+
+static void *
+evgl_eng_context_create(void *data, void *share_context)
+{
+   Render_Engine *re;
+   EGLContext context = EGL_NO_CONTEXT;
+   int context_attrs[3];
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   EVGLINIT(re, NULL);
+
+   context_attrs[0] = EGL_CONTEXT_CLIENT_VERSION;
+   context_attrs[1] = 2;
+   context_attrs[2] = EGL_NONE;
+
+   // Share context already assumes that it's sharing with evas' context
+   if (share_context)
+     {
+        context = eglCreateContext(re->win->egl_disp, re->win->egl_config,
+                                   (EGLContext)share_context, context_attrs);
+     }
+   else
+     {
+        context = eglCreateContext(re->win->egl_disp, re->win->egl_config,
+                                   re->win->egl_context[0], context_attrs);
+     }
+
+   if (!context)
+     {
+        ERR("Engine Context Creations Failed. Error: %#x.", eglGetError());
+        return NULL;
+     }
+
+   return (void*)context;
+}
+
+static int 
+evgl_eng_context_destroy(void *data, void *context)
+{
+   Render_Engine *re;
+   EGLBoolean ret = EGL_FALSE;
+
+   if (!(re = (Render_Engine *)data)) return 0;
+
+   EVGLINIT(re, 0);
+
+   if (!context) return 0;
+
+   ret = eglDestroyContext(re->win->egl_disp, (EGLContext)context);
+   if (ret == EGL_TRUE) return 1;
+
+   return 0;
+}
+
+static const char *
+evgl_eng_string_get(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   EVGLINIT(re, NULL);
+
+   if (glsym_eglQueryString)
+     return glsym_eglQueryString(re->win->egl_disp, EGL_EXTENSIONS);
+
+   return "";
+}
+
+static void *
+evgl_eng_proc_address_get(const char *name)
+{
+   if (glsym_eglGetProcAddress) return glsym_eglGetProcAddress(name);
+   return dlsym(RTLD_DEFAULT, name);
+}
+
+static int 
+evgl_eng_rotation_angle_get(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return 0;
+
+   EVGLINIT(re, 0);
+
+   if ((re->win) && (re->win->gl_context))
+     return re->win->gl_context->rot;
+
+   return 0;
+}
+
+static Eina_Bool 
+_re_wincheck(Render_Engine *re)
+{
+   if (!re) return EINA_FALSE;
+   if (re->win)
+     {
+        if (re->win->surf) return EINA_TRUE;
+
+        eng_window_resurf(re->win);
+        re->lost_back = EINA_TRUE;
+
+        if (!re->win->surf)
+          ERR("EGL engine can't re-create window surface!");
+     }
+
+   return EINA_FALSE;
+}
+
+static void 
+_re_winfree(Render_Engine *re)
+{
+   if ((!re) || (!re->win)) return;
+   if (!re->win->surf) return;
+   eng_window_unsurf(re->win);
+}
+
+static Tilebuf_Rect *
+_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3)
+{
+   Tilebuf_Rect *r, *rects;
+   Evas_Point p1, p2;
+
+   if (r1)
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(r1), r)
+          evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
+     }
+   if (r2)
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(r2), r)
+          evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
+     }
+   if (r3)
+     {
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(r3), r)
+          evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h);
+     }
+
+   rects = evas_common_tilebuf_get_render_rects(tb);
+   
+   if (partial_rect_union_mode == -1)
+     {
+        const char *s;
+
+        if ((s = getenv("EVAS_GL_PARTIAL_MERGE")))
+          {
+             if ((!strcmp(s, "bounding")) || (!strcmp(s, "b")))
+               partial_rect_union_mode = MERGE_BOUNDING;
+             else if ((!strcmp(s, "full")) || (!strcmp(s, "f")))
+               partial_rect_union_mode = MERGE_FULL;
+          }
+        else
+          partial_rect_union_mode = MERGE_BOUNDING;
+     }
+
+   if (partial_rect_union_mode == MERGE_BOUNDING)
+     {
+// bounding box -> make a bounding box single region update of all regions.
+// yes we could try and be smart and figure out size of regions, how far
+// apart etc. etc. to try and figure out an optimal "set". this is a tradeoff
+// between multiple update regions to render and total pixels to render.
+        if (rects)
+          {
+             p1.x = rects->x; p1.y = rects->y;
+             p2.x = rects->x + rects->w; p2.y = rects->y + rects->h;
+             EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
+               {
+                  if (r->x < p1.x) p1.x = r->x;
+                  if (r->y < p1.y) p1.y = r->y;
+                  if ((r->x + r->w) > p2.x) p2.x = r->x + r->w;
+                  if ((r->y + r->h) > p2.y) p2.y = r->y + r->h;
+               }
+             evas_common_tilebuf_free_render_rects(rects);
+             rects = calloc(1, sizeof(Tilebuf_Rect));
+             if (rects)
+               {
+                  rects->x = p1.x;
+                  rects->y = p1.y;
+                  rects->w = p2.x - p1.x;
+                  rects->h = p2.y - p1.y;
+               }
+          }
+     }
+
+   evas_common_tilebuf_clear(tb);
+   return rects;
+}
+
+static void 
+_native_bind_cb(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+   Native *n;
+
+   if (!(im = image)) return;
+   if (!(n = im->native.data)) return;
+
+   if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
+     glBindTexture(GL_TEXTURE_2D, n->ns.data.opengl.texture_id);
+}
+
+static void 
+_native_unbind_cb(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+   Native *n;
+
+   if (!(im = image)) return;
+   if (!(n = im->native.data)) return;
+   if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
+     glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+static void 
+_native_free_cb(void *data, void *image)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im;
+   Native *n;
+   unsigned int texid;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (!(im = image)) return;
+   if (!(n = im->native.data)) return;
+
+   if (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL)
+     {
+        texid = n->ns.data.opengl.texture_id;
+        eina_hash_del(re->win->gl_context->shared->native_tex_hash, 
+                      &texid, im);
+     }
+
+   im->native.data = NULL;
+   im->native.func.data = NULL;
+   im->native.func.bind = NULL;
+   im->native.func.unbind = NULL;
+   im->native.func.free = NULL;
+   free(n);
+}
 
 /* engine specific override functions */
 static void *
@@ -120,6 +627,7 @@ eng_setup(Evas *evas, void *info)
    Evas_Engine_Info_Wayland_Egl *inf;
    Evas_Public_Data *epd;
    Render_Engine *re;
+   const char *s;
 
    inf = (Evas_Engine_Info_Wayland_Egl *)info;
    epd = eo_data_scope_get(evas, EVAS_CLASS);
@@ -138,9 +646,11 @@ eng_setup(Evas *evas, void *info)
         re->h = epd->output.h;
 
         /* try to create a new window */
-        re->win = eng_window_new(inf->display, inf->surface, inf->screen, 
-                                 inf->depth, re->w, re->h, inf->indirect, 
-                                 inf->destination_alpha, inf->rotation);
+        re->win = eng_window_new(inf->info.display, inf->info.surface, 
+                                 inf->info.screen, inf->info.depth, 
+                                 re->w, re->h, inf->indirect, 
+                                 inf->info.destination_alpha, 
+                                 inf->info.rotation);
         if (!re->win)
           {
              free(re);
@@ -154,7 +664,7 @@ eng_setup(Evas *evas, void *info)
         /* if we have not initialize gl & evas, do it */
         if (!initted)
           {
-             gl_symbols();
+             evgl_symbols();
              evas_common_cpu_init();
              evas_common_blend_init();
              evas_common_image_init();
@@ -166,8 +676,9 @@ eng_setup(Evas *evas, void *info)
              evas_common_font_init();
              evas_common_draw_init();
              evas_common_tilebuf_init();
-             gl_extn_veto(re);
-             initted = 1;
+             evgl_extn_veto(re);
+//             evgl_engine_init(re, &evgl_funcs);
+             initted = EINA_TRUE;
           }
      }
    else
@@ -183,30 +694,44 @@ eng_setup(Evas *evas, void *info)
                  (re->info->info.destination_alpha != re->win->alpha))
                {
                   Eina_Bool inc = EINA_FALSE;
+                  Evas_GL_Wl_Window *new_win = NULL;
 
-                  if (re->win)
+                  if ((re->win) && (re->win->surface) && 
+                      (re->info->info.surface = NULL))
                     {
-                       re->win->gl_context->references++;
                        eng_window_free(re->win);
-                       inc = EINA_TRUE;
                        gl_wins--;
+                       re->win = NULL;
+                       return 1;
                     }
 
-                  re->w = epd->output.w;
-                  re->h = epd->output.h;
-
-                  re->win = eng_window_new(re->info->info.display, 
+                  new_win = eng_window_new(re->info->info.display, 
                                            re->info->info.surface, 
                                            re->info->info.screen, 
                                            re->info->info.depth, 
-                                           re->w, re->h, 
-                                           re->info->info.indirect, 
+                                           epd->output.w, epd->output.h,
+                                           re->info->indirect, 
                                            re->info->info.destination_alpha, 
                                            re->info->info.rotation);
-                  eng_window_use(re->win);
-                  if (re->win) gl_wins++;
-                  if ((re->win) && (inc))
-                    re->win->gl_context->references--;
+                  if (new_win)
+                    {
+                       if (re->win)
+                         {
+                            re->win->gl_context->references++;
+                            eng_window_free(re->win);
+                            inc = EINA_TRUE;
+                            gl_wins--;
+                         }
+
+                       re->win = new_win;
+                       re->w = epd->output.w;
+                       re->h = epd->output.h;
+
+                       eng_window_use(re->win);
+                       if (re->win) gl_wins++;
+                       if ((re->win) && (inc))
+                         re->win->gl_context->references--;
+                    }
                }
              else if ((re->win->w != epd->output.w) || 
                       (re->win->h != epd->output.h))
@@ -250,7 +775,7 @@ eng_setup(Evas *evas, void *info)
 //        re->mode = MODE_TRIPLE;
 // XXX: note - the above seems to break on some older intel chipsets and
 // drivers. it seems we CANT depend on backbuffer staying around. bugger!
-        switch (info->swap_mode)
+        switch (inf->swap_mode)
           {
            case EVAS_ENGINE_WAYLAND_EGL_SWAP_MODE_FULL:
              re->mode = MODE_FULL;
@@ -272,6 +797,7 @@ eng_setup(Evas *evas, void *info)
    if (!re->win)
      {
         free(re);
+        epd->engine.data.output = NULL;
         return 0;
      }
 
@@ -283,6 +809,7 @@ eng_setup(Evas *evas, void *info)
              gl_wins--;
           }
         free(re);
+        epd->engine.data.output = NULL;
         return 0;
      }
 
@@ -295,6 +822,7 @@ eng_setup(Evas *evas, void *info)
              gl_wins--;
           }
         free(re);
+        epd->engine.data.output = NULL;
         return 0;
      }
 
@@ -314,24 +842,1642 @@ eng_setup(Evas *evas, void *info)
    return 1;
 }
 
-/* evas module functions */
-static int 
-module_open(Evas_Module *em)
+static Eina_Bool 
+eng_canvas_alpha_get(void *data, void *info EINA_UNUSED)
 {
-   /* check for valid module */
-   if (!em) return 0;
+   Render_Engine *re;
 
-   /* try to init evas_gl_common */
-   if (!evas_gl_common_module_open()) return 0;
+   if (!(re = (Render_Engine *)data)) 
+     return EINA_FALSE;
 
-   /* get whatever engine module we inherit from */
-   if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0;
+   if (re->win) 
+     return re->win->alpha;
+   else if (re->info) 
+     return re->info->info.destination_alpha;
 
-   /* setup logging domain */
-   if (_evas_engine_wl_egl_log_dom < 0)
+   return EINA_FALSE;
+}
+
+static void 
+eng_output_free(void *data)
+{
+   Render_Engine *re;
+
+   if ((re = (Render_Engine *)data))
      {
-        _evas_engine_wl_egl_log_dom = 
-          eina_log_domain_register("evas-wayland_egl", EVAS_DEFAULT_LOG_COLOR);
+        if (re->win)
+          {
+             eng_window_free(re->win);
+             gl_wins--;
+          }
+
+        evas_common_tilebuf_free(re->tb);
+        if (re->rects) 
+          evas_common_tilebuf_free_render_rects(re->rects);
+        if (re->rects_prev[0]) 
+          evas_common_tilebuf_free_render_rects(re->rects_prev[0]);
+        if (re->rects_prev[1]) 
+          evas_common_tilebuf_free_render_rects(re->rects_prev[1]);
+        if (re->rects_prev[2]) 
+          evas_common_tilebuf_free_render_rects(re->rects_prev[2]);
+
+        if (gl_wins == 0) evgl_engine_shutdown(re);
+        
+        free(re);
+     }
+
+   if ((initted) && (!gl_wins))
+     {
+        evas_common_image_shutdown();
+        evas_common_font_shutdown();
+        initted = EINA_FALSE;
+     }
+}
+
+static void 
+eng_output_resize(void *data, int w, int h)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+
+   if (re->win)
+     {
+        re->win->w = w;
+        re->win->h = h;
+        eng_window_use(re->win);
+     }
+
+   if (re->win->win)
+     {
+        int aw, ah, dx = 0, dy = 0;
+
+        if ((re->win->rot == 90) || (re->win->rot == 270))
+          wl_egl_window_get_attached_size(re->win->win, &ah, &aw);
+        else
+          wl_egl_window_get_attached_size(re->win->win, &aw, &ah);
+
+        if (re->info->info.edges & 4) // resize from left
+          {
+             if ((re->win->rot == 90) || (re->win->rot == 270))
+               dx = ah - h;
+             else
+               dx = aw - w;
+          }
+
+        if (re->info->info.edges & 1) // resize from top
+          {
+             if ((re->win->rot == 90) || (re->win->rot == 270))
+               dy = aw - w;
+             else
+               dy = ah - h;
+          }
+
+        if ((re->win->rot == 90) || (re->win->rot == 270))
+          wl_egl_window_resize(re->win->win, h, w, dx, dy);
+        else
+          wl_egl_window_resize(re->win->win, w, h, dx, dy);
+     }
+
+   if (re->win)
+     evas_gl_common_context_resize(re->win->gl_context, w, h, re->win->rot);
+
+   evas_common_tilebuf_free(re->tb);
+   if ((re->tb = evas_common_tilebuf_new(w, h)))
+     {
+        evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
+        evas_common_tilebuf_tile_strict_set(re->tb, EINA_TRUE);
+     }
+}
+
+static void 
+eng_output_tile_size_set(void *data, int w, int h)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_set_tile_size(re->tb, w, h);
+}
+
+static void 
+eng_output_redraws_rect_add(void *data, int x, int y, int w, int h)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->win)
+     {
+        eng_window_use(re->win);
+        evas_gl_common_context_resize(re->win->gl_context, 
+                                      re->win->w, re->win->h, re->win->rot);
+     }
+   if (re->tb) evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
+}
+
+static void 
+eng_output_redraws_rect_del(void *data, int x, int y, int w, int h)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
+}
+
+static void 
+eng_output_redraws_clear(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->tb) evas_common_tilebuf_clear(re->tb);
+}
+
+static void *
+eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch)
+{
+   Render_Engine *re;
+   Tilebuf_Rect *rect;
+   Eina_Bool first_rect = EINA_FALSE;
+
+#define CLEAR_PREV_RECTS(x) \
+   do { \
+      if (re->rects_prev[x]) \
+        evas_common_tilebuf_free_render_rects(re->rects_prev[x]); \
+      re->rects_prev[x] = NULL; \
+   } while (0)
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   if (re->end)
+     {
+        re->end = EINA_FALSE;
+        return NULL;
+     }
+
+   if (!re->rects)
+     {
+        re->rects = evas_common_tilebuf_get_render_rects(re->tb);
+        if (re->rects)
+          {
+             if (re->info->swap_mode == EVAS_ENGINE_WAYLAND_EGL_SWAP_MODE_AUTO)
+               {
+                  if (extn_have_buffer_age)
+                    {
+                       EGLint age = 0;
+
+                       if (!eglQuerySurface(re->win->egl_disp, 
+                                            re->win->egl_surface[0], 
+                                            EGL_BUFFER_AGE_EXT, &age))
+                         age = 0;
+
+                       if (age == 1) re->mode = MODE_COPY;
+                       else if (age == 2) re->mode = MODE_DOUBLE;
+                       else if (age == 3) re->mode = MODE_TRIPLE;
+                       else re->mode = MODE_FULL;
+                       if ((int)age != re->prev_age) re->mode = MODE_FULL;
+                       re->prev_age = age;
+                    }
+               }
+
+             /* NB: Disabled this OR for now as it causes some very strange things in the GLView/Simple tests */
+             if ((re->lost_back))// || (re->mode == MODE_FULL))
+               {
+                  re->lost_back = EINA_FALSE;
+                  evas_common_tilebuf_add_redraw(re->tb, 0, 0, 
+                                                 re->win->w, re->win->h);
+                  evas_common_tilebuf_free_render_rects(re->rects);
+                  re->rects = evas_common_tilebuf_get_render_rects(re->tb);
+               }
+
+             evas_common_tilebuf_clear(re->tb);
+             CLEAR_PREV_RECTS(2);
+             re->rects_prev[2] = re->rects_prev[1];
+             re->rects_prev[1] = re->rects_prev[0];
+             re->rects_prev[0] = re->rects;
+             re->rects = NULL;
+             switch (re->mode)
+               {
+                case MODE_FULL:
+                case MODE_COPY: // no prev rects needed
+                  re->rects = 
+                    _merge_rects(re->tb, re->rects_prev[0], NULL, NULL);
+                  break;
+                case MODE_DOUBLE: // double mode - only 1 level of prev rect
+                  re->rects = 
+                    _merge_rects(re->tb, re->rects_prev[0], 
+                                 re->rects_prev[1], NULL);
+                  break;
+                case MODE_TRIPLE: // keep all
+                  re->rects = 
+                    _merge_rects(re->tb, re->rects_prev[0], 
+                                 re->rects_prev[1], re->rects_prev[2]);
+                  break;
+                default:
+                  break;
+               }
+             first_rect = EINA_TRUE;
+          }
+        evas_common_tilebuf_clear(re->tb);
+        re->cur_rect = EINA_INLIST_GET(re->rects);
+     }
+
+   if (!re->cur_rect) return NULL;
+
+   rect = (Tilebuf_Rect *)re->cur_rect;
+   if (re->rects)
+     {
+        switch (re->mode)
+          {
+           case MODE_COPY:
+           case MODE_DOUBLE:
+           case MODE_TRIPLE:
+             rect = (Tilebuf_Rect *)re->cur_rect;
+             *x = rect->x;
+             *y = rect->y;
+             *w = rect->w;
+             *h = rect->h;
+             *cx = rect->x;
+             *cy = rect->y;
+             *cw = rect->w;
+             *ch = rect->h;
+             re->cur_rect = re->cur_rect->next;
+             re->win->gl_context->master_clip.enabled = EINA_TRUE;
+             re->win->gl_context->master_clip.x = rect->x;
+             re->win->gl_context->master_clip.y = rect->y;
+             re->win->gl_context->master_clip.w = rect->w;
+             re->win->gl_context->master_clip.h = rect->h;
+             break;
+           case MODE_FULL:
+             re->cur_rect = NULL;
+             if (x) *x = 0;
+             if (y) *y = 0;
+             if (w) *w = re->win->w;
+             if (h) *h = re->win->h;
+             if (cx) *cx = 0;
+             if (cy) *cy = 0;
+             if (cw) *cw = re->win->w;
+             if (ch) *ch = re->win->h;
+             re->win->gl_context->master_clip.enabled = EINA_FALSE;
+             break;
+           default:
+             break;
+          }
+
+        if (first_rect)
+          {
+             eng_window_use(re->win);
+             if (!_re_wincheck(re)) return NULL;
+             
+             evas_gl_common_context_flush(re->win->gl_context);
+             evas_gl_common_context_newframe(re->win->gl_context);
+          }
+
+        if (!re->cur_rect) re->end = EINA_TRUE;
+
+        return re->win->gl_context->def_surface;
+     }
+
+   return NULL;
+}
+
+static void 
+eng_output_redraws_next_update_push(void *data, void *surface EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, Evas_Render_Mode render_mode)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+
+   if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
+
+   if (!_re_wincheck(re)) return;
+
+   re->win->draw.drew = EINA_TRUE;
+   evas_gl_common_context_flush(re->win->gl_context);
+
+   if (safe_native == -1)
+     {
+        const char *s;
+
+        safe_native = 0;
+        if ((s = getenv("EVAS_GL_SAFE_NATIVE")))
+          safe_native = atoi(s);
+        else
+          {
+             if ((s = (const char *)glGetString(GL_RENDERER)))
+               {
+                  if (strstr(s, "PowerVR SGX 540") || strstr(s, "Mali-400 MP"))
+                    safe_native = 1;
+               }
+          }
+     }
+}
+
+static void 
+eng_output_flush(void *data, Evas_Render_Mode render_mode)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+
+   if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
+
+   if (!_re_wincheck(re)) return;
+
+   if (!re->win->draw.drew) return;
+   re->win->draw.drew = EINA_FALSE;
+   eng_window_use(re->win);
+
+   if (!re->vsync)
+     {
+        if (re->info->vsync) eglSwapInterval(re->win->egl_disp, 1);
+        else eglSwapInterval(re->win->egl_disp, 0);
+        re->vsync = 1;
+     }
+
+   if (re->info->callback.pre_swap)
+     re->info->callback.pre_swap(re->info->callback.data, re->evas);
+
+   if ((glsym_eglSwapBuffersRegion) && (re->mode != MODE_FULL))
+     {
+        EGLint num = 0, *rects = NULL, i = 0;
+        Tilebuf_Rect *r;
+        
+        // if partial swaps can be done use re->rects
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(re->rects), r) num++;
+        if (num > 0) rects = malloc(sizeof(EGLint) * 4 * num);
+        if (rects)
+          {
+             EINA_INLIST_FOREACH(EINA_INLIST_GET(re->rects), r)
+               {
+                  int gw, gh;
+                  
+                  gw = re->win->gl_context->w;
+                  gh = re->win->gl_context->h;
+                  switch (re->win->rot)
+                    {
+                     case 0:
+                       rects[i + 0] = r->x;
+                       rects[i + 1] = r->y;
+                       rects[i + 2] = r->w;
+                       rects[i + 3] = r->h;
+                       break;
+                     case 90:
+                       rects[i + 0] = r->y;
+                       rects[i + 1] = gh - (r->x + r->w);
+                       rects[i + 2] = r->h;
+                       rects[i + 3] = r->w;
+                       break;
+                     case 180:
+                       rects[i + 0] = gw - (r->x + r->w);
+                       rects[i + 1] = gh - (r->y + r->h);
+                       rects[i + 2] = r->w;
+                       rects[i + 3] = r->h;
+                       break;
+                     case 270:
+                       rects[i + 0] = gh - (r->y + r->h);
+                       rects[i + 1] = r->x;
+                       rects[i + 2] = r->h;
+                       rects[i + 3] = r->w;
+                       break;
+                     default:
+                       rects[i + 0] = r->x;
+                       rects[i + 1] = r->y;
+                       rects[i + 2] = r->w;
+                       rects[i + 3] = r->h;
+                       break;
+                    }
+                  i += 4;
+               }
+             glsym_eglSwapBuffersRegion(re->win->egl_disp,
+                                        re->win->egl_surface[0], num, rects);
+             free(rects);
+          }
+     }
+   else
+     eglSwapBuffers(re->win->egl_disp, re->win->egl_surface[0]);
+
+   if (re->info->callback.post_swap)
+     re->info->callback.post_swap(re->info->callback.data, re->evas);
+
+   if (re->rects)
+     {
+        evas_common_tilebuf_free_render_rects(re->rects);
+        re->rects = NULL;
+     }
+}
+
+static void 
+eng_output_idle_flush(void *data EINA_UNUSED)
+{
+
+}
+
+static void 
+eng_output_dump(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+
+   evas_common_image_image_all_unload();
+   evas_common_font_font_all_unload();
+   if (re->win) evas_gl_common_image_all_unload(re->win->gl_context);
+   _re_winfree(re);
+}
+
+static void 
+eng_context_cutout_add(void *data EINA_UNUSED, void *context, int x, int y, int w, int h)
+{
+   evas_common_draw_context_add_cutout(context, x, y, w, h);
+}
+
+static void 
+eng_context_cutout_clear(void *data EINA_UNUSED, void *context)
+{
+   evas_common_draw_context_clear_cutouts(context);
+}
+
+static void 
+eng_context_flush(void *data)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (re->win)
+     {
+        eng_window_use(re->win);
+        evas_gl_common_context_flush(re->win->gl_context);
+     }
+}
+
+static void *
+eng_gl_surface_create(void *data, void *config, int w, int h)
+{
+   Evas_GL_Config *cfg;
+
+   cfg = (Evas_GL_Config *)config;
+   EVGLINIT(data, NULL);
+   return evgl_surface_create(data, cfg, w, h);
+}
+
+static int 
+eng_gl_surface_destroy(void *data, void *surface)
+{
+   EVGL_Surface *sfc;
+
+   sfc = (EVGL_Surface *)surface;
+   EVGLINIT(data, 0);
+   return evgl_surface_destroy(data, sfc);
+}
+
+static void *
+eng_gl_context_create(void *data, void *share_context)
+{
+   EVGL_Context *sctx;
+
+   sctx = (EVGL_Context *)share_context;
+   EVGLINIT(data, NULL);
+   return evgl_context_create(data, sctx);
+}
+
+static int 
+eng_gl_context_destroy(void *data, void *context)
+{
+   EVGL_Context *sctx;
+
+   sctx = (EVGL_Context *)context;
+   EVGLINIT(data, 0);
+   return evgl_context_destroy(data, sctx);
+}
+
+static int 
+eng_gl_make_current(void *data, void *surface, void *context)
+{
+   EVGL_Surface *sfc;
+   EVGL_Context *ctx;
+
+   sfc = (EVGL_Surface *)surface;
+   ctx = (EVGL_Context *)context;
+   EVGLINIT(data, 0);
+   return evgl_make_current(data, sfc, ctx);
+}
+
+static void *
+eng_gl_string_query(void *data, int name)
+{
+   EVGLINIT(data, NULL);
+   return (void *)evgl_string_query(name);
+}
+
+// Need to deprecate this function..
+static void *
+eng_gl_proc_address_get(void *data EINA_UNUSED, const char *name EINA_UNUSED)
+{
+   return NULL;
+}
+
+static int 
+eng_gl_native_surface_get(void *data EINA_UNUSED, void *surface, void *native_surface)
+{
+   EVGL_Surface *sfc;
+   Evas_Native_Surface *ns;
+
+   sfc = (EVGL_Surface *)surface;
+   ns = (Evas_Native_Surface *)native_surface;
+   return evgl_native_surface_get(sfc, ns);
+}
+
+static void *
+eng_gl_api_get(void *data)
+{
+   EVGLINIT(data, NULL);
+   return evgl_api_get();
+}
+
+static void 
+eng_gl_img_obj_set(void *data, void *image, int has_alpha)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   EVGLINIT(data, );
+   evgl_direct_img_obj_set(image, has_alpha, re->win->gl_context->rot);
+}
+
+static void 
+eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h, Eina_Bool do_async EINA_UNUSED)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) 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_rect_draw(re->win->gl_context, x, y, w, h);
+}
+
+static void
+eng_line_draw(void *data, void *context, void *surface, int p1x, int p1y, int p2x, int p2y, Eina_Bool do_async EINA_UNUSED)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) 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_line_draw(re->win->gl_context, p1x, p1y, p2x, p2y);
+}
+
+static Eina_Bool
+eng_font_draw(void *data, void *context, void *surface, Evas_Font_Set *font EINA_UNUSED, int x, int y, int w EINA_UNUSED, int h EINA_UNUSED, int ow EINA_UNUSED, int oh EINA_UNUSED, Evas_Text_Props *intl_props, Eina_Bool do_async EINA_UNUSED)
+{
+   Render_Engine *re;
+   static RGBA_Image *im = NULL;
+
+   if (!(re = (Render_Engine *)data)) return EINA_FALSE;
+   eng_window_use(re->win);
+   evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
+   re->win->gl_context->dc = context;
+
+   // FIXME: put im into context so we can free it
+
+   if (!im)
+     im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
+
+   im->cache_entry.w = re->win->gl_context->shared->w;
+   im->cache_entry.h = re->win->gl_context->shared->h;
+
+   evas_common_draw_context_font_ext_set(context, re->win->gl_context,
+                                         evas_gl_font_texture_new,
+                                         evas_gl_font_texture_free,
+                                         evas_gl_font_texture_draw);
+   evas_common_font_draw_prepare(intl_props);
+   evas_common_font_draw(im, context, x, y, intl_props->glyphs);
+   evas_common_draw_context_font_ext_set(context, NULL, NULL, NULL, NULL);
+
+   return EINA_FALSE;
+}
+
+static void
+eng_polygon_draw(void *data, void *context, void *surface EINA_UNUSED, void *polygon, int x, int y, Eina_Bool do_async EINA_UNUSED)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) 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_poly_draw(re->win->gl_context, polygon, x, y);
+}
+
+static void *
+eng_polygon_point_add(void *data EINA_UNUSED, void *context EINA_UNUSED, void *polygon, int x, int y)
+{
+   return evas_gl_common_poly_point_add(polygon, x, y);
+}
+
+static void *
+eng_polygon_points_clear(void *data EINA_UNUSED, void *context EINA_UNUSED, void *polygon)
+{
+   return evas_gl_common_poly_points_clear(polygon);
+}
+
+static void *
+eng_image_load(void *data, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   *error = EVAS_LOAD_ERROR_NONE;
+   eng_window_use(re->win);
+   return evas_gl_common_image_load(re->win->gl_context, file, key, lo, error);
+}
+
+static void *
+eng_image_mmap(void *data, Eina_File *f, const char *key, int *error, Evas_Image_Load_Opts *lo)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   *error = EVAS_LOAD_ERROR_NONE;
+   eng_window_use(re->win);
+   return evas_gl_common_image_mmap(re->win->gl_context, f, key, lo, error);
+}
+
+static void *
+eng_image_new_from_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   eng_window_use(re->win);
+   return evas_gl_common_image_new_from_data(re->win->gl_context, w, h, image_data, alpha, cspace);
+}
+
+static void *
+eng_image_new_from_copied_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   eng_window_use(re->win);
+   return evas_gl_common_image_new_from_copied_data(re->win->gl_context, w, h, image_data, alpha, cspace);
+}
+
+static void
+eng_image_free(void *data, void *image)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (!image) return;
+   eng_window_use(re->win);
+   evas_gl_common_image_free(image);
+}
+
+static void
+eng_image_size_get(void *data EINA_UNUSED, void *image, int *w, int *h)
+{
+   if (!image)
+     {
+        *w = 0;
+        *h = 0;
+        return;
+     }
+   if (w) *w = ((Evas_GL_Image *)image)->w;
+   if (h) *h = ((Evas_GL_Image *)image)->h;
+}
+
+static void *
+eng_image_size_set(void *data, void *image, int w, int h)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im, *im_old;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   if (!(im = image)) return NULL;
+
+   if (im->native.data)
+     {
+        im->w = w;
+        im->h = h;
+        return image;
+     }
+   eng_window_use(re->win);
+   if ((im->tex) && (im->tex->pt->dyn.img))
+     {
+        evas_gl_common_texture_free(im->tex);
+        im->tex = NULL;
+        im->w = w;
+        im->h = h;
+        im->tex = evas_gl_common_texture_dynamic_new(im->gc, im);
+        return image;
+     }
+   im_old = image;
+
+   switch (eng_image_colorspace_get(data, image))
+     {
+      case EVAS_COLORSPACE_YCBCR422P601_PL:
+      case EVAS_COLORSPACE_YCBCR422P709_PL:
+      case EVAS_COLORSPACE_YCBCR422601_PL:
+      case EVAS_COLORSPACE_YCBCR420NV12601_PL:
+      case EVAS_COLORSPACE_YCBCR420TM12601_PL:
+         w &= ~0x1;
+         break;
+     }
+
+   if ((im_old->im) &&
+       ((int)im_old->im->cache_entry.w == w) &&
+       ((int)im_old->im->cache_entry.h == h))
+     return image;
+
+   if (im_old)
+     {
+        im = evas_gl_common_image_new(re->win->gl_context, w, h,
+                                      eng_image_alpha_get(data, image),
+                                      eng_image_colorspace_get(data, image));
+        evas_gl_common_image_free(im_old);
+     }
+   else
+     im = evas_gl_common_image_new(re->win->gl_context, w, h, 
+                                   1, EVAS_COLORSPACE_ARGB8888);
+   return im;
+}
+
+static void *
+eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   if (!(im = image)) return NULL;
+   if (im->native.data) return image;
+   eng_window_use(re->win);
+   evas_gl_common_image_dirty(image, x, y, w, h);
+   return image;
+}
+
+static void *
+eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, int *err)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im;
+   int error;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   if (!image)
+     {
+        *image_data = NULL;
+        if (err) *err = EVAS_LOAD_ERROR_GENERIC;
+        return NULL;
+     }
+   im = image;
+   if (im->native.data)
+     {
+        *image_data = NULL;
+        if (err) *err = EVAS_LOAD_ERROR_NONE;
+        return im;
+     }
+
+#ifdef GL_GLES
+   eng_window_use(re->win);
+
+   if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.img) && 
+       (im->cs.space == EVAS_COLORSPACE_ARGB8888))
+     {
+        if (im->tex->pt->dyn.checked_out > 0)
+          {
+             im->tex->pt->dyn.checked_out++;
+             *image_data = im->tex->pt->dyn.data;
+             if (err) *err = EVAS_LOAD_ERROR_NONE;
+             return im;
+          }
+        *image_data = im->tex->pt->dyn.data = 
+          glsym_eglMapImageSEC(re->win->egl_disp, 
+                               im->tex->pt->dyn.img, 
+                               EGL_MAP_GL_TEXTURE_DEVICE_CPU_SEC, 
+                               EGL_MAP_GL_TEXTURE_OPTION_WRITE_SEC);
+
+        if (!im->tex->pt->dyn.data)
+          {
+             if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+             GLERR(__FUNCTION__, __FILE__, __LINE__, "");
+             return im;
+          }
+        im->tex->pt->dyn.checked_out++;
+
+        if (err) *err = EVAS_LOAD_ERROR_NONE;
+        return im;
+     }
+#endif
+
+   /* Engine can be fail to create texture after cache drop like eng_image_content_hint_set function,
+        so it is need to add code which check im->im's NULL value*/
+
+   if (!im->im)
+    {
+       *image_data = NULL;
+       if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+       return NULL;
+    }
+
+   error = evas_cache_image_load_data(&im->im->cache_entry);
+   switch (im->cs.space)
+     {
+      case EVAS_COLORSPACE_ARGB8888:
+         if (to_write)
+           {
+              if (im->references > 1)
+                {
+                   Evas_GL_Image *im_new;
+
+                   im_new = evas_gl_common_image_new_from_copied_data
+                     (im->gc, im->im->cache_entry.w, im->im->cache_entry.h,
+                         im->im->image.data,
+                         eng_image_alpha_get(data, image),
+                         eng_image_colorspace_get(data, image));
+                   if (!im_new)
+                     {
+                        *image_data = NULL;
+                        if (err) 
+                          *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+                        return NULL;
+                     }
+                   evas_gl_common_image_free(im);
+                   im = im_new;
+                }
+              else
+                evas_gl_common_image_dirty(im, 0, 0, 0, 0);
+           }
+         *image_data = im->im->image.data;
+         break;
+      case EVAS_COLORSPACE_YCBCR422P601_PL:
+      case EVAS_COLORSPACE_YCBCR422P709_PL:
+      case EVAS_COLORSPACE_YCBCR422601_PL:
+      case EVAS_COLORSPACE_YCBCR420NV12601_PL:
+      case EVAS_COLORSPACE_YCBCR420TM12601_PL:
+         *image_data = im->cs.data;
+         break;
+      default:
+         abort();
+         break;
+     }
+   if (err) *err = error;
+   return im;
+}
+
+static void *
+eng_image_data_put(void *data, void *image, DATA32 *image_data)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im, *im2;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   if (!(im = image)) return NULL;
+   if (im->native.data) return image;
+   eng_window_use(re->win);
+   if ((im->tex) && (im->tex->pt)
+       && (im->tex->pt->dyn.data)
+       && (im->cs.space == EVAS_COLORSPACE_ARGB8888))
+     {
+        if (im->tex->pt->dyn.data == image_data)
+          {
+             if (im->tex->pt->dyn.checked_out > 0)
+               {
+                 im->tex->pt->dyn.checked_out--;
+#ifdef GL_GLES
+                 if (im->tex->pt->dyn.checked_out == 0)
+                   glsym_eglUnmapImageSEC(re->win->egl_disp, 
+                                          im->tex->pt->dyn.img, 
+                                          EGL_MAP_GL_TEXTURE_DEVICE_CPU_SEC);
+#endif
+               }
+
+             return image;
+          }
+        im2 = eng_image_new_from_data(data, im->w, im->h, image_data,
+                                      eng_image_alpha_get(data, image),
+                                      eng_image_colorspace_get(data, image));
+        if (!im2) return im;
+        evas_gl_common_image_free(im);
+        im = im2;
+        evas_gl_common_image_dirty(im, 0, 0, 0, 0);
+        return im;
+     }
+   switch (im->cs.space)
+     {
+      case EVAS_COLORSPACE_ARGB8888:
+         if ((!im->im) || (image_data != im->im->image.data))
+           {
+              im2 = eng_image_new_from_data(data, im->w, im->h, image_data,
+                                            eng_image_alpha_get(data, image),
+                                            eng_image_colorspace_get(data, image));
+              if (!im2) return im;
+              evas_gl_common_image_free(im);
+              im = im2;
+           }
+         break;
+      case EVAS_COLORSPACE_YCBCR422P601_PL:
+      case EVAS_COLORSPACE_YCBCR422P709_PL:
+      case EVAS_COLORSPACE_YCBCR422601_PL:
+      case EVAS_COLORSPACE_YCBCR420NV12601_PL:
+      case EVAS_COLORSPACE_YCBCR420TM12601_PL:
+         if (image_data != im->cs.data)
+           {
+              if (im->cs.data)
+                {
+                   if (!im->cs.no_free) free(im->cs.data);
+                }
+              im->cs.data = image_data;
+           }
+         evas_gl_common_image_dirty(im, 0, 0, 0, 0);
+         break;
+      default:
+         abort();
+         break;
+     }
+   return im;
+}
+
+static void
+eng_image_data_preload_request(void *data EINA_UNUSED, void *image, const void *target)
+{
+   Evas_GL_Image *gim;
+   RGBA_Image *im;
+
+   if (!(gim = image)) return;
+   if (gim->native.data) return;
+   im = (RGBA_Image *)gim->im;
+   if (!im) return;
+   evas_cache_image_preload_data(&im->cache_entry, target);
+}
+
+static void
+eng_image_data_preload_cancel(void *data EINA_UNUSED, void *image, const void *target)
+{
+   Evas_GL_Image *gim;
+   RGBA_Image *im;
+
+   if (!(gim = image)) return;
+   if (gim->native.data) return;
+   im = (RGBA_Image *)gim->im;
+   if (!im) return;
+   evas_cache_image_preload_cancel(&im->cache_entry, target);
+}
+
+static void *
+eng_image_alpha_set(void *data, void *image, int has_alpha)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   if (!(im = image)) return NULL;
+   if (im->alpha == has_alpha) return image;
+   if (im->native.data)
+     {
+        im->alpha = has_alpha;
+        return image;
+     }
+   eng_window_use(re->win);
+   if ((im->tex) && (im->tex->pt->dyn.img))
+     {
+        im->alpha = has_alpha;
+        im->tex->alpha = im->alpha;
+        return image;
+     }
+   /* FIXME: can move to gl_common */
+   if (im->cs.space != EVAS_COLORSPACE_ARGB8888) return im;
+   if ((has_alpha) && (im->im->cache_entry.flags.alpha)) return image;
+   else if ((!has_alpha) && (!im->im->cache_entry.flags.alpha)) return image;
+   if (im->references > 1)
+     {
+        Evas_GL_Image *im_new;
+
+        if (!im->im->image.data)
+          evas_cache_image_load_data(&im->im->cache_entry);
+        im_new = evas_gl_common_image_new_from_copied_data
+          (im->gc, im->im->cache_entry.w, im->im->cache_entry.h,
+              im->im->image.data,
+              eng_image_alpha_get(data, image),
+              eng_image_colorspace_get(data, image));
+        if (!im_new) return im;
+        evas_gl_common_image_free(im);
+        im = im_new;
+     }
+   else
+     evas_gl_common_image_dirty(im, 0, 0, 0, 0);
+   return evas_gl_common_image_alpha_set(im, has_alpha ? 1 : 0);
+//   im->im->cache_entry.flags.alpha = has_alpha ? 1 : 0;
+//   return image;
+}
+
+static int
+eng_image_alpha_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+
+   if (!(im = image)) return 1;
+   return im->alpha;
+}
+
+static void *
+eng_image_border_set(void *data EINA_UNUSED, void *image, int l EINA_UNUSED, int r EINA_UNUSED, int t EINA_UNUSED, int b EINA_UNUSED)
+{
+   return image;
+}
+
+static void
+eng_image_border_get(void *data EINA_UNUSED, void *image EINA_UNUSED, int *l EINA_UNUSED, int *r EINA_UNUSED, int *t EINA_UNUSED, int *b EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+eng_image_draw(void *data, void *context, void *surface, void *image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int smooth, Eina_Bool do_async EINA_UNUSED)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im;
+   Native *n;
+
+   if (!(re = (Render_Engine *)data)) return EINA_FALSE;
+   if (!(im = image)) return EINA_FALSE;
+   n = im->native.data;
+
+   if ((n) && (n->ns.type == EVAS_NATIVE_SURFACE_OPENGL) &&
+       (n->ns.data.opengl.framebuffer_id == 0) &&
+       (evgl_direct_rendered()))
+     {
+        DBG("Rendering Directly to the window: %p", data);
+        evas_object_image_pixels_dirty_set(evgl_direct_img_obj_get(), 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);
+     }
+
+   return EINA_FALSE;
+}
+
+static char *
+eng_image_comment_get(void *data EINA_UNUSED, void *image, char *key EINA_UNUSED)
+{
+   Evas_GL_Image *im;
+
+   if (!(im = image)) return NULL;
+   if (!im->im) return NULL;
+   return im->im->info.comment;
+}
+
+static char *
+eng_image_format_get(void *data EINA_UNUSED, void *image EINA_UNUSED)
+{
+   return NULL;
+}
+
+static void
+eng_image_colorspace_set(void *data, void *image, int cspace)
+{
+   Render_Engine *re;
+   Evas_GL_Image *im;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (!(im = image)) return;
+   if (im->native.data) return;
+   /* FIXME: can move to gl_common */
+   if (im->cs.space == cspace) return;
+   eng_window_use(re->win);
+   evas_cache_image_colorspace(&im->im->cache_entry, cspace);
+   switch (cspace)
+     {
+      case EVAS_COLORSPACE_ARGB8888:
+         if (im->cs.data)
+           {
+              if (!im->cs.no_free) free(im->cs.data);
+              im->cs.data = NULL;
+              im->cs.no_free = 0;
+           }
+         break;
+      case EVAS_COLORSPACE_YCBCR422P601_PL:
+      case EVAS_COLORSPACE_YCBCR422P709_PL:
+      case EVAS_COLORSPACE_YCBCR422601_PL:
+      case EVAS_COLORSPACE_YCBCR420NV12601_PL:
+      case EVAS_COLORSPACE_YCBCR420TM12601_PL:
+         if (im->tex) evas_gl_common_texture_free(im->tex);
+         im->tex = NULL;
+         if (im->cs.data)
+           {
+              if (!im->cs.no_free) free(im->cs.data);
+           }
+         if (im->im->cache_entry.h > 0)
+           im->cs.data =
+              calloc(1, im->im->cache_entry.h * sizeof(unsigned char *) * 2);
+         else
+           im->cs.data = NULL;
+         im->cs.no_free = 0;
+         break;
+      default:
+         abort();
+         break;
+     }
+   im->cs.space = cspace;
+}
+
+static int
+eng_image_colorspace_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+
+   if (!(im = image)) return EVAS_COLORSPACE_ARGB8888;
+   return im->cs.space;
+}
+
+static Eina_Bool
+eng_image_can_region_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return EINA_FALSE;
+   if (!(im = (Image_Entry *)gim->im)) return EINA_FALSE;
+   return ((Evas_Image_Load_Func*) im->info.loader)->do_region;
+}
+
+static void *
+eng_image_native_set(void *data, void *image, void *native)
+{
+   Render_Engine *re;
+   Evas_Native_Surface *ns;
+   Evas_GL_Image *im, *im2 = NULL;
+   Native *n = NULL;
+   unsigned int texid;
+   unsigned int tex = 0;
+   unsigned int fbo = 0;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+
+   ns = native;
+   im = image;
+   if (!im)
+     {
+        if ((ns) && (ns->type == EVAS_NATIVE_SURFACE_OPENGL))
+          {
+             im = evas_gl_common_image_new_from_data(re->win->gl_context,
+                                                     ns->data.opengl.w,
+                                                     ns->data.opengl.h,
+                                                     NULL, 1,
+                                                     EVAS_COLORSPACE_ARGB8888);
+          }
+        else
+          return NULL;
+     }
+
+   if (ns)
+     {
+        if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
+          {
+             tex = ns->data.opengl.texture_id;
+             fbo = ns->data.opengl.framebuffer_id;
+             if (im->native.data)
+               {
+                  Evas_Native_Surface *ens;
+
+                  ens = im->native.data;
+                  if ((ens->data.opengl.texture_id == tex) &&
+                      (ens->data.opengl.framebuffer_id == fbo))
+                    return im;
+               }
+          }
+     }
+
+   if ((!ns) && (!im->native.data)) return im;
+
+   eng_window_use(re->win);
+
+   if (im->native.data)
+     {
+        if (im->native.func.free)
+          im->native.func.free(im->native.func.data, im);
+        evas_gl_common_image_native_disable(im);
+     }
+
+   if (!ns) return im;
+
+   if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
+     {
+        texid = tex;
+        im2 = eina_hash_find(re->win->gl_context->shared->native_tex_hash, &texid);
+        if (im2 == im) return im;
+        if (im2)
+          {
+             n = im2->native.data;
+             if (n)
+               {
+                  evas_gl_common_image_ref(im2);
+                  evas_gl_common_image_free(im);
+                  return im2;
+               }
+          }
+     }
+
+   im2 = evas_gl_common_image_new_from_data(re->win->gl_context,
+                                            im->w, im->h, NULL, im->alpha,
+                                            EVAS_COLORSPACE_ARGB8888);
+   evas_gl_common_image_free(im);
+   if (!(im = im2)) return NULL;
+
+   if (ns->type == EVAS_NATIVE_SURFACE_OPENGL)
+     {
+        if (native)
+          {
+             n = calloc(1, sizeof(Native));
+             if (n)
+               {
+                  memcpy(&(n->ns), ns, sizeof(Evas_Native_Surface));
+
+                  eina_hash_add(re->win->gl_context->shared->native_tex_hash, 
+                                &texid, im);
+
+                  n->egl_surface = 0;
+                  im->native.yinvert = 0;
+                  im->native.loose = 0;
+                  im->native.data = n;
+                  im->native.func.data = re;
+                  im->native.func.bind = _native_bind_cb;
+                  im->native.func.unbind = _native_unbind_cb;
+                  im->native.func.free = _native_free_cb;
+                  im->native.target = GL_TEXTURE_2D;
+                  im->native.mipmap = 0;
+
+                  // FIXME: need to implement mapping sub texture regions
+                  // x, y, w, h for possible texture atlasing
+
+                  evas_gl_common_image_native_enable(im);
+               }
+          }
+    }
+
+   return im;
+}
+
+static void *
+eng_image_native_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+   Native *n;
+
+   if (!(im = image)) return NULL;
+   if (!(n = im->native.data)) return NULL;
+   return &(n->ns);
+}
+
+static void
+eng_image_scale_hint_set(void *data EINA_UNUSED, void *image, int hint)
+{
+   if (image) evas_gl_common_image_scale_hint_set(image, hint);
+}
+
+static int
+eng_image_scale_hint_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+
+   if (!(gim = image)) return EVAS_IMAGE_SCALE_HINT_NONE;
+   return gim->scale_hint;
+}
+
+static void
+eng_image_stride_get(void *data EINA_UNUSED, void *image, int *stride)
+{
+   Evas_GL_Image *im;
+
+   if (!(im = image)) return;
+   if ((im->tex) && (im->tex->pt->dyn.img))
+     {
+        if (stride) *stride = im->tex->pt->dyn.stride;
+     }
+   else
+     {
+        if (stride) *stride = im->w * 4;
+     }
+}
+
+static void
+eng_image_content_hint_set(void *data EINA_UNUSED, void *image, int hint)
+{
+   if (image) evas_gl_common_image_content_hint_set(image, hint);
+}
+
+static int
+eng_image_content_hint_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+
+   if (!(gim = image)) return EVAS_IMAGE_CONTENT_HINT_NONE;
+   return gim->content_hint;
+}
+
+static void
+eng_image_cache_flush(void *data)
+{
+   Render_Engine *re;
+   int tmp_size;
+
+   if (!(re = (Render_Engine *)data)) return;
+
+   tmp_size = evas_common_image_get_cache();
+   evas_common_image_set_cache(0);
+   evas_common_rgba_image_scalecache_flush();
+   evas_gl_common_image_cache_flush(re->win->gl_context);
+   evas_common_image_set_cache(tmp_size);
+}
+
+static void
+eng_image_cache_set(void *data, int bytes)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   evas_common_image_set_cache(bytes);
+   evas_common_rgba_image_scalecache_size_set(bytes);
+   evas_gl_common_image_cache_flush(re->win->gl_context);
+}
+
+static int
+eng_image_cache_get(void *data EINA_UNUSED)
+{
+   return evas_common_image_get_cache();
+}
+
+static int
+eng_image_load_error_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+
+   if (!(im = image)) return EVAS_LOAD_ERROR_NONE;
+   return im->im->cache_entry.load_error;
+}
+
+static void
+eng_image_max_size_get(void *data, int *maxw, int *maxh)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return;
+   if (maxw) *maxw = re->win->gl_context->shared->info.max_texture_size;
+   if (maxh) *maxh = re->win->gl_context->shared->info.max_texture_size;
+}
+
+static Eina_Bool
+eng_image_map_draw(void *data, void *context, void *surface, void *image, RGBA_Map *m, int smooth, int level, Eina_Bool do_async)
+{
+   Evas_GL_Image *gim;
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return EINA_FALSE;
+   if (!(gim = image)) return EINA_FALSE;
+   eng_window_use(re->win);
+   evas_gl_common_context_target_surface_set(re->win->gl_context, surface);
+   re->win->gl_context->dc = context;
+   if (m->count != 4)
+     {
+        // FIXME: nash - you didn't fix this
+        abort();
+     }
+   if ((m->pts[0].x == m->pts[3].x) &&
+       (m->pts[1].x == m->pts[2].x) &&
+       (m->pts[0].y == m->pts[1].y) &&
+       (m->pts[3].y == m->pts[2].y) &&
+       (m->pts[0].x <= m->pts[1].x) &&
+       (m->pts[0].y <= m->pts[2].y) &&
+       (m->pts[0].u == 0) &&
+       (m->pts[0].v == 0) &&
+       (m->pts[1].u == (gim->w << FP)) &&
+       (m->pts[1].v == 0) &&
+       (m->pts[2].u == (gim->w << FP)) &&
+       (m->pts[2].v == (gim->h << FP)) &&
+       (m->pts[3].u == 0) &&
+       (m->pts[3].v == (gim->h << FP)) &&
+       (m->pts[0].col == 0xffffffff) &&
+       (m->pts[1].col == 0xffffffff) &&
+       (m->pts[2].col == 0xffffffff) &&
+       (m->pts[3].col == 0xffffffff))
+     {
+        int dx, dy, dw, dh;
+
+        dx = m->pts[0].x >> FP;
+        dy = m->pts[0].y >> FP;
+        dw = (m->pts[2].x >> FP) - dx;
+        dh = (m->pts[2].y >> FP) - dy;
+        eng_image_draw(data, context, surface, image,
+                       0, 0, gim->w, gim->h, dx, dy, dw, dh, smooth, do_async);
+     }
+   else
+     evas_gl_common_image_map_draw(re->win->gl_context, image, m->count, 
+                                   &m->pts[0], smooth, level);
+
+   return EINA_FALSE;
+}
+
+static void *
+eng_image_map_surface_new(void *data, int w, int h, int alpha)
+{
+   Render_Engine *re;
+
+   if (!(re = (Render_Engine *)data)) return NULL;
+   return evas_gl_common_image_surface_new(re->win->gl_context, w, h, alpha);
+}
+
+static void
+eng_image_map_surface_free(void *data EINA_UNUSED, void *surface)
+{
+   evas_gl_common_image_free(surface);
+}
+
+static void
+eng_image_map_clean(void *data EINA_UNUSED, RGBA_Map *m EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+eng_image_animated_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return EINA_FALSE;
+   if (!(im = (Image_Entry *)gim->im)) return EINA_FALSE;
+   return im->animated.animated;
+}
+
+static int
+eng_image_animated_frame_count_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return -1;
+   if (!(im = (Image_Entry *)gim->im)) return -1;
+   if (!im->animated.animated) return -1;
+   return im->animated.frame_count;
+}
+
+static Evas_Image_Animated_Loop_Hint
+eng_image_animated_loop_type_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return EVAS_IMAGE_ANIMATED_HINT_NONE;
+   if (!(im = (Image_Entry *)gim->im)) return EVAS_IMAGE_ANIMATED_HINT_NONE;
+   if (!im->animated.animated) return EVAS_IMAGE_ANIMATED_HINT_NONE;
+   return im->animated.loop_hint;
+}
+
+static int
+eng_image_animated_loop_count_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return -1;
+   if (!(im = (Image_Entry *)gim->im)) return -1;
+   if (!im->animated.animated) return -1;
+   return im->animated.loop_count;
+}
+
+static double
+eng_image_animated_frame_duration_get(void *data EINA_UNUSED, void *image, int start_frame, int frame_num)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return -1;
+   if (!(im = (Image_Entry *)gim->im)) return -1;
+   if (!im->animated.animated) return -1;
+   return evas_common_load_rgba_image_frame_duration_from_file(im, start_frame, frame_num);
+}
+
+static Eina_Bool
+eng_image_animated_frame_set(void *data EINA_UNUSED, void *image, int frame_index)
+{
+   Evas_GL_Image *gim;
+   Image_Entry *im;
+
+   if (!(gim = image)) return EINA_FALSE;
+   if (!(im = (Image_Entry *)gim->im)) return EINA_FALSE;
+   if (!im->animated.animated) return EINA_FALSE;
+   if (im->animated.cur_frame == frame_index) return EINA_FALSE;
+
+   im->animated.cur_frame = frame_index;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+eng_pixel_alpha_get(void *image, int x, int y, DATA8 *alpha, int src_region_x, int src_region_y, int src_region_w, int src_region_h, int dst_region_x, int dst_region_y, int dst_region_w, int dst_region_h)
+{
+   Evas_GL_Image *im;
+   int px, py, dx, dy, sx, sy, src_w, src_h;
+   double scale_w, scale_h;
+
+   if (!(im = image)) return EINA_FALSE;
+
+   if ((dst_region_x > x) || (x >= (dst_region_x + dst_region_w)) ||
+       (dst_region_y > y) || (y >= (dst_region_y + dst_region_h)))
+     {
+        *alpha = 0;
+        return EINA_FALSE;
+     }
+
+   src_w = im->im->cache_entry.w;
+   src_h = im->im->cache_entry.h;
+   if ((src_w == 0) || (src_h == 0))
+     {
+        *alpha = 0;
+        return EINA_TRUE;
+     }
+
+   EINA_SAFETY_ON_TRUE_GOTO(src_region_x < 0, error_oob);
+   EINA_SAFETY_ON_TRUE_GOTO(src_region_y < 0, error_oob);
+   EINA_SAFETY_ON_TRUE_GOTO(src_region_x + src_region_w > src_w, error_oob);
+   EINA_SAFETY_ON_TRUE_GOTO(src_region_y + src_region_h > src_h, error_oob);
+
+   scale_w = (double)dst_region_w / (double)src_region_w;
+   scale_h = (double)dst_region_h / (double)src_region_h;
+
+   /* point at destination */
+   dx = x - dst_region_x;
+   dy = y - dst_region_y;
+
+   /* point at source */
+   sx = dx / scale_w;
+   sy = dy / scale_h;
+
+   /* pixel point (translated) */
+   px = src_region_x + sx;
+   py = src_region_y + sy;
+   EINA_SAFETY_ON_TRUE_GOTO(px >= src_w, error_oob);
+   EINA_SAFETY_ON_TRUE_GOTO(py >= src_h, error_oob);
+
+   switch (im->im->cache_entry.space)
+     {
+      case EVAS_COLORSPACE_ARGB8888:
+          {
+             DATA32 *pixel;
+
+             evas_cache_image_load_data(&im->im->cache_entry);
+             if (!im->im->cache_entry.flags.loaded)
+               {
+                  ERR("im %p has no pixels loaded yet", im);
+                  return EINA_FALSE;
+               }
+
+             pixel = im->im->image.data;
+             pixel += ((py * src_w) + px);
+             *alpha = ((*pixel) >> 24) & 0xff;
+          }
+        break;
+
+      default:
+        ERR("Colorspace %d not supported.", im->im->cache_entry.space);
+        *alpha = 0;
+     }
+
+   return EINA_TRUE;
+
+error_oob:
+   ERR("Invalid region src=(%d, %d, %d, %d), dst=(%d, %d, %d, %d), image=%dx%d",
+       src_region_x, src_region_y, src_region_w, src_region_h,
+       dst_region_x, dst_region_y, dst_region_w, dst_region_h,
+       src_w, src_h);
+   *alpha = 0;
+   return EINA_TRUE;
+}
+
+/* evas module functions */
+static int 
+module_open(Evas_Module *em)
+{
+   /* check for valid module */
+   if (!em) return 0;
+
+   /* try to init evas_gl_common */
+   if (!evas_gl_common_module_open()) return 0;
+
+   /* get whatever engine module we inherit from */
+   if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0;
+
+   /* setup logging domain */
+   if (_evas_engine_wl_egl_log_dom < 0)
+     {
+        _evas_engine_wl_egl_log_dom = 
+          eina_log_domain_register("evas-wayland_egl", EVAS_DEFAULT_LOG_COLOR);
      }
 
    if (_evas_engine_wl_egl_log_dom < 0)
@@ -348,6 +2494,91 @@ module_open(Evas_Module *em)
    ORD(info);
    ORD(info_free);
    ORD(setup);
+   ORD(canvas_alpha_get);
+
+   ORD(output_free);
+   ORD(output_resize);
+   ORD(output_tile_size_set);
+   ORD(output_redraws_rect_add);
+   ORD(output_redraws_rect_del);
+   ORD(output_redraws_clear);
+   ORD(output_redraws_next_update_get);
+   ORD(output_redraws_next_update_push);
+   ORD(output_flush);
+   ORD(output_idle_flush);
+   ORD(output_dump);
+
+   ORD(context_cutout_add);
+   ORD(context_cutout_clear);
+   ORD(context_flush);
+
+   ORD(gl_surface_create);
+   ORD(gl_surface_destroy);
+   ORD(gl_context_create);
+   ORD(gl_context_destroy);
+   ORD(gl_make_current);
+   ORD(gl_string_query);
+   ORD(gl_proc_address_get);
+   ORD(gl_native_surface_get);
+   ORD(gl_api_get);
+   ORD(gl_img_obj_set);
+
+   ORD(rectangle_draw);
+   ORD(line_draw);
+   ORD(font_draw);
+
+   ORD(polygon_draw);
+   ORD(polygon_point_add);
+   ORD(polygon_points_clear);
+
+   ORD(image_load);
+   ORD(image_mmap);
+   ORD(image_new_from_data);
+   ORD(image_new_from_copied_data);
+   ORD(image_free);
+   ORD(image_size_get);
+   ORD(image_size_set);
+   ORD(image_dirty_region);
+   ORD(image_data_get);
+   ORD(image_data_put);
+   ORD(image_data_preload_request);
+   ORD(image_data_preload_cancel);
+   ORD(image_alpha_set);
+   ORD(image_alpha_get);
+   ORD(image_border_set);
+   ORD(image_border_get);
+   ORD(image_draw);
+   ORD(image_comment_get);
+   ORD(image_format_get);
+   ORD(image_colorspace_set);
+   ORD(image_colorspace_get);
+   ORD(image_can_region_get);
+   ORD(image_native_set);
+   ORD(image_native_get);
+   ORD(image_scale_hint_set);
+   ORD(image_scale_hint_get);
+   ORD(image_stride_get);
+   ORD(image_content_hint_set);
+   ORD(image_content_hint_get);
+   ORD(image_cache_flush);
+   ORD(image_cache_set);
+   ORD(image_cache_get);
+   ORD(image_load_error_get);
+   ORD(image_max_size_get);
+
+   ORD(image_map_draw);
+   ORD(image_map_surface_new);
+   ORD(image_map_surface_free);
+   ORD(image_map_clean);
+
+   ORD(image_animated_get);
+   ORD(image_animated_frame_count_get);
+   ORD(image_animated_loop_type_get);
+   ORD(image_animated_loop_count_get);
+   ORD(image_animated_frame_duration_get);
+   ORD(image_animated_frame_set);
+
+   ORD(pixel_alpha_get);
 
    /* advertise out which functions we support */
    em->functions = (void *)(&func);
index 1b133ca..ea54090 100644 (file)
@@ -2,23 +2,25 @@
 # define EVAS_ENGINE_H
 
 # include "config.h"
-# include "evas_common.h"
-# include "evas_private.h"
-# include "evas_gl_common.h"
-# include "Evas.h"
-# include "Evas_Engine_Wayland_Egl.h"
-
-# define GL_GLEXT_PROTOTYPES
 
 /* NB: This already includes wayland-client.h */
 # include <wayland-egl.h>
 
 # ifdef GL_GLES
 #  include <EGL/egl.h>
-#  include <GLES2/gl2.h>
-#  include <GLES2/gl2ext.h>
+/* NB: These are already included from gl_common */
+/* #  include <GLES2/gl2.h> */
+/* #  include <GLES2/gl2ext.h> */
 # endif
 
+# include "evas_common.h"
+# include "evas_private.h"
+# include "evas_gl_common.h"
+# include "Evas.h"
+# include "Evas_Engine_Wayland_Egl.h"
+
+# define GL_GLEXT_PROTOTYPES
+
 extern int _evas_engine_wl_egl_log_dom;
 
 # ifdef ERR
@@ -60,7 +62,7 @@ struct _Evas_GL_Wl_Window
 
    struct 
      {
-        int drew : 1;
+        Eina_Bool drew : 1;
      } draw;
 
 #ifdef GL_GLES
@@ -70,7 +72,7 @@ struct _Evas_GL_Wl_Window
    EGLDisplay egl_disp;
 #endif
 
-   int surf : 1;
+   Eina_Bool surf : 1;
 };
 
 Evas_GL_Wl_Window *eng_window_new(struct wl_display *disp, struct wl_surface *surface, int screen, int depth, int w, int h, int indirect, int alpha, int rot);