evas-wayland-shm: Refactor Evas Wayland Shm Engine (Fix T2201)
authorChris Michael <cp.michael@samsung.com>
Tue, 17 Mar 2015 19:49:09 +0000 (15:49 -0400)
committerChris Michael <cp.michael@samsung.com>
Tue, 17 Mar 2015 19:49:09 +0000 (15:49 -0400)
Summary: This patch set fixes the issue of Evas wayland shm engine
causing crashes when resizing efl apps in the E wayland compositor. It
refactors the evas engine to wait for release events on buffers, and
hooks into frame callbacks so that release events will get triggered
at the appropriate time.

@fix

Signed-off-by: Chris Michael <cp.michael@samsung.com>
src/Makefile_Evas.am
src/modules/evas/engines/wayland_shm/evas_engine.c
src/modules/evas/engines/wayland_shm/evas_engine.h
src/modules/evas/engines/wayland_shm/evas_outbuf.c [new file with mode: 0644]
src/modules/evas/engines/wayland_shm/evas_shm.c [new file with mode: 0644]

index cb79b49..af00028 100644 (file)
@@ -1179,10 +1179,8 @@ WAYLAND_SHM_SOURCES = \
 modules/evas/engines/wayland_shm/Evas_Engine_Wayland_Shm.h \
 modules/evas/engines/wayland_shm/evas_engine.c \
 modules/evas/engines/wayland_shm/evas_engine.h \
-modules/evas/engines/wayland_shm/evas_swapbuf.c \
-modules/evas/engines/wayland_shm/evas_swapbuf.h \
-modules/evas/engines/wayland_shm/evas_swapper.c \
-modules/evas/engines/wayland_shm/evas_swapper.h
+modules/evas/engines/wayland_shm/evas_shm.c \
+modules/evas/engines/wayland_shm/evas_outbuf.c
 if EVAS_STATIC_BUILD_WAYLAND_SHM
 lib_evas_libevas_la_SOURCES += $(WAYLAND_SHM_SOURCES)
 lib_evas_libevas_la_CPPFLAGS += @evas_engine_wayland_shm_cflags@
index 21f4ef3..fd97de6 100644 (file)
 #include "evas_common_private.h"
 #include "evas_private.h"
-#include "Evas_Engine_Wayland_Shm.h"
+#ifdef EVAS_CSERVE2
+# include "evas_cs2_private.h"
+#endif
+
 #include "evas_engine.h"
-#include "evas_swapbuf.h"
 
-/* local structures */
-typedef struct _Render_Engine Render_Engine;
+/* logging domain variable */
+int _evas_engine_way_shm_log_dom = -1;
 
+/* evas function tables - filled in later (func and parent func) */
+static Evas_Func func, pfunc;
+
+/* engine structure data */
+typedef struct _Render_Engine Render_Engine;
 struct _Render_Engine
 {
    Render_Engine_Software_Generic generic;
 
-   void (*outbuf_reconfigure)(Outbuf *ob, int x, int y, int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha);
+   void (*outbuf_reconfigure)(Outbuf *ob, int x, int y, int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, Eina_Bool resize);
 };
 
-/* engine function prototypes */
-static void *eng_info(Evas *eo_evas EINA_UNUSED);
-static void eng_info_free(Evas *eo_evas EINA_UNUSED, void *einfo);
-static int eng_setup(Evas *eo_evas, void *einfo);
-static void eng_output_free(void *data);
-
-/* local variables */
-static Evas_Func func, pfunc;
-
-/* external variables */
-int _evas_engine_way_shm_log_dom = -1;
-
-/* local functions */
-static void *
-_output_engine_setup(Evas_Engine_Info_Wayland_Shm *info,
-                     int w, int h,
-                     unsigned int rotation, unsigned int depth,
-                     Eina_Bool destination_alpha,
-                     struct wl_shm *wl_shm,
-                     struct wl_surface *wl_surface)
+/* LOCAL FUNCTIONS */
+Render_Engine *
+_render_engine_swapbuf_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha, struct wl_shm *shm, struct wl_surface *surface)
 {
-   Render_Engine *re = NULL;
+   Render_Engine *re;
    Outbuf *ob;
 
    LOGFN(__FILE__, __LINE__, __FUNCTION__);
 
-   /* try to allocate a new render engine */
-   if (!(re = calloc(1, sizeof(Render_Engine))))
-     return NULL;
-
+   /* try to allocate space for new render engine */
+   if (!(re = calloc(1, sizeof(Render_Engine)))) return NULL;
 
-   ob = evas_swapbuf_setup(info, w, h, rotation, depth,
-                           destination_alpha, wl_shm,
-                           wl_surface);
-   if (!ob) goto on_error;
+   ob = _evas_outbuf_setup(w, h, rotation, depth, alpha, shm, surface);
+   if (!ob) goto err;
 
-   if (!evas_render_engine_software_generic_init(&re->generic, ob,
-                                                 evas_swapbuf_state_get,
-                                                 evas_swapbuf_rotation_get,
-                                                 NULL,
+   if (!evas_render_engine_software_generic_init(&re->generic, ob, 
+                                                 _evas_outbuf_swapmode_get,
+                                                 _evas_outbuf_rotation_get,
                                                  NULL,
-                                                 evas_swapbuf_update_region_new,
-                                                 evas_swapbuf_update_region_push,
-                                                 evas_swapbuf_update_region_free,
-                                                 evas_swapbuf_idle_flush,
-                                                 evas_swapbuf_flush,
-                                                 evas_swapbuf_free,
+                                                 NULL, 
+                                                 _evas_outbuf_update_region_new,
+                                                 _evas_outbuf_update_region_push,
+                                                 _evas_outbuf_update_region_free,
+                                                 _evas_outbuf_idle_flush,
+                                                 _evas_outbuf_flush,
+                                                 _evas_outbuf_free,
                                                  w, h))
-     goto on_error;
+     goto err;
 
-   re->outbuf_reconfigure = evas_swapbuf_reconfigure;
+   re->outbuf_reconfigure = _evas_outbuf_reconfigure;
 
    /* return allocated render engine */
    return re;
 
- on_error:
-   if (ob) evas_swapbuf_free(ob);
+err:
+   if (ob) _evas_outbuf_free(ob);
    free(re);
    return NULL;
 }
 
-/* engine functions */
+/* ENGINE API FUNCTIONS WE PROVIDE */
 static void *
 eng_info(Evas *eo_evas EINA_UNUSED)
 {
-   Evas_Engine_Info_Wayland_Shm *info;
+   Evas_Engine_Info_Wayland_Shm *einfo;
 
-   /* try to allocate space for engine info */
-   if (!(info = calloc(1, sizeof(Evas_Engine_Info_Wayland_Shm))))
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   /* try to allocate space for new engine info */
+   if (!(einfo = calloc(1, sizeof(Evas_Engine_Info_Wayland_Shm))))
      return NULL;
 
-   /* fill in default engine info fields */
-   info->magic.magic = rand();
-   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
+   /* fill in engine info */
+   einfo->magic.magic = rand();
+   einfo->render_mode = EVAS_RENDER_MODE_BLOCKING;
 
    /* return allocated engine info */
-   return info;
+   return einfo;
 }
 
 static void 
-eng_info_free(Evas *eo_evas EINA_UNUSED, void *einfo)
+eng_info_free(Evas *eo_evas EINA_UNUSED, void *info)
 {
-   Evas_Engine_Info_Wayland_Shm *info;
+   Evas_Engine_Info_Wayland_Shm *einfo;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
 
    /* try to free previously allocated engine info */
-   if ((info = (Evas_Engine_Info_Wayland_Shm *)einfo))
-     free(info);
+   if ((einfo = (Evas_Engine_Info_Wayland_Shm *)info))
+     free(einfo);
 }
 
 static int 
-eng_setup(Evas *eo_evas, void *einfo)
+eng_setup(Evas *eo_evas, void *info)
 {
-   Evas_Engine_Info_Wayland_Shm *info;
+   Evas_Engine_Info_Wayland_Shm *einfo;
    Evas_Public_Data *epd;
    Render_Engine *re = NULL;
 
    LOGFN(__FILE__, __LINE__, __FUNCTION__);
 
-   /* try to cast the engine info to our engine info */
-   if (!(info = (Evas_Engine_Info_Wayland_Shm *)einfo))
+   /* try to cast to our engine info */
+   if (!(einfo = (Evas_Engine_Info_Wayland_Shm *)info))
      return 0;
 
-   /* try to get evas public data from the canvas */
+   /* try to get evas public data */
    if (!(epd = eo_data_scope_get(eo_evas, EVAS_CANVAS_CLASS)))
      return 0;
 
    /* test for valid engine output */
    if (!(re = epd->engine.data.output))
      {
-        static int try_swap = -1;
-
-        /* NB: If we have no valid output then assume we have not been 
-         * initialized yet and call any needed common init routines */
+        /* if we have no engine data, assume we have not initialized yet */
         evas_common_init();
 
-        if (try_swap == -1)
-          {
-             /* check for env var to see if we should try swapping */
-             if (getenv("EVAS_NO_WAYLAND_SWAPBUF")) try_swap = 0;
-             else try_swap = 1;
-          }
+        re = _render_engine_swapbuf_setup(epd->output.w, epd->output.h,
+                                          einfo->info.rotation, 
+                                          einfo->info.depth, 
+                                          einfo->info.destination_alpha,
+                                          einfo->info.wl_shm, 
+                                          einfo->info.wl_surface);
 
-        if (!(re =
-              _output_engine_setup(info, epd->output.w, epd->output.h,
-                                   info->info.rotation, info->info.depth,
-                                   info->info.destination_alpha,
-                                   info->info.wl_shm, info->info.wl_surface)))
-          return 0;
-      }
+        if (re) 
+          re->generic.ob->info = einfo;
+        else
+          goto err;
+     }
    else
      {
         Outbuf *ob;
-        int ponebuf = 0;
-
-        if ((re) && (re->generic.ob)) ponebuf = re->generic.ob->onebuf;
 
-        ob = evas_swapbuf_setup(info, epd->output.w, epd->output.h,
-                                info->info.rotation,
-                                info->info.depth,
-                                info->info.destination_alpha,
-                                info->info.wl_shm,
-                                info->info.wl_surface);
-        if (!ob) return 0;
-
-        evas_render_engine_software_generic_update(&re->generic, ob, epd->output.w, epd->output.h);
-
-        if ((re) && (re->generic.ob)) re->generic.ob->onebuf = ponebuf;
+        ob = _evas_outbuf_setup(epd->output.w, epd->output.h, 
+                                einfo->info.rotation, einfo->info.depth, 
+                                einfo->info.destination_alpha, 
+                                einfo->info.wl_shm, einfo->info.wl_surface);
+        if (ob)
+          {
+             ob->info = einfo;
+             evas_render_engine_software_generic_update(&re->generic, ob, 
+                                                        epd->output.w, 
+                                                        epd->output.h);
+          }
      }
 
-   /* reassign render engine to output */
    epd->engine.data.output = re;
-   if (!epd->engine.data.output) return 0;
+   if (!epd->engine.data.output)
+     {
+        ERR("Failed to create Render Engine");
+        goto err;
+     }
 
    if (!epd->engine.data.context)
      {
@@ -173,86 +158,92 @@ eng_setup(Evas *eo_evas, void *einfo)
           epd->engine.func->context_new(epd->engine.data.output);
      }
 
-   /* return success */
    return 1;
+
+err:
+   evas_common_shutdown();
+   return 0;
 }
 
-static void
+static void 
 eng_output_free(void *data)
 {
-   Render_Engine *re = data;
+   Render_Engine *re;
 
-   LOGFN(__FILE__, __LINE__, __FUNCTION__);
-   evas_render_engine_software_generic_clean(&re->generic);
-   free(re);
+   if ((re = (Render_Engine *)data))
+     {
+        evas_render_engine_software_generic_clean(&re->generic);
+        free(re);
+     }
 
    evas_common_shutdown();
 }
 
-static void
+static void 
 eng_output_resize(void *data, int w, int h)
 {
    Render_Engine *re;
-   Evas_Engine_Info_Wayland_Shm *info;
+   Evas_Engine_Info_Wayland_Shm *einfo;
    int dx = 0, dy = 0;
+   Eina_Bool resize = EINA_FALSE;
 
    LOGFN(__FILE__, __LINE__, __FUNCTION__);
-   if (!(re = (Render_Engine *)data)) return;
 
-   if (!(info = re->generic.ob->info)) return;
+   if (!(re = (Render_Engine *)data)) return;
+   if (!(einfo = re->generic.ob->info)) return;
 
-   if (info->info.edges & 4)
+   if (einfo->info.edges & 4) // resize from left
      {
-        if ((info->info.rotation == 90) || (info->info.rotation == 270))
+        if ((einfo->info.rotation == 90) || (einfo->info.rotation == 270))
           dx = re->generic.ob->h - h;
         else
           dx = re->generic.ob->w - w;
      }
 
-   if (info->info.edges & 1)
+   if (einfo->info.edges & 1) // resize from top
      {
-        if ((info->info.rotation == 90) || (info->info.rotation == 270))
+        if ((einfo->info.rotation == 90) || (einfo->info.rotation == 270))
           dy = re->generic.ob->w - w;
         else
           dy = re->generic.ob->h - h;
      }
 
-   re->outbuf_reconfigure(re->generic.ob, dx, dy, w, h,
-                          info->info.rotation, info->info.depth,
-                          info->info.destination_alpha);
+   if (einfo->info.edges) resize = EINA_TRUE;
+
+   re->outbuf_reconfigure(re->generic.ob, dx, dy, w, h, 
+                          einfo->info.rotation, einfo->info.depth, 
+                          einfo->info.destination_alpha, resize);
 
    evas_common_tilebuf_free(re->generic.tb);
    if ((re->generic.tb = evas_common_tilebuf_new(w, h)))
      evas_common_tilebuf_set_tile_size(re->generic.tb, TILESIZE, TILESIZE);
 }
 
-/* module functions */
+/* EVAS MODULE FUNCTIONS */
 static int 
 module_open(Evas_Module *em)
 {
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
    /* check for valid evas module */
    if (!em) return 0;
 
+   /* try to get functions from whatever engine module we inherit from */
+   if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0;
+
    /* try to create our logging domain */
    _evas_engine_way_shm_log_dom = 
      eina_log_domain_register("evas-wayland_shm", EVAS_DEFAULT_LOG_COLOR);
    if (_evas_engine_way_shm_log_dom < 0)
      {
-        /* creating the logging domain failed. notify user */
-        EINA_LOG_ERR("Could not create a module log domain.");
-
-        /* return failure */
+        EINA_LOG_ERR("Cannot create a module logging domain");
         return 0;
      }
 
-   /* try to inherit base functions from the software generic engine */
-   if (!_evas_module_engine_inherit(&pfunc, "software_generic"))
-     return 0;
-
-   /* copy base functions from the software_generic engine */
+   /* copy parent functions */
    func = pfunc;
 
-   /* override any engine specific functions that we provide */
+   /* override engine specific functions */
 #define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_)
    ORD(info);
    ORD(info_free);
@@ -260,19 +251,23 @@ module_open(Evas_Module *em)
    ORD(output_free);
    ORD(output_resize);
 
-   /* advertise out our own api */
+   /* advertise our own engine functions */
    em->functions = (void *)(&func);
 
-   /* return success */
    return 1;
 }
 
 static void 
 module_close(Evas_Module *em EINA_UNUSED)
 {
-   /* if we have the log domain, unregister it */
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   /* unregister logging domain */
    if (_evas_engine_way_shm_log_dom > -1)
      eina_log_domain_unregister(_evas_engine_way_shm_log_dom);
+
+   /* reset logging domain variable */
+   _evas_engine_way_shm_log_dom = -1;
 }
 
 static Evas_Module_Api evas_modapi = 
index 9892449..4a74f4f 100644 (file)
@@ -38,32 +38,69 @@ extern int _evas_engine_way_shm_log_dom;
 # define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_way_shm_log_dom, __VA_ARGS__)
 
 # include <wayland-client.h>
+# include "../software_generic/Evas_Engine_Software_Generic.h"
+# include "Evas_Engine_Wayland_Shm.h"
 
-#include "Evas_Engine_Wayland_Shm.h"
+# define MAX_BUFFERS 4
+# define SURFACE_HINT_RESIZING 0x10
 
-#include "../software_generic/Evas_Engine_Software_Generic.h"
+typedef struct _Shm_Pool Shm_Pool;
+struct _Shm_Pool
+{
+   struct wl_shm_pool *pool;
+   size_t size, used;
+   void *data;
+};
 
-struct _Outbuf
+typedef struct _Shm_Data Shm_Data;
+struct _Shm_Data
 {
-   Evas_Engine_Info_Wayland_Shm *info;
+   struct wl_buffer *buffer;
+   Shm_Pool *pool;
+   void *map;
+};
+
+typedef struct _Shm_Leaf Shm_Leaf;
+struct _Shm_Leaf
+{
+   int w, h, busy;
+   Shm_Data *data;
+   Shm_Pool *resize_pool;
+   Eina_Bool valid : 1;
+};
+
+typedef struct _Shm_Surface Shm_Surface;
+struct _Shm_Surface
+{
+   struct wl_shm *shm;
+   struct wl_surface *surface;
+   struct wl_callback *frame_cb;
+   uint32_t flags;
+   int w, h;
+   int dx, dy;
+   int num_buff;
 
+   Shm_Leaf leaf[MAX_BUFFERS];
+   Shm_Leaf *current;
+
+   Eina_Bool redraw : 1;
+   Eina_Bool alpha : 1;
+};
+
+struct _Outbuf
+{
    int w, h;
    int rotation;
    int onebuf;
+   int num_buff;
    Outbuf_Depth depth;
 
-   struct 
-     {
-        struct 
-          {
-             /* wayland shared memory object */
-             struct wl_shm *shm;
-             struct wl_surface *surface;
-          } wl;
+   Evas_Engine_Info_Wayland_Shm *info;
 
-        /* swapper */
-        void *swapper;
+   Shm_Surface *surface;
 
+   struct 
+     {
         /* one big buffer for updates. flushed on idle_flush */
         RGBA_Image *onebuf;
         Eina_Array onebuf_regions;
@@ -74,8 +111,28 @@ struct _Outbuf
         /* list of previous frame pending regions to write out */
         Eina_List *prev_pending_writes;
 
+        /* Eina_Bool redraw : 1; */
         Eina_Bool destination_alpha : 1;
      } priv;
 };
 
+Shm_Surface *_evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, int h, Eina_Bool alpha);
+void _evas_shm_surface_destroy(Shm_Surface *surface);
+void _evas_shm_surface_prepare(Shm_Surface *surface, int dx, int dy, int w, int h, int num_buff, uint32_t flags);
+void _evas_shm_surface_swap(Shm_Surface *surface, Eina_Rectangle *rects, unsigned int count);
+void *_evas_shm_surface_data_get(Shm_Surface *surface, int *w, int *h);
+void _evas_shm_surface_redraw(Shm_Surface *surface);
+
+Outbuf *_evas_outbuf_setup(int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, struct wl_shm *shm, struct wl_surface *surface);
+void _evas_outbuf_free(Outbuf *ob);
+void _evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
+void _evas_outbuf_idle_flush(Outbuf *ob);
+
+Render_Engine_Swap_Mode _evas_outbuf_swapmode_get(Outbuf *ob);
+int _evas_outbuf_rotation_get(Outbuf *ob);
+void _evas_outbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, Eina_Bool resize);
+void *_evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
+void _evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
+void _evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
+
 #endif
diff --git a/src/modules/evas/engines/wayland_shm/evas_outbuf.c b/src/modules/evas/engines/wayland_shm/evas_outbuf.c
new file mode 100644 (file)
index 0000000..cedd2f1
--- /dev/null
@@ -0,0 +1,515 @@
+#include "evas_common_private.h"
+#include "evas_private.h"
+#ifdef EVAS_CSERVE2
+# include "evas_cs2_private.h"
+#endif
+#include "evas_engine.h"
+
+#define RED_MASK 0x00ff0000
+#define GREEN_MASK 0x0000ff00
+#define BLUE_MASK 0x000000ff
+
+Outbuf *
+_evas_outbuf_setup(int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, struct wl_shm *shm, struct wl_surface *surface)
+{
+   Outbuf *ob = NULL;
+   char *num;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   /* try to allocate space for new Outbuf */
+   if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL;
+
+   /* set outbuf properties */
+   ob->w = w;
+   ob->h = h;
+   ob->rotation = rot;
+   ob->depth = depth;
+   ob->priv.destination_alpha = alpha;
+
+   /* default to double buffer */
+   ob->num_buff = 2;
+
+   /* check for any 'number of buffers' override in the environment */
+   if ((num = getenv("EVAS_WAYLAND_SHM_BUFFERS")))
+     {
+        int n = 0;
+
+        n = atoi(num);
+        if (n <= 0) n = 1;
+        if (n > 4) n = 4;
+
+        ob->num_buff = n;
+     }
+
+   /* try to create the outbuf surface */
+   if (!(ob->surface = _evas_shm_surface_create(shm, surface, w, h, alpha)))
+     goto surf_err;
+
+   /* call prepare function to setup first buffer */
+   _evas_shm_surface_prepare(ob->surface, 0, 0, w, h, 
+                             ob->num_buff, ob->surface->flags);
+
+   eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8);
+
+   return ob;
+
+surf_err:
+   free(ob);
+   return NULL;
+}
+
+void 
+_evas_outbuf_free(Outbuf *ob)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   _evas_outbuf_flush(ob, NULL, MODE_FULL);
+   _evas_outbuf_idle_flush(ob);
+
+   if (ob->surface) _evas_shm_surface_destroy(ob->surface);
+
+   eina_array_flush(&ob->priv.onebuf_regions);
+
+   free(ob);
+}
+
+void 
+_evas_outbuf_idle_flush(Outbuf *ob)
+{
+   _evas_shm_surface_redraw(ob->surface);
+}
+
+void 
+_evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode)
+{
+   Eina_Rectangle *result;
+   RGBA_Image *img;
+   unsigned int n = 0, i = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
+
+   if (!ob->surface->current)
+     {
+        WRN("Cannot Flush. No Current Leaf !!");
+        return;
+     }
+
+   /* check for pending writes */
+   if (!ob->priv.pending_writes)
+     {
+        Eina_Rectangle *rect;
+        Eina_Array_Iterator it;
+
+        /* get number of buffer regions */
+        n = eina_array_count_get(&ob->priv.onebuf_regions);
+        if (n == 0) return;
+
+        /* allocate rectangles */
+        if (!(result = alloca(n * sizeof(Eina_Rectangle)))) return;
+
+        /* loop the buffer regions and assign to result */
+        EINA_ARRAY_ITER_NEXT(&ob->priv.onebuf_regions, i, rect, it)
+          result[i] = *rect;
+
+        /* force a buffer swap */
+        _evas_shm_surface_swap(ob->surface, result, n);
+
+        /* clean array */
+        eina_array_clean(&ob->priv.onebuf_regions);
+
+        img = ob->priv.onebuf;
+        ob->priv.onebuf = NULL;
+        if (img)
+          {
+#ifdef EVAS_CSERVE2
+             if (evas_cserve2_use_get())
+               evas_cache2_image_close(&img->cache_entry);
+             else
+#endif
+               evas_cache_image_drop(&img->cache_entry);
+          }
+     }
+   else
+     {
+        /* get number of pending writes */
+        n = eina_list_count(ob->priv.pending_writes);
+        if (n == 0) return;
+
+        /* allocate rectangles */
+        if (!(result = alloca(n * sizeof(Eina_Rectangle)))) return;
+
+        /* loop the pending writes */
+        EINA_LIST_FREE(ob->priv.pending_writes, img)
+          {
+             Eina_Rectangle *rect;
+             int x = 0, y = 0, w = 0, h = 0;
+
+             if (!(rect = img->extended_info)) continue;
+
+             x = rect->x; y = rect->y; w = rect->w; h = rect->h;
+
+             /* based on rotation, set rectangle position */
+             if (ob->rotation == 0)
+               {
+                  result[i].x = x;
+                  result[i].y = y;
+               }
+             else if (ob->rotation == 90)
+               {
+                  result[i].x = y;
+                  result[i].y = (ob->w - x - w);
+               }
+             else if (ob->rotation == 180)
+               {
+                  result[i].x = (ob->w - x - w);
+                  result[i].y = (ob->h - y - h);
+               }
+             else if (ob->rotation == 270)
+               {
+                  result[i].x = (ob->h - y - h);
+                  result[i].y = x;
+               }
+
+             /* based on rotation, set rectangle size */
+             if ((ob->rotation == 0) || (ob->rotation == 180))
+               {
+                  result[i].w = w;
+                  result[i].h = h;
+               }
+             else if ((ob->rotation == 90) || (ob->rotation == 270))
+               {
+                  result[i].w = h;
+                  result[i].h = w;
+               }
+
+             eina_rectangle_free(rect);
+
+#ifdef EVAS_CSERVE2
+             if (evas_cserve2_use_get())
+               evas_cache2_image_close(&img->cache_entry);
+             else
+#endif
+               evas_cache_image_drop(&img->cache_entry);
+
+             i++;
+          }
+
+        /* force a buffer swap */
+        _evas_shm_surface_swap(ob->surface, result, n);
+     }
+
+   _evas_shm_surface_redraw(ob->surface);
+}
+
+Render_Engine_Swap_Mode 
+_evas_outbuf_swapmode_get(Outbuf *ob)
+{
+   int i = 0, count = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   for (; i < ob->num_buff; i++)
+     {
+        if (ob->surface->leaf[i].busy)
+          count++;
+     }
+
+   switch (count)
+     {
+      case 0:
+        return MODE_COPY;
+      case 1:
+        return MODE_DOUBLE;
+      case 2:
+        return MODE_TRIPLE;
+      case 3:
+        return MODE_QUADRUPLE;
+      default:
+        return MODE_FULL;
+     }
+}
+
+int 
+_evas_outbuf_rotation_get(Outbuf *ob)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   return ob->rotation;
+}
+
+void 
+_evas_outbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, Eina_Bool resize)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth;
+
+   if ((ob->w == w) && (ob->h == h) && 
+       (ob->rotation == rot) && (ob->depth == depth) && 
+       (ob->priv.destination_alpha == alpha))
+     return;
+
+   ob->w = w;
+   ob->h = h;
+   ob->rotation = rot;
+   ob->depth = depth;
+   ob->priv.destination_alpha = alpha;
+
+   if (resize)
+     ob->surface->flags = SURFACE_HINT_RESIZING;
+   else
+     ob->surface->flags = 0;
+
+   _evas_shm_surface_prepare(ob->surface, x, y, w, h, 
+                             ob->num_buff, ob->surface->flags);
+}
+
+void *
+_evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
+{
+   RGBA_Image *img;
+   Eina_Rectangle *rect;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h);
+   if ((w <= 0) || (h <= 0)) return NULL;
+
+   if (ob->rotation == 0)
+     {
+        if (!(img = ob->priv.onebuf))
+          {
+             int bw = 0, bh = 0, bpl = 0;
+             void *data;
+
+             if (!(data = _evas_shm_surface_data_get(ob->surface, &bw, &bh)))
+               {
+                  ERR("Could not get surface data");
+                  return NULL;
+               }
+
+             bpl = (bw * sizeof(int));
+
+#ifdef EVAS_CSERVE2
+             if (evas_cserve2_use_get())
+               {
+                  img = (RGBA_Image *)
+                    evas_cache2_image_data(evas_common_image_cache2_get(),
+                                           bpl / sizeof(int), bh, data,
+                                           ob->priv.destination_alpha,
+                                           EVAS_COLORSPACE_ARGB8888);
+               }
+             else
+#endif
+               {
+                  img = (RGBA_Image *)
+                    evas_cache_image_data(evas_common_image_cache_get(),
+                                          bpl / sizeof(int), bh, data,
+                                          ob->priv.destination_alpha,
+                                          EVAS_COLORSPACE_ARGB8888);
+
+               }
+
+             ob->priv.onebuf = img;
+             if (!img) return NULL;
+          }
+
+        if (!(rect = eina_rectangle_new(x, y, w, h)))
+          return NULL;
+
+        if (!eina_array_push(&ob->priv.onebuf_regions, rect))
+          {
+#ifdef EVAS_CSERVE2
+             if (evas_cserve2_use_get())
+               evas_cache2_image_close(&img->cache_entry);
+             else
+#endif
+               evas_cache_image_drop(&img->cache_entry);
+
+             eina_rectangle_free(rect);
+             return NULL;
+          }
+
+        if (cx) *cx = x;
+        if (cy) *cy = y;
+        if (cw) *cw = w;
+        if (ch) *ch = h;
+
+        img->extended_info = rect;
+
+        return img;
+     }
+   else
+     {
+        if (!(rect = eina_rectangle_new(x, y, w, h)))
+          return NULL;
+
+#ifdef EVAS_CSERVE2
+        if (evas_cserve2_use_get())
+          img = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get());
+        else
+#endif
+          img = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
+
+        if (!img)
+          {
+             eina_rectangle_free(rect);
+             return NULL;
+          }
+
+        img->cache_entry.flags.alpha |= ob->priv.destination_alpha ? 1 : 0;
+
+#ifdef EVAS_CSERVE2
+        if (evas_cserve2_use_get())
+          evas_cache2_image_surface_alloc(&img->cache_entry, w, h);
+        else
+#endif
+          evas_cache_image_surface_alloc(&img->cache_entry, w, h);
+
+        img->extended_info = rect;
+
+        ob->priv.pending_writes = 
+          eina_list_append(ob->priv.pending_writes, img);
+
+        if (cx) *cx = 0;
+        if (cy) *cy = 0;
+        if (cw) *cw = w;
+        if (ch) *ch = h;
+        return img;
+     }
+
+   return NULL;
+}
+
+void 
+_evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h)
+{
+   Gfx_Func_Convert func = NULL;
+   Eina_Rectangle rect = {0, 0, 0, 0}, pr;
+   DATA32 *src;
+   DATA8 *dst;
+   int depth = 32, bpp = 0, bpl = 0, wid = 0;
+   int ww = 0, hh = 0;
+   int rx = 0, ry = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   /* check for valid output buffer */
+   if (!ob) return;
+
+   /* check for pending writes */
+   if (!ob->priv.pending_writes) return;
+
+   if ((ob->rotation == 0) || (ob->rotation == 180))
+     {
+        func = 
+          evas_common_convert_func_get(0, w, h, depth, 
+                                       RED_MASK, GREEN_MASK, BLUE_MASK,
+                                       PAL_MODE_NONE, ob->rotation);
+     }
+   else if ((ob->rotation == 90) || (ob->rotation == 270))
+     {
+        func = 
+          evas_common_convert_func_get(0, h, w, depth, 
+                                       RED_MASK, GREEN_MASK, BLUE_MASK,
+                                       PAL_MODE_NONE, ob->rotation);
+     }
+
+   /* make sure we have a valid convert function */
+   if (!func) return;
+
+   /* based on rotation, set rectangle position */
+   if (ob->rotation == 0)
+     {
+        rect.x = x;
+        rect.y = y;
+     }
+   else if (ob->rotation == 90)
+     {
+        rect.x = y;
+        rect.y = (ob->w - x - w);
+     }
+   else if (ob->rotation == 180)
+     {
+        rect.x = (ob->w - x - w);
+        rect.y = (ob->h - y - h);
+     }
+   else if (ob->rotation == 270)
+     {
+        rect.x = (ob->h - y - h);
+        rect.y = x;
+     }
+
+   /* based on rotation, set rectangle size */
+   if ((ob->rotation == 0) || (ob->rotation == 180))
+     {
+        rect.w = w;
+        rect.h = h;
+     }
+   else if ((ob->rotation == 90) || (ob->rotation == 270))
+     {
+        rect.w = h;
+        rect.h = w;
+     }
+
+   /* check for valid update image data */
+   if (!(src = update->image.data)) return;
+
+   bpp = depth / 8;
+   if (bpp <= 0) return;
+
+   /* check for valid desination data */
+   if (!(dst = _evas_shm_surface_data_get(ob->surface, &ww, &hh))) return;
+
+   bpl = (ww * sizeof(int));
+
+   if (ob->rotation == 0)
+     {
+        RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
+        dst += (bpl * rect.y) + (rect.x * bpp);
+        w -= rx;
+     }
+   else if (ob->rotation == 180)
+     {
+        pr = rect;
+        RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
+        rx = pr.w - rect.w;
+        ry = pr.h - rect.h;
+        src += (update->cache_entry.w * ry) + rx;
+        w -= rx;
+     }
+   else if (ob->rotation == 90)
+     {
+        pr = rect;
+        RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
+        rx = pr.w - rect.w; ry = pr.h - rect.h;
+        src += ry;
+        w -= ry;
+     }
+   else if (ob->rotation == 270)
+     {
+        pr = rect;
+        RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh);
+        rx = pr.w - rect.w; ry = pr.h - rect.h;
+        src += (update->cache_entry.w * rx);
+        w -= ry;
+     }
+
+   if ((rect.w <= 0) || (rect.h <= 0)) return;
+
+   wid = bpl / bpp;
+
+   dst += (bpl * rect.y) + (rect.x * bpp);
+
+   func(src, dst, (update->cache_entry.w - w), (wid - rect.w),
+        rect.w, rect.h, x + rx, y + ry, NULL);
+}
+
+void 
+_evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+}
diff --git a/src/modules/evas/engines/wayland_shm/evas_shm.c b/src/modules/evas/engines/wayland_shm/evas_shm.c
new file mode 100644 (file)
index 0000000..16c7d27
--- /dev/null
@@ -0,0 +1,477 @@
+#include "evas_common_private.h"
+#include "evas_private.h"
+#ifdef EVAS_CSERVE2
+# include "evas_cs2_private.h"
+#endif
+#include "evas_engine.h"
+#include <sys/mman.h>
+
+static void 
+_evas_shm_surface_cb_frame(void *data, struct wl_callback *callback, uint32_t timestamp EINA_UNUSED)
+{
+   Shm_Surface *surf;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (!(surf = data)) return;
+   if (callback != surf->frame_cb) return;
+
+   wl_callback_destroy(callback);
+   surf->frame_cb = NULL;
+   surf->redraw = EINA_FALSE;
+}
+
+static const struct wl_callback_listener _frame_listener = 
+{
+   _evas_shm_surface_cb_frame
+};
+
+static struct wl_shm_pool *
+_shm_pool_make(struct wl_shm *shm, int size, void **data)
+{
+   struct wl_shm_pool *pool;
+   static const char tmp[] = "/evas-wayland_shm-XXXXXX";
+   const char *path;
+   char *name;
+   int fd = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   /* check for valid wl_shm */
+   if (!shm) return NULL;
+
+   /* create tmp file name */
+   if ((path = getenv("XDG_RUNTIME_DIR")))
+     {
+        if ((name = malloc(strlen(path) + sizeof(tmp))))
+          strcpy(name, path);
+     }
+   else
+     {
+        if ((name = malloc(strlen("/tmp") + sizeof(tmp))))
+          strcpy(name, "/tmp");
+     }
+
+   if (!name) return NULL;
+
+   strcat(name, tmp);
+
+   /* try to create tmp file */
+   if ((fd = mkstemp(name)) < 0)
+     {
+        ERR("Could not create temporary file: %m");
+        free(name);
+        return NULL;
+     }
+
+   unlink(name);
+   free(name);
+
+   /* try to truncate file to size */
+   if (ftruncate(fd, size) < 0)
+     {
+        ERR("Could not truncate temporary file: %m");
+        goto fd_err;
+     }
+
+   /* try to mmap the file */
+   *data = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
+   if (*data == MAP_FAILED)
+     {
+        ERR("Could not mmap temporary file: %m");
+        goto fd_err;
+     }
+
+   /* create wl_shm_pool using fd */
+   pool = wl_shm_create_pool(shm, fd, size);
+
+   close(fd);
+
+   return pool;
+
+fd_err:
+   close(fd);
+   return NULL;
+}
+
+static Shm_Pool *
+_shm_pool_create(struct wl_shm *shm, size_t size)
+{
+   Shm_Pool *pool;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (!(pool = malloc(sizeof(Shm_Pool)))) return NULL;
+
+   pool->pool = _shm_pool_make(shm, size, &pool->data);
+   if (!pool->pool) goto err;
+
+   pool->size = size;
+   pool->used = 0;
+
+   return pool;
+
+err:
+   free(pool);
+   return NULL;
+}
+
+static void 
+_shm_pool_destroy(Shm_Pool *pool)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   munmap(pool->data, pool->size);
+   wl_shm_pool_destroy(pool->pool);
+   free(pool);
+}
+
+static void *
+_shm_pool_allocate(Shm_Pool *pool, size_t size, int *offset)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if ((pool->used + size) > pool->size)
+     return NULL;
+
+   *offset = pool->used;
+   pool->used += size;
+
+   return (char *)pool->data + *offset;
+}
+
+static void 
+_shm_pool_reset(Shm_Pool *pool)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   pool->used = 0;
+}
+
+static Shm_Data *
+_shm_data_create_from_pool(Shm_Pool *pool, int w, int h, Eina_Bool alpha)
+{
+   Shm_Data *data;
+   int len, offset;
+   uint32_t wl_format = WL_SHM_FORMAT_XRGB8888;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   /* try to malloc space for data */
+   if (!(data = malloc(sizeof(Shm_Data))))
+     {
+        ERR("Could not allocate space for data");
+        return NULL;
+     }
+
+   len = (w * sizeof(int)) * h;
+   data->pool = NULL;
+
+   if (!(data->map = _shm_pool_allocate(pool, len, &offset)))
+     {
+        ERR("Could not map leaf data");
+        free(data);
+        return NULL;
+     }
+
+   if (alpha) 
+     wl_format = WL_SHM_FORMAT_ARGB8888;
+
+   data->buffer = 
+     wl_shm_pool_create_buffer(pool->pool, offset, w, h, 
+                               (w * sizeof(int)), wl_format);
+   if (!data->buffer)
+     {
+        ERR("Could not create buffer from pool: %m");
+        free(data);
+        return NULL;
+     }
+
+   return data;
+}
+
+static void
+_shm_data_create(Shm_Pool *alt_pool, Shm_Data **ret, Shm_Surface *surface, int w, int h)
+{
+   Shm_Pool *pool;
+   Shm_Data *data;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (alt_pool)
+     {
+        _shm_pool_reset(alt_pool);
+        if ((data = _shm_data_create_from_pool(alt_pool, w, h, surface->alpha)))
+          goto out;
+     }
+
+   if (!(pool = _shm_pool_create(surface->shm, ((w * sizeof(int)) * h))))
+     {
+        ERR("Could not create shm pool");
+        goto err;
+     }
+
+   if (!(data = _shm_data_create_from_pool(pool, w, h, surface->alpha)))
+     {
+        ERR("Could not create data from pool");
+        _shm_pool_destroy(pool);
+        goto err;
+     }
+
+   data->pool = pool;
+
+out:
+   if (ret) *ret = data;
+   return;
+err:
+   if (ret) *ret = NULL;
+}
+
+static void 
+_shm_data_destroy(Shm_Data *data)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (data->buffer) wl_buffer_destroy(data->buffer);
+   if (data->pool) _shm_pool_destroy(data->pool);
+   free(data);
+}
+
+static void 
+_shm_leaf_release(Shm_Leaf *leaf)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (leaf->data) _shm_data_destroy(leaf->data);
+   if (leaf->resize_pool) _shm_pool_destroy(leaf->resize_pool);
+   memset(leaf, 0, sizeof(*leaf));
+}
+
+static void 
+_shm_buffer_release(void *data, struct wl_buffer *buffer)
+{
+   Shm_Surface *surf;
+   Shm_Leaf *leaf;
+   int i = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   surf = data;
+
+   for (; i < surf->num_buff; i++)
+     {
+        leaf = &surf->leaf[i];
+        if ((leaf->data) && (leaf->data->buffer == buffer))
+          {
+             leaf->busy = 0;
+             break;
+          }
+     }
+}
+
+static const struct wl_buffer_listener _shm_buffer_listener = 
+{
+   _shm_buffer_release
+};
+
+Shm_Surface *
+_evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, int h, Eina_Bool alpha)
+{
+   Shm_Surface *surf;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (!(surf = calloc(1, sizeof(Shm_Surface)))) return NULL;
+
+   surf->dx = 0;
+   surf->dy = 0;
+   surf->w = w;
+   surf->h = h;
+   surf->shm = shm;
+   surf->surface = surface;
+   surf->alpha = alpha;
+   surf->flags = 0;
+
+   return surf;
+}
+
+void 
+_evas_shm_surface_destroy(Shm_Surface *surface)
+{
+   int i = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   for (; i < surface->num_buff; i++)
+     _shm_leaf_release(&surface->leaf[i]);
+
+   free(surface);
+}
+
+void 
+_evas_shm_surface_prepare(Shm_Surface *surface, int dx, int dy, int w, int h, int num_buff, uint32_t flags)
+{
+   Shm_Leaf *leaf = NULL;
+   int i = 0, resize = 0;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   resize = !!(flags & SURFACE_HINT_RESIZING);
+
+   /* update surface properties */
+   surface->w = w;
+   surface->h = h;
+   surface->dx = dx;
+   surface->dy = dy;
+   surface->num_buff = num_buff;
+
+   for (; i < num_buff; i++)
+     {
+        if (surface->leaf[i].busy) continue;
+        if ((!leaf) || (leaf->valid))
+          {
+             leaf = &surface->leaf[i];
+             break;
+          }
+     }
+
+   if (!leaf)
+     {
+        CRI("All buffers held by server");
+        return;
+     }
+
+   if ((!resize) && (leaf->resize_pool))
+     {
+        _shm_data_destroy(leaf->data);
+        leaf->data = NULL;
+
+        _shm_pool_destroy(leaf->resize_pool);
+        leaf->resize_pool = NULL;
+     }
+
+   if (leaf->valid)
+     {
+        if ((leaf->w == w) && (leaf->h == h)) goto out;
+     }
+
+   if (leaf->data) _shm_data_destroy(leaf->data);
+   leaf->data = NULL;
+
+   if ((resize) && (!leaf->resize_pool))
+     {
+        leaf->resize_pool = 
+          _shm_pool_create(surface->shm, 6 * 1024 * 1024);
+     }
+
+   _shm_data_create(leaf->resize_pool, &leaf->data, surface, w, h);
+   if (!leaf->data)
+     {
+        CRI("Failed to create leaf data");
+        abort();
+     }
+
+   leaf->w = w;
+   leaf->h = h;
+   leaf->valid = EINA_TRUE;
+
+   wl_buffer_add_listener(leaf->data->buffer, &_shm_buffer_listener, surface);
+
+out:
+   surface->current = leaf;
+}
+
+void 
+_evas_shm_surface_swap(Shm_Surface *surface, Eina_Rectangle *rects, unsigned int count)
+{
+   Shm_Leaf *leaf;
+   Eina_Rectangle *rect;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (!(leaf = surface->current))
+     {
+        ERR("No Current Leaf");
+        return;
+     }
+
+   if (!leaf->valid)
+     {
+        ERR("Leaf Not Valid");
+        return;
+     }
+
+   rect = eina_rectangle_new(0, 0, 0, 0);
+   if ((rects) && (count > 0))
+     {
+        unsigned int i = 0;
+
+        for (; i < count; i++)
+          eina_rectangle_union(rect, &rects[i]);
+     }
+   else
+     {
+        Eina_Rectangle r;
+
+        r.x = 0; r.y = 0;
+        r.w = leaf->w; r.h = leaf->h;
+
+        eina_rectangle_union(rect, &r);
+     }
+
+   wl_surface_attach(surface->surface, leaf->data->buffer, 0, 0);
+   wl_surface_damage(surface->surface, rect->x, rect->y, rect->w, rect->h);
+   wl_surface_commit(surface->surface);
+
+   eina_rectangle_free(rect);
+
+   leaf->busy = 1;
+   surface->dx = 0;
+   surface->dy = 0;
+   surface->redraw = EINA_TRUE;
+}
+
+void *
+_evas_shm_surface_data_get(Shm_Surface *surface, int *bw, int *bh)
+{
+   Shm_Leaf *leaf;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (bw) *bw = 0;
+   if (bh) *bh = 0;
+
+   if (!(leaf = surface->current))
+     {
+        _evas_shm_surface_prepare(surface, 0, 0, surface->w, surface->h, 
+                                  surface->num_buff, surface->flags);
+
+        if (!(leaf = surface->current))
+          {
+             CRI("NO Current Surface");
+             return NULL;
+          }
+     }
+
+   if (bw) *bw = leaf->w;
+   if (bh) *bh = leaf->h;
+
+   return leaf->data->map;
+}
+
+void 
+_evas_shm_surface_redraw(Shm_Surface *surface)
+{
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   if (surface->frame_cb)
+     {
+        if (!surface->redraw) return;
+        wl_callback_destroy(surface->frame_cb);
+     }
+
+   if (!surface->surface) return;
+
+   surface->frame_cb = wl_surface_frame(surface->surface);
+   wl_callback_add_listener(surface->frame_cb, &_frame_listener, surface);
+}