big patch from Samsung SAIT (Advanced research group) for async multi-frame
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 21 May 2010 07:10:45 +0000 (07:10 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 21 May 2010 07:10:45 +0000 (07:10 +0000)
rendering. to turn on:

1.
configure with --enable-async-render
2.
export EVAS_RENDER_MODE=non-blocking

presto. necessitates some api swizzling (thus the expedite. ecore etc. changes)

the kind of results you get on a desktop:

http://www.rasterman.com/files/evas-async-vs-none.html

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

65 files changed:
AUTHORS
README.in
configure.ac
src/lib/Evas.h
src/lib/cache/evas_cache.h
src/lib/cache/evas_cache_image.c
src/lib/canvas/evas_main.c
src/lib/canvas/evas_object_gradient.c
src/lib/canvas/evas_object_gradient2.c
src/lib/canvas/evas_object_image.c
src/lib/canvas/evas_object_main.c
src/lib/canvas/evas_object_text.c
src/lib/canvas/evas_object_textblock.c
src/lib/canvas/evas_render.c
src/lib/engines/common/Makefile.am
src/lib/engines/common/evas_font_draw.c
src/lib/engines/common/evas_font_load.c
src/lib/engines/common/evas_font_main.c
src/lib/engines/common/evas_font_private.h [new file with mode: 0644]
src/lib/engines/common/evas_font_query.c
src/lib/engines/common/evas_gradient2_main.c
src/lib/engines/common/evas_gradient_main.c
src/lib/engines/common/evas_image_main.c
src/lib/engines/common/evas_image_scalecache.c
src/lib/engines/common/evas_intl_utils.c
src/lib/engines/common/evas_pipe.c
src/lib/engines/common/evas_pipe.h
src/lib/include/evas_common.h
src/modules/engines/buffer/Evas_Engine_Buffer.h
src/modules/engines/buffer/evas_engine.c
src/modules/engines/cairo_x11/Evas_Engine_Cairo_X11.h
src/modules/engines/cairo_x11/evas_engine.c
src/modules/engines/direct3d/Evas_Engine_Direct3D.h
src/modules/engines/direct3d/evas_engine.c
src/modules/engines/directfb/Evas_Engine_DirectFB.h
src/modules/engines/fb/Evas_Engine_FB.h
src/modules/engines/fb/evas_engine.c
src/modules/engines/gl_glew/Evas_Engine_GL_Glew.h
src/modules/engines/gl_glew/evas_engine.c
src/modules/engines/gl_x11/Evas_Engine_GL_X11.h
src/modules/engines/gl_x11/evas_engine.c
src/modules/engines/quartz/Evas_Engine_Quartz.h
src/modules/engines/quartz/evas_engine.c
src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h
src/modules/engines/software_16_ddraw/evas_engine.c
src/modules/engines/software_16_sdl/Evas_Engine_SDL_16.h
src/modules/engines/software_16_wince/Evas_Engine_Software_16_WinCE.h
src/modules/engines/software_16_wince/evas_engine.c
src/modules/engines/software_16_x11/Evas_Engine_Software_16_X11.h
src/modules/engines/software_16_x11/evas_engine.c
src/modules/engines/software_ddraw/Evas_Engine_Software_DDraw.h
src/modules/engines/software_ddraw/evas_engine.c
src/modules/engines/software_gdi/Evas_Engine_Software_Gdi.h
src/modules/engines/software_generic/evas_engine.c
src/modules/engines/software_qtopia/Evas_Engine_Software_Qtopia.h
src/modules/engines/software_qtopia/evas_engine.c
src/modules/engines/software_sdl/Evas_Engine_SDL.h
src/modules/engines/software_x11/Evas_Engine_Software_X11.h
src/modules/engines/software_x11/evas_engine.c
src/modules/engines/software_x11/evas_engine.h
src/modules/engines/software_x11/evas_xlib_buffer.c
src/modules/engines/software_x11/evas_xlib_outbuf.c
src/modules/engines/software_x11/evas_xlib_outbuf.h
src/modules/engines/xrender_x11/Evas_Engine_XRender_X11.h
src/modules/engines/xrender_x11/evas_engine.c

diff --git a/AUTHORS b/AUTHORS
index fce4857..d9c7f7b 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -18,3 +18,5 @@ Tom Hacohen <tom@stosb.com>
 Mathieu Taillefumier <mathieu.taillefumier@free.fr>
 Iván Briano <ivan@profusion.mobi>
 Gustavo Lima Chaves <glima@profusion.mobi>
+Saumsung Electronics <tbd>
+Samsung SAIT <tbd>
index b0897f9..1e3e6c9 100644 (file)
--- a/README.in
+++ b/README.in
@@ -275,3 +275,8 @@ NOTES:
 
 For the arm optimizations you want to try:
   export CFLAGS="-O2 -march=armv5te -mcpu=arm1136jf-s -fomit-frame-pointer"
+
+To enable the async renderer compile with:
+  --enable-async-render
+and also runtime set this environment variable:
+  export EVAS_RENDER_MODE=non-blocking
index e865dd8..a30d5f9 100644 (file)
@@ -761,6 +761,38 @@ else
 fi
 
 #######################################
+## Async Renderer
+build_async_render="no"
+AC_MSG_CHECKING(whether to build Asynchronously Threaded Pipe Rendering support)
+AC_ARG_ENABLE(async-render,
+  AC_HELP_STRING([--enable-async-render], [enable asynchronously threaded pipe rendering support]),
+  [ build_async_render=$enableval ]
+)
+AC_MSG_RESULT($build_async_render)
+
+AC_MSG_CHECKING(whether we can build Asynchronously Threaded Pipe Rendering support)
+if test \( "x$build_async_render" = "xyes" \); then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(EVAS_FRAME_QUEUING, 1, [Build async render support])
+  build_async_render="yes"
+  AC_DEFINE(BUILD_PIPE_RENDER, 1, [Build pipe render support])
+  build_pipe_render="yes"
+  need_pthreads="yes"
+
+  PKG_CHECK_MODULES([XEXT],
+     [xext < 1.1.1],
+     [ build_avoid_libXext_bug=yes ],
+     [ build_avoid_libXext_bug=no ]
+  )
+  if test \( "x$build_avoid_libXext_bug" = "xyes" \); then
+    AC_DEFINE(LIBXEXT_VERSION_LOW, 1, [To avoid bug on old libXext version])
+  fi
+else
+  AC_MSG_RESULT(no)
+  build_async_render="no"
+fi
+
+#######################################
 ## Async events
 build_async_events="auto"
 AC_MSG_CHECKING(whether to build Async Events support)
@@ -1453,6 +1485,7 @@ echo "  MAGIC_DEBUG.............: $want_evas_magic_debug"
 echo "  Cache Server............: $want_evas_cserve"
 echo
 echo "  Threaded Pipe Rendering.: $build_pipe_render"
+echo "  Async Pipe Rendering....: $build_async_render"
 echo "  Async Events............: $build_async_events"
 echo "  Async Image Preload.....: $build_async_preload"
 echo
index 0590049..f5f9628 100644 (file)
@@ -373,6 +373,12 @@ typedef enum _Evas_Image_Scale_Hint
    EVAS_IMAGE_SCALE_HINT_STATIC = 2
 } Evas_Image_Scale_Hint;
 
+typedef enum _Evas_Engine_Render_Mode
+{
+   EVAS_RENDER_MODE_BLOCKING = 0,
+   EVAS_RENDER_MODE_NONBLOCKING = 1,
+} Evas_Engine_Render_Mode;
+
 typedef enum _Evas_Image_Content_Hint
 {
    EVAS_IMAGE_CONTENT_HINT_NONE = 0,
@@ -721,6 +727,7 @@ extern "C" {
    EAPI void              evas_pointer_canvas_xy_get        (const Evas *e, Evas_Coord *x, Evas_Coord *y) EINA_ARG_NONNULL(1);
    EAPI int               evas_pointer_button_down_mask_get (const Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
    EAPI Eina_Bool         evas_pointer_inside_get           (const Evas *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+   EAPI void              evas_sync(Evas *e) EINA_ARG_NONNULL(1);
 
 
 /**
index 462d35a..80aedcf 100644 (file)
@@ -60,6 +60,9 @@ struct _Evas_Cache_Image
    int                           usage;
    int                           limit;
    int                           references;
+#ifdef EVAS_FRAME_QUEUING
+   LK(lock);
+#endif
 };
 
 struct _Evas_Cache_Engine_Image_Func
index 68a1d60..5bf0e84 100644 (file)
@@ -58,7 +58,13 @@ _evas_cache_image_make_dirty(Evas_Cache_Image *cache,
    im->flags.dirty = 1;
    im->flags.activ = 0;
    im->flags.lru_nodata = 0;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(cache->lock);
+#endif
    cache->dirty = eina_inlist_prepend(cache->dirty, EINA_INLIST_GET(im));
+#ifdef EVAS_FRAME_QUEUING
+   LKU(cache->lock);
+#endif
 
    if (im->cache_key)
      {
@@ -80,7 +86,13 @@ _evas_cache_image_make_activ(Evas_Cache_Image *cache,
         im->flags.activ = 1;
         im->flags.lru_nodata = 0;
         im->flags.dirty = 0;
+#ifdef EVAS_FRAME_QUEUING
+        LKL(cache->lock);
+#endif
        eina_hash_direct_add(cache->activ, key, im);
+#ifdef EVAS_FRAME_QUEUING
+        LKU(cache->lock);
+#endif
      }
    else
      {
@@ -98,9 +110,15 @@ _evas_cache_image_make_inactiv(Evas_Cache_Image *cache,
        im->flags.activ = 0;
        im->flags.dirty = 0;
        im->flags.cached = 1;
+#ifdef EVAS_FRAME_QUEUING
+        LKL(cache->lock);
+#endif
        eina_hash_direct_add(cache->inactiv, key, im);
        cache->lru = eina_inlist_prepend(cache->lru, EINA_INLIST_GET(im));
        cache->usage += cache->func.mem_size_get(im);
+#ifdef EVAS_FRAME_QUEUING
+        LKU(cache->lock);
+#endif
      }
    else
      {
@@ -115,9 +133,15 @@ _evas_cache_image_remove_lru_nodata(Evas_Cache_Image *cache,
    if (im->flags.lru_nodata)
      {
         im->flags.lru_nodata = 0;
+#ifdef EVAS_FRAME_QUEUING
+        LKL(cache->lock);
+#endif
         cache->lru_nodata = eina_inlist_remove(cache->lru_nodata, EINA_INLIST_GET(im));
         cache->usage -= cache->func.mem_size_get(im);
-     }
+#ifdef EVAS_FRAME_QUEUING
+        LKU(cache->lock);
+#endif
+    }
 }
 
 static void
@@ -126,8 +150,14 @@ _evas_cache_image_activ_lru_nodata(Evas_Cache_Image *cache,
 {
    im->flags.need_data = 0;
    im->flags.lru_nodata = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(cache->lock);
+#endif
    cache->lru_nodata = eina_inlist_prepend(cache->lru_nodata, EINA_INLIST_GET(im));
    cache->usage += cache->func.mem_size_get(im);
+#ifdef EVAS_FRAME_QUEUING
+   LKU(cache->lock);
+#endif
 }
 
 static void
@@ -138,11 +168,20 @@ _evas_cache_image_remove_activ(Evas_Cache_Image *cache,
      {
         if (ie->flags.activ)
           {
+#ifdef EVAS_FRAME_QUEUING
+             LKL(cache->lock);
+#endif
             eina_hash_del(cache->activ, ie->cache_key, ie);
+#ifdef EVAS_FRAME_QUEUING
+             LKU(cache->lock);
+#endif
              _evas_cache_image_remove_lru_nodata(cache, ie);
           }
         else
           {
+#ifdef EVAS_FRAME_QUEUING
+             LKL(cache->lock);
+#endif
              if (ie->flags.dirty)
                {
                  cache->dirty = eina_inlist_remove(cache->dirty, EINA_INLIST_GET(ie));
@@ -153,6 +192,9 @@ _evas_cache_image_remove_activ(Evas_Cache_Image *cache,
                   cache->lru = eina_inlist_remove(cache->lru, EINA_INLIST_GET(ie));
                   cache->usage -= cache->func.mem_size_get(ie);
                }
+#ifdef EVAS_FRAME_QUEUING
+             LKU(cache->lock);
+#endif
           }
         ie->flags.cached = 0;
         ie->flags.dirty = 0;
@@ -163,7 +205,8 @@ _evas_cache_image_remove_activ(Evas_Cache_Image *cache,
 static void
 _evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie)
 {
-   if (!ie) return ;
+   if (!ie)
+       return ;
 
    if (cache->func.debug)
      cache->func.debug("deleting", ie);
@@ -201,6 +244,9 @@ _evas_cache_image_entry_delete(Evas_Cache_Image *cache, Image_Entry *ie)
 #ifdef BUILD_ASYNC_PRELOAD
    LKD(ie->lock);
 #endif
+#ifdef EVAS_FRAME_QUEUING
+   LKD(ie->lock_references);
+#endif
 
    cache->func.dealloc(ie);
 }
@@ -237,6 +283,9 @@ _evas_cache_image_entry_new(Evas_Cache_Image *cache,
    ie->allocated.w = 0;
    ie->allocated.h = 0;
 
+#ifdef EVAS_FRAME_QUEUING
+   LKI(ie->lock_references);
+#endif
    ie->references = 0;
    ie->cache = cache;
 
@@ -400,12 +449,18 @@ _evas_cache_image_async_cancel(void *data)
        _evas_cache_image_async_end(ie);
      }
 
+#ifdef EVAS_FRAME_QUEUING
+   LKL(ie->lock_references);
+#endif
    if (ie->references == 0)
      {
        _evas_cache_image_remove_activ(ie->cache, ie);
        _evas_cache_image_make_inactiv(ie->cache, ie, ie->cache_key);
        evas_cache_image_flush(ie->cache);
      }
+#ifdef EVAS_FRAME_QUEUING
+   LKU(ie->lock_references);
+#endif
 }
 
 static int
@@ -500,9 +555,21 @@ EAPI void
 evas_cache_image_set(Evas_Cache_Image *cache, int limit)
 {
    assert(cache != NULL);
-   if (cache->limit == limit) return;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(cache->lock);
+#endif
+   if (cache->limit == limit)
+     {
+#ifdef EVAS_FRAME_QUEUING
+        LKU(cache->lock);
+#endif
+        return;
+     }
    cache->limit = limit;
    evas_cache_image_flush(cache);
+#ifdef EVAS_FRAME_QUEUING
+   LKU(cache->lock);
+#endif
 }
 
 EAPI Evas_Cache_Image *
@@ -530,6 +597,10 @@ evas_cache_image_init(const Evas_Cache_Image_Func *cb)
    new->preload = NULL;
    new->pending = NULL;
 
+#ifdef EVAS_FRAME_QUEUING
+   LKI(new->lock);
+#endif
+
    return new;
 }
 
@@ -550,10 +621,18 @@ evas_cache_image_shutdown(Evas_Cache_Image *cache)
    Image_Entry  *im;
 
    assert(cache != NULL);
+#ifdef EVAS_FRAME_QUEUING
+   LKL(cache->lock);
+#endif
    cache->references--;
 
    if (cache->references > 0)
-     return ;
+     {
+#ifdef EVAS_FRAME_QUEUING
+        LKU(cache->lock);
+#endif
+        return ;
+     }
 
 #ifdef BUILD_ASYNC_PRELOAD
    EINA_LIST_FREE(cache->preload, im)
@@ -610,6 +689,11 @@ evas_cache_image_shutdown(Evas_Cache_Image *cache)
    eina_hash_free(cache->activ);
    eina_hash_free(cache->inactiv);
 
+#ifdef EVAS_FRAME_QUEUING
+   LKU(cache->lock);
+   LKD(cache->lock);
+#endif
+
    free(cache);
 }
 
@@ -711,7 +795,13 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *
 
    hkey[size] = '\0';
 
+#ifdef EVAS_FRAME_QUEUING
+   LKL(cache->lock);
+#endif
    im = eina_hash_find(cache->activ, hkey);
+#ifdef EVAS_FRAME_QUEUING
+   LKU(cache->lock);
+#endif
    if (im)
      {
         time_t  t;
@@ -733,7 +823,13 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *
        _evas_cache_image_make_dirty(cache, im);
      }
 
+#ifdef EVAS_FRAME_QUEUING
+   LKL(cache->lock);
+#endif
    im = eina_hash_find(cache->inactiv, hkey);
+#ifdef EVAS_FRAME_QUEUING
+   LKU(cache->lock);
+#endif
    if (im)
      {
         int     ok;
@@ -779,9 +875,15 @@ evas_cache_image_request(Evas_Cache_Image *cache, const char *file, const char *
 
  on_ok:
    *error = EVAS_LOAD_ERROR_NONE;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
    im->references++;
    if (im->references > 1 && im->flags.lru_nodata)
      _evas_cache_image_remove_lru_nodata(cache, im);
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
 
    return im;
 
@@ -812,15 +914,37 @@ EAPI void
 evas_cache_image_drop(Image_Entry *im)
 {
    Evas_Cache_Image    *cache;
+   int                              references;
 
    assert(im);
    assert(im->cache);
 
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
    im->references--;
+   references = im->references;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
+   
    cache = im->cache;
 
-   if (im->references == 0)
+   if (references == 0)
      {
+#ifdef EVAS_FRAME_QUEUING
+        LKL(((RGBA_Image *)im)->ref_fq_add);
+        LKL(((RGBA_Image *)im)->ref_fq_del);
+        if (((RGBA_Image *)im)->ref_fq[0] != ((RGBA_Image *)im)->ref_fq[1])
+          {
+             LKU(((RGBA_Image *)im)->ref_fq_add);
+             LKU(((RGBA_Image *)im)->ref_fq_del);
+             return;
+          }
+       LKU(((RGBA_Image *)im)->ref_fq_add);
+       LKU(((RGBA_Image *)im)->ref_fq_del);
+#endif
+
 #ifdef BUILD_ASYNC_PRELOAD
        if (im->preload)
          {
@@ -845,13 +969,22 @@ EAPI void
 evas_cache_image_data_not_needed(Image_Entry *im)
 {
    Evas_Cache_Image    *cache;
-
+   int   references;
+   
    assert(im);
    assert(im->cache);
 
    cache = im->cache;
 
-   if (im->references > 1) return ;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
+   references = im->references;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
+
+   if (references > 1) return ;
    if (im->flags.dirty || !im->flags.need_data) return ;
 
    _evas_cache_image_activ_lru_nodata(cache, im);
@@ -862,6 +995,7 @@ evas_cache_image_dirty(Image_Entry *im, int x, int y, int w, int h)
 {
    Image_Entry          *im_dirty = im;
    Evas_Cache_Image     *cache;
+   int                           references;
 
    assert(im);
    assert(im->cache);
@@ -869,9 +1003,17 @@ evas_cache_image_dirty(Image_Entry *im, int x, int y, int w, int h)
    cache = im->cache;
    if (!(im->flags.dirty))
      {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
+   references = im->references;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
+
 #ifndef EVAS_CSERVE
 // if ref 1 also copy if using shared cache as its read-only
-        if (im->references == 1) im_dirty = im;
+        if (references == 1) im_dirty = im;
         else
 #endif
           {
@@ -900,7 +1042,13 @@ evas_cache_image_dirty(Image_Entry *im, int x, int y, int w, int h)
 
              if (error != 0) goto on_error;
  */
+#ifdef EVAS_FRAME_QUEUING
+             LKL(im_dirty->lock_references);
+#endif
              im_dirty->references = 1;
+#ifdef EVAS_FRAME_QUEUING
+             LKU(im_dirty->lock_references);
+#endif
 
              evas_cache_image_drop(im);
           }
@@ -927,12 +1075,21 @@ evas_cache_image_alone(Image_Entry *im)
 {
    Evas_Cache_Image     *cache;
    Image_Entry          *im_dirty = im;
+   int                           references;
 
    assert(im);
    assert(im->cache);
 
    cache = im->cache;
-   if (im->references == 1)
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
+   references = im->references;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
+
+   if (references == 1)
      {
         if (!(im->flags.dirty))
           {
@@ -967,7 +1124,13 @@ evas_cache_image_alone(Image_Entry *im)
 
         if (error != 0) goto on_error;
  */
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im_dirty->lock_references);
+#endif
         im_dirty->references = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im_dirty->lock_references);
+#endif
 
         evas_cache_image_drop(im);
      }
@@ -1004,7 +1167,13 @@ evas_cache_image_copied_data(Evas_Cache_Image *cache, int w, int h, DATA32 *imag
         _evas_cache_image_entry_delete(cache, im);
         return NULL;
      }
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
    im->references = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
 
    if (cache->func.debug)
      cache->func.debug("copied-data", im);
@@ -1032,7 +1201,13 @@ evas_cache_image_data(Evas_Cache_Image *cache, int w, int h, DATA32 *image_data,
         _evas_cache_image_entry_delete(cache, im);
         return NULL;
      }
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
    im->references = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
 
    if (cache->func.debug)
      cache->func.debug("data", im);
@@ -1068,7 +1243,13 @@ evas_cache_image_size_set(Image_Entry *im, int w, int h)
 
    assert(im);
    assert(im->cache);
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
    assert(im->references > 0);
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
 
    if ((im->space == EVAS_COLORSPACE_YCBCR422P601_PL) ||
        (im->space == EVAS_COLORSPACE_YCBCR422P709_PL))
@@ -1091,7 +1272,13 @@ evas_cache_image_size_set(Image_Entry *im, int w, int h)
    error = cache->func.size_set(new, im, w, h);
    if (error != 0) goto on_error;
 
+#ifdef EVAS_FRAME_QUEUING
+   LKL(new->lock_references);
+#endif
    new->references = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(new->lock_references);
+#endif
 
    evas_cache_image_drop(im);
 
@@ -1314,7 +1501,13 @@ evas_cache_image_empty(Evas_Cache_Image *cache)
    im = _evas_cache_image_entry_new(cache, NULL, 0, NULL, NULL, NULL, NULL);
    if (!im) return NULL;
 
+#ifdef EVAS_FRAME_QUEUING
+   LKL(im->lock_references);
+#endif
    im->references = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKU(im->lock_references);
+#endif
    return im;
 }
 
index c60cb21..5c7e606 100644 (file)
@@ -48,6 +48,9 @@ evas_init(void)
 #ifdef BUILD_ASYNC_PRELOAD
    _evas_preload_thread_init();
 #endif
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_frameq_init();
+#endif
 
    return _evas_init_count;
 
@@ -84,6 +87,13 @@ evas_shutdown(void)
    if (--_evas_init_count != 0)
      return _evas_init_count;
 
+#ifdef EVAS_FRAME_QUEUING
+   if (evas_common_frameq_enabled())
+     {
+        evas_common_frameq_finish();
+        evas_common_frameq_destroy();
+     }
+#endif
 #ifdef BUILD_ASYNC_EVENTS
    _evas_preload_thread_shutdown();
 #endif
@@ -180,6 +190,10 @@ evas_free(Evas *e)
    return;
    MAGIC_CHECK_END();
 
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_frameq_flush();
+#endif
+
    if (e->walking_list == 0) evas_render_idle_flush(e);
    
    if (e->walking_list > 0) return;
@@ -424,6 +438,11 @@ evas_output_size_set(Evas *e, int w, int h)
    if ((w == e->output.w) && (h == e->output.h)) return;
    if (w < 1) w = 1;
    if (h < 1) h = 1;
+
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_frameq_flush();
+#endif
+
    e->output.w = w;
    e->output.h = h;
    e->output.changed = 1;
index 54b50c9..73dbc9f 100644 (file)
@@ -147,9 +147,15 @@ evas_object_gradient_color_stop_add(Evas_Object *obj, int r, int g, int b, int a
    return;
    MAGIC_CHECK_END();
    if (o->engine_data)
-      obj->layer->evas->engine.func->gradient_color_stop_add(obj->layer->evas->engine.data.output,
-                                                            o->engine_data,
-                                                            r, g, b, a, delta);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad_flush(o->engine_data);
+#endif
+
+        obj->layer->evas->engine.func->gradient_color_stop_add(obj->layer->evas->engine.data.output,
+                           o->engine_data,
+                           r, g, b, a, delta);
+     }
    o->gradient_changed = 1;
    o->changed = 1;
    evas_object_change(obj);
@@ -180,8 +186,13 @@ evas_object_gradient_alpha_stop_add(Evas_Object *obj, int a, int delta)
    return;
    MAGIC_CHECK_END();
    if (o->engine_data)
-      obj->layer->evas->engine.func->gradient_alpha_stop_add(obj->layer->evas->engine.data.output,
-                                                            o->engine_data, a, delta);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad_flush(o->engine_data);
+#endif
+        obj->layer->evas->engine.func->gradient_alpha_stop_add(obj->layer->evas->engine.data.output,
+                     o->engine_data, a, delta);
+     }
    o->gradient_changed = 1;
    o->changed = 1;
    evas_object_change(obj);
@@ -204,8 +215,13 @@ evas_object_gradient_clear(Evas_Object *obj)
    return;
    MAGIC_CHECK_END();
    if (o->engine_data)
-      obj->layer->evas->engine.func->gradient_clear(obj->layer->evas->engine.data.output,
-                                                   o->engine_data);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad_flush(o->engine_data);
+#endif
+        obj->layer->evas->engine.func->gradient_clear(obj->layer->evas->engine.data.output,
+                        o->engine_data);
+     }
    o->gradient_changed = 1;
    o->changed = 1;
    o->cur.gradient_opaque = 0;
@@ -236,9 +252,14 @@ evas_object_gradient_color_data_set(Evas_Object *obj, void *data, int len, Eina_
    return;
    MAGIC_CHECK_END();
    if (o->engine_data)
-       obj->layer->evas->engine.func->gradient_color_data_set(obj->layer->evas->engine.data.output,
-                                                               o->engine_data,
-                                                               data, len, has_alpha);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad_flush(o->engine_data);
+#endif
+        obj->layer->evas->engine.func->gradient_color_data_set(obj->layer->evas->engine.data.output,
+                        o->engine_data,
+                        data, len, has_alpha);
+     }
    o->gradient_changed = 1;
    o->changed = 1;
    evas_object_change(obj);
@@ -267,9 +288,14 @@ evas_object_gradient_alpha_data_set(Evas_Object *obj, void *data, int len)
    return;
    MAGIC_CHECK_END();
    if (o->engine_data)
-       obj->layer->evas->engine.func->gradient_alpha_data_set(obj->layer->evas->engine.data.output,
-                                                               o->engine_data,
-                                                               data, len);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad_flush(o->engine_data);
+#endif
+        obj->layer->evas->engine.func->gradient_alpha_data_set(obj->layer->evas->engine.data.output,
+                        o->engine_data,
+                        data, len);
+     }
    o->gradient_changed = 1;
    o->changed = 1;
    evas_object_change(obj);
index ab003ce..6511aa5 100644 (file)
@@ -53,9 +53,15 @@ evas_object_gradient2_color_np_stop_insert(Evas_Object *obj, int r, int g, int b
    MAGIC_CHECK_END();
    engine_data = obj->func->engine_data_get(obj);
    if (engine_data)
-      obj->layer->evas->engine.func->gradient2_color_np_stop_insert(obj->layer->evas->engine.data.output,
-                                                            engine_data,
-                                                            r, g, b, a, pos);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad2_flush(engine_data);
+#endif
+
+        obj->layer->evas->engine.func->gradient2_color_np_stop_insert(obj->layer->evas->engine.data.output,
+                           engine_data,
+                           r, g, b, a, pos);
+     }
    og->gradient_changed = 1;
    evas_object_change(obj);
 }
@@ -79,8 +85,13 @@ evas_object_gradient2_clear(Evas_Object *obj)
    MAGIC_CHECK_END();
    engine_data = obj->func->engine_data_get(obj);
    if (engine_data)
-      obj->layer->evas->engine.func->gradient2_clear(obj->layer->evas->engine.data.output,
-                                                    engine_data);
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_grad2_flush(engine_data);
+#endif
+        obj->layer->evas->engine.func->gradient2_clear(obj->layer->evas->engine.data.output,
+                        engine_data);
+     }
    og->gradient_changed = 1;
    og->cur.gradient_opaque = 0;
    evas_object_change(obj);
index 233c5d8..109af58 100644 (file)
@@ -960,6 +960,9 @@ evas_object_image_data_set(Evas_Object *obj, void *data)
    MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
    return;
    MAGIC_CHECK_END();
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_pipe_op_image_flush(o->engine_data);
+#endif
    p_data = o->engine_data;
    if (data)
      {
@@ -1031,6 +1034,10 @@ evas_object_image_data_get(const Evas_Object *obj, Eina_Bool for_writing)
    return NULL;
    MAGIC_CHECK_END();
    if (!o->engine_data) return NULL;
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_pipe_op_image_flush(o->engine_data);
+#endif
+
    data = NULL;
    o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output,
                                                                  o->engine_data,
@@ -1202,9 +1209,14 @@ evas_object_image_alpha_set(Evas_Object *obj, Eina_Bool has_alpha)
      return;
    o->cur.has_alpha = has_alpha;
    if (o->engine_data)
-     o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
+     {
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_pipe_op_image_flush(o->engine_data);
+#endif
+        o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output,
                                                                     o->engine_data,
                                                                     o->cur.has_alpha);
+     }
    evas_object_image_data_update_add(obj, 0, 0, o->cur.image.w, o->cur.image.h);
    EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o);
 }
@@ -1810,6 +1822,13 @@ evas_object_image_colorspace_set(Evas_Object *obj, Evas_Colorspace cspace)
    MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
    return;
    MAGIC_CHECK_END();
+
+#ifdef EVAS_FRAME_QUEUING
+   if (o->cur.cspace != cspace)
+      if (o->engine_data)
+         evas_common_pipe_op_image_flush(o->engine_data);
+#endif
+
    o->cur.cspace = cspace;
    if (o->engine_data)
      obj->layer->evas->engine.func->image_colorspace_set(obj->layer->evas->engine.data.output,
@@ -1913,6 +1932,11 @@ evas_object_image_scale_hint_set(Evas_Object *obj, Evas_Image_Scale_Hint hint)
    MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
    return;
    MAGIC_CHECK_END();
+#ifdef EVAS_FRAME_QUEUING
+   if (o->scale_hint != hint)
+      if (o->engine_data)
+         evas_common_pipe_op_image_flush(o->engine_data);
+#endif
    o->scale_hint = hint;
 }
 
index 8173d4a..1cbb9aa 100644 (file)
@@ -368,6 +368,10 @@ evas_object_del(Evas_Object *obj)
 
    if (obj->delete_me) return;
 
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_frameq_flush();
+#endif
+
    _evas_object_event_new();
 
    evas_object_event_callback_call(obj, EVAS_CALLBACK_DEL, NULL);
index 575b449..1b89f7e 100644 (file)
@@ -195,6 +195,12 @@ evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size siz
                                              obj->layer->evas->pointer.x,
                                              obj->layer->evas->pointer.y, 1, 1);
      }
+
+#ifdef EVAS_FRAME_QUEUING
+   if (o->engine_data)
+      evas_common_pipe_op_text_flush(o->engine_data);
+#endif
+
    /* DO IT */
    if (o->engine_data)
      {
@@ -1102,6 +1108,7 @@ evas_font_hinting_set(Evas *e, Evas_Font_Hinting_Flags hinting)
    MAGIC_CHECK_END();
    if (e->hinting == hinting) return;
    e->hinting = hinting;
+
    EINA_INLIST_FOREACH(e->layers, lay)
      {
        Evas_Object *obj;
@@ -1834,6 +1841,9 @@ _evas_object_text_rehint(Evas_Object *obj)
 
    o = (Evas_Object_Text *)(obj->object_data);
    if (!o->engine_data) return;
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_pipe_op_text_flush(o->engine_data);
+#endif
    evas_font_load_hinting_set(obj->layer->evas, o->engine_data,
                              obj->layer->evas->hinting);
    was = evas_object_is_in_output_rect(obj,
index 50f5295..ca0fd87 100644 (file)
@@ -6027,9 +6027,14 @@ _evas_object_textblock_rehint(Evas_Object *obj)
        EINA_INLIST_FOREACH(ln->items, it)
          {
             if (it->format->font.font)
-              evas_font_load_hinting_set(obj->layer->evas,
-                                         it->format->font.font,
+            {  
+#ifdef EVAS_FRAME_QUEUING
+               evas_common_pipe_op_text_flush(it->format->font.font);
+#endif
+                 evas_font_load_hinting_set(obj->layer->evas,
+                                         it->format->font.font,
                                          obj->layer->evas->hinting);
+              }
          }
      }
    o->formatted.valid = 0;
index e871e9e..a30f32c 100644 (file)
@@ -245,8 +245,13 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj,
    obj->rect_del = 0;
    obj->render_pre = 0;
 
+#ifndef EVAS_FRAME_QUEUING
    /* because of clip objects - delete 2 cycles later */
-   if (obj->delete_me == 2) eina_array_push(delete_objects, obj);
+   if (obj->delete_me == 2)
+#else
+   if (obj->delete_me == evas_common_frameq_get_frameq_sz() + 2)
+#endif
+        eina_array_push(delete_objects, obj);
    else if (obj->delete_me != 0) obj->delete_me++;
    /* If the object will be removed, we should not cache anything during this run. */
    if (obj->delete_me != 0) clean_them = EINA_TRUE;
@@ -1236,6 +1241,10 @@ evas_render_updates(Evas *e)
    return NULL;
    MAGIC_CHECK_END();
 
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_frameq_flush_ready ();
+#endif
+
    if (!e->changed) return NULL;
    return evas_render_updates_internal(e, 1, 1);
 }
@@ -1254,6 +1263,10 @@ evas_render(Evas *e)
    return;
    MAGIC_CHECK_END();
 
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_frameq_flush_ready ();
+#endif
+
    if (!e->changed) return;
    evas_render_updates_internal(e, 0, 1);
 }
@@ -1316,6 +1329,18 @@ evas_render_idle_flush(Evas *e)
    e->invalidate = 1;
 }
 
+EAPI void
+evas_sync(Evas *e)
+{
+#ifdef EVAS_FRAME_QUEUING
+   MAGIC_CHECK(e, Evas, MAGIC_EVAS);
+   return;
+   MAGIC_CHECK_END();
+
+   evas_common_frameq_flush ();
+#endif
+}
+
 /**
  * Make the canvas discard as much data as possible used by the engine at
  * runtime.
@@ -1393,12 +1418,19 @@ evas_render_object_recalc(Evas_Object *obj)
    return;
    MAGIC_CHECK_END();
 
+#ifndef EVAS_FRAME_QUEUING
    if ((!obj->changed) && (obj->delete_me < 2))
+#else
+   if ((!obj->changed) )
+#endif
      {
        Evas *e;
 
        e = obj->layer->evas;
        if ((!e) || (e->cleanup)) return;
+#ifdef EVAS_FRAME_QUEUING
+   if (obj->delete_me >= evas_common_frameq_get_frameq_sz() + 2) return;
+#endif
         eina_array_push(&e->pending_objects, obj);
        obj->changed = 1;
      }
index f8669ae..b0d0d35 100644 (file)
@@ -90,6 +90,7 @@ evas_convert_rgb_8.h \
 evas_convert_yuv.h \
 evas_draw.h \
 evas_font.h \
+evas_font_private.h \
 evas_gradient.h \
 evas_gradient_private.h \
 evas_image.h \
index 87372de..d629718 100644 (file)
@@ -7,7 +7,23 @@
 #include "evas_blend_private.h"
 
 #include "evas_intl_utils.h" /*defines INTERNATIONAL_SUPPORT if possible */
+#include "evas_font_private.h" /* for Frame-Queuing support */
 
+#ifdef EVAS_FRAME_QUEUING
+EAPI void
+evas_common_font_draw_init(void)
+{
+   LKI(lock_font_draw);
+   LKI(lock_fribidi);
+}
+
+EAPI void
+evas_common_font_draw_finish(void)
+{
+   LKD(lock_font_draw);
+   LKD(lock_fribidi);
+}
+#endif
 
 static void
 _fash_int_free(Fash_Int *fash)
@@ -123,9 +139,11 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
 //   fg = eina_hash_find(fi->glyphs, &hindex);
 //   if (fg) return fg;
 
+   FTLOCK();
 //   error = FT_Load_Glyph(fi->src->ft.face, index, FT_LOAD_NO_BITMAP);
    error = FT_Load_Glyph(fi->src->ft.face, index,
                         FT_LOAD_RENDER | hintflags[fi->hinting]);
+   FTUNLOCK();
    if (error)
      {
         if (!fi->fash) fi->fash = _fash_gl_new();
@@ -137,7 +155,9 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
    if (!fg) return NULL;
    memset(fg, 0, (sizeof(struct _RGBA_Font_Glyph)));
 
+   FTLOCK();
    error = FT_Get_Glyph(fi->src->ft.face->glyph, &(fg->glyph));
+   FTUNLOCK();
    if (error)
      {
        free(fg);
@@ -147,15 +167,18 @@ evas_common_font_int_cache_glyph_get(RGBA_Font_Int *fi, FT_UInt index)
      }
    if (fg->glyph->format != FT_GLYPH_FORMAT_BITMAP)
      {
+        FTLOCK();
        error = FT_Glyph_To_Bitmap(&(fg->glyph), FT_RENDER_MODE_NORMAL, 0, 1);
        if (error)
          {
             FT_Done_Glyph(fg->glyph);
+        FTUNLOCK();
             free(fg);
              if (!fi->fash) fi->fash = _fash_gl_new();
              if (fi->fash) _fash_gl_add(fi->fash, index, (void *)(-1));
             return NULL;
          }
+   FTUNLOCK();
      }
    fg->glyph_out = (FT_BitmapGlyph)fg->glyph;
    fg->index = hindex;
@@ -180,6 +203,7 @@ static FT_UInt
 _evas_common_get_char_index(RGBA_Font_Int* fi, int gl)
 {
    Font_Char_Index result;
+   FT_UInt ret;
 
 #ifdef HAVE_PTHREAD
 ///   pthread_mutex_lock(&fi->ft_mutex);
@@ -197,7 +221,9 @@ _evas_common_get_char_index(RGBA_Font_Int* fi, int gl)
 //     return FT_Get_Char_Index(fi->src->ft.face, gl);
 //     }
 
+   FTLOCK();
    result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
+   FTUNLOCK();
    result.gl = gl;
 
 //   eina_hash_direct_add(fi->indexes, &result->gl, result);
@@ -583,7 +609,9 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int
    if (ext_w <= 0) return;
    if (ext_h <= 0) return;
 
+#ifndef EVAS_FRAME_QUEUING
    LKL(fn->lock);
+#endif
 //   evas_common_font_size_use(fn);
    use_kerning = FT_HAS_KERNING(fi->src->ft.face);
    func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst, 1, dc->render_op);
@@ -616,5 +644,7 @@ evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font *fn, int
           }
         dc->clip.use = c; dc->clip.x = cx; dc->clip.y = cy; dc->clip.w = cw; dc->clip.h = ch;
      }
+#ifndef EVAS_FRAME_QUEUING
    LKU(fn->lock);
+#endif
 }
index d754cf0..a6b07e1 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <assert.h>
 
+#include "evas_font_private.h" /* for Frame-Queuing support */
+
 extern FT_Library         evas_ft_lib;
 
 static int                font_cache_usage = 0;
@@ -45,7 +47,9 @@ _evas_font_cache_int_hash(const RGBA_Font_Int *key, int key_length __UNUSED__)
 static void
 _evas_common_font_source_free(RGBA_Font_Source *fs)
 {
+   FTLOCK();
    FT_Done_Face(fs->ft.face);
+   FTUNLOCK();
 #if 0 /* FIXME: Disable as it is only used by dead code using deprecated datatype. */
 //   if (fs->charmap) evas_array_hash_free(fs->charmap);
 #endif
@@ -59,7 +63,9 @@ font_flush_free_glyph_cb(const Eina_Hash *hash, const void *key, void *data, voi
    RGBA_Font_Glyph *fg;
 
    fg = data;
+   FTLOCK();
    FT_Done_Glyph(fg->glyph);
+   FTUNLOCK();
    // extension calls
    if (fg->ext_dat_free) fg->ext_dat_free(fg->ext_dat);
    free(fg);
@@ -137,7 +143,9 @@ evas_common_font_source_memory_load(const char *name, const void *data, int data
    fs->data_size = data_size;
    fs->current_size = 0;
    memcpy(fs->data, data, data_size);
+   FTLOCK();
    error = FT_New_Memory_Face(evas_ft_lib, fs->data, fs->data_size, 0, &(fs->ft.face));
+   FTUNLOCK();
    if (error)
      {
        free(fs);
@@ -145,7 +153,9 @@ evas_common_font_source_memory_load(const char *name, const void *data, int data
      }
    fs->name = eina_stringshare_add(name);
    fs->file = NULL;
+   FTLOCK();
    error = FT_Select_Charmap(fs->ft.face, ft_encoding_unicode);
+   FTUNLOCK();
    fs->ft.orig_upem = fs->ft.face->units_per_EM;
    fs->references = 1;
 
@@ -183,9 +193,11 @@ evas_common_font_source_load_complete(RGBA_Font_Source *fs)
 {
    int error;
 
+   FTLOCK();
    error = FT_New_Face(evas_ft_lib, fs->file, 0, &(fs->ft.face));
    if (error)
      {
+        FTUNLOCK();
        fs->ft.face = NULL;
        return error;
      }
@@ -194,10 +206,12 @@ evas_common_font_source_load_complete(RGBA_Font_Source *fs)
    if (error)
      {
        FT_Done_Face(fs->ft.face);
+   FTUNLOCK();
        fs->ft.face = NULL;
        return error;
      }
 
+   FTUNLOCK();
    fs->ft.orig_upem = fs->ft.face->units_per_EM;
    return error;
 }
@@ -236,7 +250,9 @@ evas_common_font_size_use(RGBA_Font *fn)
      {
        if (fi->src->current_size != fi->size)
          {
+        FTLOCK();
             FT_Activate_Size(fi->ft.size);
+        FTUNLOCK();
             fi->src->current_size = fi->size;
          }
      }
@@ -369,6 +385,7 @@ evas_common_font_int_load_complete(RGBA_Font_Int *fi)
    int ret;
    int error;
 
+   FTLOCK();
    error = FT_New_Size(fi->src->ft.face, &(fi->ft.size));
    if (!error)
      {
@@ -381,6 +398,7 @@ evas_common_font_int_load_complete(RGBA_Font_Int *fi)
        fi->real_size = fi->size;
        error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
      }
+   FTUNLOCK();
    if (error)
      {
        int i;
@@ -405,7 +423,9 @@ evas_common_font_int_load_complete(RGBA_Font_Int *fi)
             if (d == 0) break;
          }
        fi->real_size = chosen_size;
+   FTLOCK();
        error = FT_Set_Pixel_Sizes(fi->src->ft.face, chosen_width, fi->real_size);
+   FTUNLOCK();
        if (error)
          {
             /* couldn't choose the size anyway... what now? */
@@ -457,6 +477,11 @@ evas_common_font_memory_load(const char *name, int size, const void *data, int d
    fi->hinting = fn->hinting;
    fn->references = 1;
    LKI(fn->lock);
+#ifdef EVAS_FRAME_QUEUING
+   LKI(fn->ref_fq_add);
+   LKI(fn->ref_fq_del);
+   pthread_cond_init(&(fn->cond_fq_del), NULL);
+#endif
    return fn;
 }
 
@@ -506,6 +531,11 @@ evas_common_font_load(const char *name, int size)
    fi->hinting = fn->hinting;
    fn->references = 1;
    LKI(fn->lock);
+#ifdef EVAS_FRAME_QUEUING
+   LKI(fn->ref_fq_add);
+   LKI(fn->ref_fq_del);
+   pthread_cond_init(&(fn->cond_fq_del), NULL);
+#endif
    return fn;
 }
 
@@ -552,6 +582,19 @@ evas_common_font_free(RGBA_Font *fn)
    if (!fn) return;
    fn->references--;
    if (fn->references > 0) return;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(fn->ref_fq_add);
+   LKL(fn->ref_fq_del);
+   if (fn->ref_fq[0] != fn->ref_fq[1])
+     {
+        LKU(fn->ref_fq_add);
+        LKU(fn->ref_fq_del);
+        return;
+     }
+   LKU(fn->ref_fq_add);
+   LKU(fn->ref_fq_del);
+#endif
+
    EINA_LIST_FOREACH(fn->fonts, l, fi)
      {
        fi->references--;
@@ -565,6 +608,12 @@ evas_common_font_free(RGBA_Font *fn)
    eina_list_free(fn->fonts);
    if (fn->fash) fn->fash->freeme(fn->fash);
    LKD(fn->lock);
+#ifdef EVAS_FRAME_QUEUING
+   LKD(fn->ref_fq_add);
+   LKD(fn->ref_fq_del);
+   pthread_cond_destroy(&(fn->cond_fq_del));
+#endif
+
    free(fn);
 }
 
index afe1b11..d1aa51e 100644 (file)
@@ -17,6 +17,9 @@ evas_common_font_init(void)
    error = FT_Init_FreeType(&evas_ft_lib);
    if (error) return;
    evas_common_font_load_init();
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_font_draw_init();
+#endif
 }
 
 EAPI void
@@ -33,6 +36,9 @@ evas_common_font_shutdown(void)
    evas_common_font_flush();
 
    error = FT_Done_FreeType(evas_ft_lib);
+#ifdef EVAS_FRAME_QUEUING
+   evas_common_font_draw_finish();
+#endif
    evas_ft_lib = 0;
 }
 
diff --git a/src/lib/engines/common/evas_font_private.h b/src/lib/engines/common/evas_font_private.h
new file mode 100644 (file)
index 0000000..12ab17b
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef _EVAS_FONT_PRIVATE_H
+#define _EVAS_FONT_PRIVATE_H
+
+LK(lock_font_draw);    // for freetype2 API calls
+LK(lock_fribidi);              // for fribidi API calls
+
+#ifdef EVAS_FRAME_QUEUING
+#define FTLOCK() LKL(lock_font_draw)
+#define FTUNLOCK() LKU(lock_font_draw)
+
+#define FBDLOCK() LKL(lock_fribidi)
+#define FBDUNLOCK() LKU(lock_fribidi)
+#else
+#define FTLOCK(x) 
+#define FTUNLOCK(x) 
+
+#define FBDLOCK() 
+#define FBDUNLOCK() 
+#endif
+
+#endif /* !_EVAS_FONT_PRIVATE_H */
+
+#ifndef _EVAS_FONT_PRIVATE_H
+#define _EVAS_FONT_PRIVATE_H
+
+LK(lock_font_draw);    // for freetype2 API calls
+LK(lock_fribidi);              // for fribidi API calls
+
+#ifdef EVAS_FRAME_QUEUING
+#define FTLOCK() LKL(lock_font_draw)
+#define FTUNLOCK() LKU(lock_font_draw)
+
+#define FBDLOCK() LKL(lock_fribidi)
+#define FBDUNLOCK() LKU(lock_fribidi)
+#else
+#define FTLOCK(x) 
+#define FTUNLOCK(x) 
+
+#define FBDLOCK() 
+#define FBDUNLOCK() 
+#endif
+
+#endif /* !_EVAS_FONT_PRIVATE_H */
+
+#ifndef _EVAS_FONT_PRIVATE_H
+#define _EVAS_FONT_PRIVATE_H
+
+LK(lock_font_draw);    // for freetype2 API calls
+LK(lock_fribidi);              // for fribidi API calls
+
+#ifdef EVAS_FRAME_QUEUING
+#define FTLOCK() LKL(lock_font_draw)
+#define FTUNLOCK() LKU(lock_font_draw)
+
+#define FBDLOCK() LKL(lock_fribidi)
+#define FBDUNLOCK() LKU(lock_fribidi)
+#else
+#define FTLOCK(x) 
+#define FTUNLOCK(x) 
+
+#define FBDLOCK() 
+#define FBDUNLOCK() 
+#endif
+
+#endif /* !_EVAS_FONT_PRIVATE_H */
+
+#ifndef _EVAS_FONT_PRIVATE_H
+#define _EVAS_FONT_PRIVATE_H
+
+LK(lock_font_draw);
+
+#ifdef EVAS_FRAME_QUEUING
+#define FTLOCK() LKL(lock_font_draw)
+#define FTUNLOCK() LKU(lock_font_draw)
+#else
+#define FTLOCK(x) 
+#define FTUNLOCK(x) 
+#endif
+
+#endif /* !_EVAS_FONT_PRIVATE_H */
+
index c626612..d1b2f99 100644 (file)
@@ -1,5 +1,6 @@
 #include "evas_common.h"
 #include "evas_intl_utils.h" /*defines INTERNATIONAL_SUPPORT if possible */
+#include "evas_font_private.h" /* for Frame-Queuing support */
 
 EAPI int
 evas_common_font_query_kerning(RGBA_Font_Int* fi,
@@ -26,12 +27,14 @@ evas_common_font_query_kerning(RGBA_Font_Int* fi,
     * values to kern by - given same font, same size and same
     * prev_index and index. auto/bytecode or none hinting doesnt
     * matter */
+   FTLOCK();
    if (FT_Get_Kerning(fi->src->ft.face,
                      key[0], key[1],
                      ft_kerning_default, &delta) == 0)
      {
        int *push;
 
+        FTUNLOCK();
        *kerning = delta.x >> 6;
 
        push = malloc(sizeof (int) * 3);
@@ -46,6 +49,7 @@ evas_common_font_query_kerning(RGBA_Font_Int* fi,
        goto on_correct;
      }
 
+        FTUNLOCK();
    error = 0;
 
  on_correct:
@@ -188,7 +192,9 @@ evas_common_font_query_advance(RGBA_Font *fn, const char *text, int *h_adv, int
    pen_x = 0;
    pen_y = 0;
 //   evas_common_font_size_use(fn);
+   FTLOCK();
    use_kerning = FT_HAS_KERNING(fi->src->ft.face);
+   FTUNLOCK();
    prev_index = 0;
    for (chr = 0; text[chr];)
      {
index e2b0d97..5d3893e 100644 (file)
@@ -68,6 +68,15 @@ evas_common_gradient2_free(RGBA_Gradient2 *gr)
    if (!gr) return;
    gr->references--;
    if (gr->references > 0) return;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(gr->ref_fq_add);  LKL(gr->ref_fq_del);
+   if (gr->ref_fq[0] != gr->ref_fq[1])
+     {
+        LKU(gr->ref_fq_add); LKU(gr->ref_fq_del);
+        return;
+     }
+   LKU(gr->ref_fq_add); LKU(gr->ref_fq_del);
+#endif
    evas_common_gradient2_clear(gr);
    if (gr->stops.cdata) free(gr->stops.cdata);
    if (gr->stops.adata) free(gr->stops.adata);
index 3d11fba..9aa9b67 100644 (file)
@@ -160,6 +160,15 @@ evas_common_gradient_free(RGBA_Gradient *gr)
    if (!gr) return;
    gr->references--;
    if (gr->references > 0) return;
+#ifdef EVAS_FRAME_QUEUING
+        LKL(gr->ref_fq_add);  LKL(gr->ref_fq_del);
+        if (gr->ref_fq[0] != gr->ref_fq[1])
+          {
+             LKU(gr->ref_fq_add); LKU(gr->ref_fq_del);
+             return;
+          }
+       LKU(gr->ref_fq_add); LKU(gr->ref_fq_del);
+#endif
    evas_common_gradient_clear(gr);
    if (gr->type.name) free(gr->type.name);
    if (gr->type.params) free(gr->type.params);
index 899a769..a86962e 100644 (file)
@@ -141,6 +141,12 @@ _evas_common_rgba_image_new(void)
    if (!im) return NULL;
    im->flags = RGBA_IMAGE_NOTHING;
    im->ref = 1;
+#ifdef EVAS_FRAME_QUEUING
+   LKI(im->ref_fq_add);
+   LKI(im->ref_fq_del);
+   pthread_cond_init(&(im->cond_fq_del), NULL);
+#endif
+
    evas_common_rgba_image_scalecache_init(&im->cache_entry);
    return &im->cache_entry;
 }
@@ -152,6 +158,11 @@ _evas_common_rgba_image_delete(Image_Entry *ie)
 
 #ifdef BUILD_PIPE_RENDER
    evas_common_pipe_free(im);
+# ifdef EVAS_FRAME_QUEUING
+   LKD(im->ref_fq_add);
+   LKD(im->ref_fq_del);
+   pthread_cond_destroy(&(im->cond_fq_del));
+# endif
 #endif   
    evas_common_rgba_image_scalecache_shutdown(&im->cache_entry);
    if (ie->info.module) evas_module_unref((Evas_Module *)ie->info.module);
index 4391beb..71ae93e 100644 (file)
@@ -40,6 +40,9 @@ struct _Scaleitem
    int dst_w, dst_h;
    int flop;
    int size_adjust;
+#ifdef EVAS_FRAME_QUEUING
+   RWLK(lock);
+#endif
    Eina_Bool forced_unload : 1;
    Eina_Bool smooth : 1;
    Eina_Bool populate_me : 1;
@@ -90,7 +93,8 @@ evas_common_scalecache_shutdown(void)
 {
 #ifdef SCALECACHE
    init--;
-   LKD(cache_lock);
+   if (init ==0)
+      LKD(cache_lock);
 #endif
 }
 
@@ -123,6 +127,9 @@ evas_common_rgba_image_scalecache_dirty(Image_Entry *ie)
      {
         Scaleitem *sci;
         sci = im->cache.list->data;
+#ifdef EVAS_FRAME_QUEUING
+        WRLKL(sci->lock);
+#endif
         im->cache.list = eina_list_remove(im->cache.list, sci);
         if (sci->im)
           {
@@ -136,6 +143,10 @@ evas_common_rgba_image_scalecache_dirty(Image_Entry *ie)
              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
              LKU(cache_lock);
           }
+#ifdef EVAS_FRAME_QUEUING
+         RWLKU(sci->lock);
+         RWLKD(sci->lock);
+#endif
         free(sci);
      }
    LKU(im->cache.lock);
@@ -230,6 +241,9 @@ _sci_find(RGBA_Image *im,
      {
         l = eina_list_last(im->cache.list);
         sci = l->data;
+#ifdef EVAS_FRAME_QUEUING
+        WRLKL(sci->lock);
+#endif
         im->cache.list = eina_list_remove_list(im->cache.list, l);
         if ((sci->usage == im->cache.newest_usage) ||
             (sci->usage_count == im->cache.newest_usage_count))
@@ -244,6 +258,9 @@ _sci_find(RGBA_Image *im,
 //             INF(" 1- %i", sci->dst_w * sci->dst_h * 4);
              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
           }
+#ifdef EVAS_FRAME_QUEUING
+        RWLKU(sci->lock);
+#endif
         if (max_scale_items < 1) return NULL;
      }
    else
@@ -255,6 +272,9 @@ _sci_find(RGBA_Image *im,
         sci = malloc(sizeof(Scaleitem));
         memset(sci, 0, sizeof(Eina_Inlist));
         sci->parent_im = im;
+#ifdef EVAS_FRAME_QUEUING
+        RWLKI(sci->lock);
+#endif
      }
    sci->usage = 0;
    sci->usage_count = 0;
@@ -288,6 +308,9 @@ _cache_prune(Scaleitem *notsci, Eina_Bool copies_only)
              if (!sci) return;
           }
         if (sci == notsci) return;
+#ifdef EVAS_FRAME_QUEUING
+        WRLKL(sci->lock);
+#endif
         if (sci->im)
           {
              evas_common_rgba_image_free(&sci->im->cache_entry);
@@ -303,6 +326,10 @@ _cache_prune(Scaleitem *notsci, Eina_Bool copies_only)
              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
              memset(sci, 0, sizeof(Eina_Inlist));
           }
+#ifdef EVAS_FRAME_QUEUING
+        RWLKU(sci->lock);
+#endif
+
 //        INF("FLUSH %i > %i", cache_size, max_cache_size);
       }
 }
@@ -467,9 +494,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
    LKL(im->cache.lock);
    if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
      {
-        if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
-          evas_cache_image_load_data(&im->cache_entry);
-        evas_common_image_colorspace_normalize(im);
+#ifdef EVAS_FRAME_QUEUING
+        if (!evas_common_frameq_enabled())
+#endif
+         {
+            if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+               evas_cache_image_load_data(&im->cache_entry);
+            evas_common_image_colorspace_normalize(im);
+         }
 //        noscales++;
         LKU(im->cache.lock);
         if (im->image.data)
@@ -496,9 +528,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
    LKU(cache_lock);
    if (!sci)
      {
-        if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
-          evas_cache_image_load_data(&im->cache_entry);
-        evas_common_image_colorspace_normalize(im);
+#ifdef EVAS_FRAME_QUEUING
+        if (!evas_common_frameq_enabled())
+#endif
+          {
+             if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+                evas_cache_image_load_data(&im->cache_entry);
+             evas_common_image_colorspace_normalize(im);
+          }
 //        misses++;
         LKU(im->cache.lock);
         if (im->image.data)
@@ -656,6 +693,9 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
              if (sci->flop > 0) sci->flop -= FLOP_DEL;
           }
 //        INF("use cached!");
+#ifdef EVAS_FRAME_QUEUING
+        RDLKL(sci->lock);
+#endif
         LKU(im->cache.lock);
         evas_common_scale_rgba_in_to_out_clip_sample
           (sci->im, dst, dc,
@@ -663,11 +703,22 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
            dst_region_w, dst_region_h,
            dst_region_x, dst_region_y, 
            dst_region_w, dst_region_h);
+#ifdef EVAS_FRAME_QUEUING
+        RWLKU(sci->lock);
+#endif
 //        hits++;
 //        INF("check %p %i < %i", 
 //               im,
 //               (int)im->cache.orig_usage, 
 //               (int)im->cache.newest_usage);
+#ifndef EVAS_FRAME_QUEUING
+        /* while framequeuing is applied,
+         * original image data is loaded by the main thread 
+         * just before enqueuing the rendering op into the pipe.
+         * so unloading the original image data here 
+         * causes only speed-down side-effect and no memory usage gain;
+         * it will be loaded again for the very next rendering for this image.
+         */
         if ((dounload) || 
             ((im->cache_entry.flags.loaded) && 
              ((!im->cs.no_free) 
@@ -683,12 +734,18 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
                   evas_common_rgba_image_unload(&im->cache_entry);
                }
           }
+#endif
      }
    else
      {
-        if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
-          evas_cache_image_load_data(&im->cache_entry);
-        evas_common_image_colorspace_normalize(im);
+#ifdef EVAS_FRAME_QUEUING
+        if (!evas_common_frameq_enabled())
+#endif
+          {
+             if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+                evas_cache_image_load_data(&im->cache_entry);
+             evas_common_image_colorspace_normalize(im);
+          }
 //        misses++;
         LKU(im->cache.lock);
         if (im->image.data)
@@ -709,9 +766,14 @@ evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
      }
 #else   
    RGBA_Image *im = (RGBA_Image *)ie;
-   if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
-     evas_cache_image_load_data(&im->cache_entry);
-   evas_common_image_colorspace_normalize(im);
+#ifdef EVAS_FRAME_QUEUING
+   if (!evas_common_frameq_enabled())
+#endif
+     {
+        if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+           evas_cache_image_load_data(&im->cache_entry);
+        evas_common_image_colorspace_normalize(im);
+     }
    if (im->image.data)
      {
         if (smooth)
index 90ccfcb..0cf5212 100644 (file)
@@ -4,6 +4,8 @@
 #include "evas_common.h"
 #include "evas_intl_utils.h"
 
+#include "evas_font_private.h"
+
 #ifdef INTERNATIONAL_SUPPORT
 #include <fribidi/fribidi.h>
 
@@ -41,10 +43,12 @@ evas_intl_utf8_to_visual(const char *text,
    if (!unicode_in)
      {
        len = -1;
-       goto error1;
+        goto error1;
      }
 
+   FBDLOCK();
    len = fribidi_utf8_to_unicode(text, byte_len, unicode_in);
+   FBDUNLOCK();
    unicode_in[len] = 0;
 
    unicode_out = (FriBidiChar *)alloca(sizeof(FriBidiChar) * (len + 1));
@@ -109,7 +113,8 @@ evas_intl_utf8_to_visual(const char *text,
      }
 
    fribidi_unicode_to_utf8(unicode_out, len, text_out);
-
+   FBDUNLOCK();
+   
    *ret_len = len;
    return text_out;
 
index bafb95a..b2f686a 100644 (file)
@@ -7,6 +7,209 @@
 #include "evas_common.h"
 
 #ifdef BUILD_PIPE_RENDER
+
+#ifdef EVAS_FRAME_QUEUING
+#define SCALECACHE
+static Evas_FrameQ gframeq;    // global frameQ
+
+static Evas_Surface *
+evas_common_surface_alloc(void *surface, int x, int y, int w, int h)
+{
+   Evas_Surface *e_surface;
+
+   e_surface = calloc(1, sizeof(Evas_Surface));
+   e_surface->im = surface;
+   LKL(e_surface->im->ref_fq_add);
+   e_surface->im->ref_fq[0]++;
+   LKU(e_surface->im->ref_fq_add);
+   e_surface->x = x;
+   e_surface->y = y;
+   e_surface->w = w;
+   e_surface->h = h;
+
+   return e_surface;
+}
+
+static void
+evas_common_surface_dealloc(Evas_Surface *surface)
+{
+   Evas_Surface *d_surface;
+
+   while(surface)
+     {
+        d_surface = surface;
+        surface = (Evas_Surface *)eina_inlist_remove(EINA_INLIST_GET(surface), EINA_INLIST_GET(d_surface));
+        LKL(d_surface->im->ref_fq_del);
+        d_surface->im->ref_fq[1]++;
+        LKU(d_surface->im->ref_fq_del);
+
+        free(d_surface);
+
+     }
+}
+
+static void
+evas_common_surface_add(Evas_Frame *frame, Evas_Surface *surface)
+{
+   frame->surfaces = (Evas_Surface *)eina_inlist_append(EINA_INLIST_GET(frame->surfaces), EINA_INLIST_GET(surface));
+}
+
+static Evas_Frame * 
+evas_common_frame_alloc()
+{
+   Evas_Frame *frame;
+
+   frame = calloc(1, sizeof(Evas_Frame));
+   frame->surfaces = NULL;
+   return frame;
+}
+
+static void 
+evas_common_frame_dealloc(Evas_Frame *frame)
+{
+   evas_common_surface_dealloc(frame->surfaces);
+   free(frame);
+}
+
+static void
+evas_common_frame_add(Evas_FrameQ *frameq, Evas_Frame *frame)
+{
+   Evas_Frame *temp_frame;
+   
+   LKL(frameq->mutex);
+   while(eina_inlist_count(EINA_INLIST_GET(frameq->frames)) >= frameq->frameq_sz)
+     {
+        /* wait a worker thread finish previous frame */
+        pthread_cond_wait(&(frameq->cond_done), &(frameq->mutex));
+   }
+   frameq->frames = (Evas_Frame *) eina_inlist_append(EINA_INLIST_GET(frameq->frames), EINA_INLIST_GET(frame));
+
+   // this frame need not to be scheduled for flushing time
+   EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), temp_frame)
+    {
+       if (!temp_frame->ready)
+         {
+            break;
+         }
+     }
+   if (temp_frame && temp_frame == frame)
+      frame->dont_schedule = 1;
+
+   LKU(frameq->mutex);
+
+   pthread_cond_signal(&(frameq->cond_new));
+}
+
+EAPI Evas_Surface *
+evas_common_frameq_new_surface (void *surface, int x, int y, int w, int h)
+{
+   return evas_common_surface_alloc(surface, x, y, w, h);
+}
+
+EAPI void
+evas_common_frameq_add_surface(Evas_Surface *surface)
+{
+   evas_common_surface_add(gframeq.cur_frame, surface);
+}
+
+EAPI void 
+evas_common_frameq_set_frame_data(void *data, 
+     void (*fn_output_redraws_next_update_push) (void *data, void *surface, int x, int y, int w, int h),
+     void (*fn_output_flush)  (void *data),
+     void (*fn_output_set_priv)(void *data, void *cur, void *prev))
+{
+   if (gframeq.cur_frame) 
+     {
+        gframeq.cur_frame->data = data;
+        gframeq.cur_frame->output_redraws_next_update_push = fn_output_redraws_next_update_push;
+        gframeq.cur_frame->output_flush = fn_output_flush;
+        gframeq.cur_frame->output_set_priv = fn_output_set_priv;
+     }
+}
+
+EAPI void
+evas_common_frameq_prepare_frame()
+{
+   if (!gframeq.cur_frame )
+     {
+        gframeq.cur_frame = evas_common_frame_alloc();
+     }
+}
+
+EAPI void
+evas_common_frameq_ready_frame()
+{
+   if (gframeq.cur_frame)
+     {
+        evas_common_frame_add(&gframeq, gframeq.cur_frame);
+        gframeq.cur_frame = NULL; // create a new frame for the next frame later
+     }
+}
+
+
+EAPI void
+evas_common_frameq_init()
+{
+   gframeq.frames = NULL;
+   pthread_cond_init(&(gframeq.cond_new), NULL);
+   pthread_cond_init(&(gframeq.cond_ready), NULL);
+   pthread_cond_init(&(gframeq.cond_done), NULL);
+   LKI(gframeq.mutex);
+   gframeq.initialised = 0;    // worker thread are not created yet
+   gframeq.frameq_sz = 1;      // this value ensures the first frame can be enqueued.
+}
+
+EAPI void
+evas_common_frameq_destroy()
+{
+#if 0 // let them destroyed indirectly with program exit
+   LKL(gframeq.mutex);
+   pthread_cond_destroy(&(gframeq.cond_new));
+   pthread_cond_destroy(&(gframeq.cond_ready));
+   pthread_cond_destroy(&(gframeq.cond_done));
+   LKU(gframeq.mutex);
+#endif
+   LKD(gframeq.mutex);
+   
+   gframeq.frames = NULL;
+   gframeq.initialised = 0;
+}
+
+EAPI void
+evas_common_frameq_flush()
+{
+   if (! evas_common_frameq_enabled())
+      return;
+
+   LKL(gframeq.mutex);
+   while(eina_inlist_count(EINA_INLIST_GET(gframeq.frames)) > 0)
+     {
+        /* wait a worker thread finish previous frame */
+        pthread_cond_wait(&(gframeq.cond_done), &(gframeq.mutex));
+   }
+   LKU(gframeq.mutex);
+}
+
+
+EAPI void
+evas_common_frameq_flush_ready ()
+{
+   return;
+}
+
+EAPI int
+evas_common_frameq_get_frameq_sz()
+{
+   return gframeq.frameq_sz;
+}
+
+EAPI int
+evas_common_frameq_enabled()
+{
+   return gframeq.initialised;
+}
+#endif
+
 static RGBA_Pipe *evas_common_pipe_add(RGBA_Pipe *pipe, RGBA_Pipe_Op **op);
 static void evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op);
 static void evas_common_pipe_op_free(RGBA_Pipe_Op *op);
@@ -20,23 +223,23 @@ evas_common_pipe_add(RGBA_Pipe *pipe, RGBA_Pipe_Op **op)
 
    if (!pipe)
      {
-       first_pipe = 1;
-       p = calloc(1, sizeof(RGBA_Pipe));
-       if (!p) return NULL;
-       pipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(pipe), EINA_INLIST_GET(p));
+        first_pipe = 1;
+        p = calloc(1, sizeof(RGBA_Pipe));
+        if (!p) return NULL;
+        pipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(pipe), EINA_INLIST_GET(p));
      }
    p = (RGBA_Pipe *)(EINA_INLIST_GET(pipe))->last;
    if (p->op_num == PIPE_LEN)
      {
-       p = calloc(1, sizeof(RGBA_Pipe));
-       if (!p) return NULL;
-       pipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(pipe), EINA_INLIST_GET(p));
+        p = calloc(1, sizeof(RGBA_Pipe));
+        if (!p) return NULL;
+        pipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(pipe), EINA_INLIST_GET(p));
      }
    p->op_num++;
    *op = &(p->op[p->op_num - 1]);
    if (first_pipe)
      {
-       /* FIXME: PTHREAD init any thread locks etc */
+        /* FIXME: PTHREAD init any thread locks etc */
      }
    return pipe;
 }
@@ -47,11 +250,13 @@ evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op)
    memcpy(&(op->context), dc, sizeof(RGBA_Draw_Context));
    if (op->context.cutout.active > 0)
      {
-       op->context.cutout.rects = malloc(sizeof(Cutout_Rect) * op->context.cutout.active);
-       memcpy(op->context.cutout.rects, dc->cutout.rects, sizeof(Cutout_Rect) * op->context.cutout.active);
+        op->context.cutout.rects = malloc(sizeof(Cutout_Rect) * op->context.cutout.active);
+        memcpy(op->context.cutout.rects, dc->cutout.rects, sizeof(Cutout_Rect) * op->context.cutout.active);
      }
    else
-     op->context.cutout.rects = NULL;
+     {
+        op->context.cutout.rects = NULL;
+     }
 }
 
 static void
@@ -60,54 +265,543 @@ evas_common_pipe_op_free(RGBA_Pipe_Op *op)
    evas_common_draw_context_apply_clean_cutouts(&op->context.cutout);
 }
 
-/* main api calls */
 #ifdef BUILD_PTHREAD
-typedef struct _Thinfo
+/* main api calls */
+static void *
+evas_common_pipe_thread(void *data)
 {
-   int                    thread_num;
-   pthread_t              thread_id;
-   pthread_barrier_t     *barrier;
-   RGBA_Pipe_Thread_Info *info;
-} Thinfo;
+   Thinfo *thinfo;
+
+// INF("TH [...........");
+   thinfo = data;
+   for (;;)
+     {
+        RGBA_Pipe_Thread_Info *info;
+        RGBA_Pipe *p;
+
+        /* wait for start signal */
+// INF(" TH %i START...", thinfo->thread_num);
+        pthread_barrier_wait(&(thinfo->barrier[0]));
+        info = thinfo->info;
+// if (info)
+//   {
+//      thinfo->info = NULL;
+//      INF(" TH %i GO", thinfo->thread_num);
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->pipe), p)
+          {
+             int i;
+
+             for (i = 0; i < p->op_num; i++)
+               {
+                  if (p->op[i].op_func)
+                  p->op[i].op_func(info->im, &(p->op[i]), info);
+               }
+          }
+        free(info);
+//   }
+// INF(" TH %i DONE", thinfo->thread_num);
+        /* send finished signal */
+        pthread_barrier_wait(&(thinfo->barrier[1]));
+     }
+   return NULL;
+}
+
+#ifdef EVAS_FRAME_QUEUING
+static void
+evas_common_frameq_release(void *data)
+{
+   Evas_FrameQ *frameq;
+   Evas_Frameq_Thread_Info *fq_info;
+   Thinfo *thinfo;
+
+   thinfo = data;
+   fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info);
+   frameq = fq_info->frameq;
+
+   /* This thread may or may not own the mutex.
+    * But there's no way to determine the ownership of the mutex, so release it anyway 
+    */
+   LKU(frameq->mutex);
+}
 
 static void *
-evas_common_pipe_thread(void *data)
+evas_common_frameq_thread(void *data)
 {
+   Evas_FrameQ *frameq;
+   Evas_Frame *frame;
+   Evas_Surface *surface;
+   RGBA_Pipe *p;
    Thinfo *thinfo;
+   Evas_Frameq_Thread_Info *fq_info;
+   RGBA_Pipe_Thread_Info p_info;
 
-//   INF("TH [...........");
    thinfo = data;
+   fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info);
+   frameq = fq_info->frameq;
+
+   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+   /* install  thread cancelation cleanup handler */
+   pthread_cleanup_push(evas_common_frameq_release, data); 
+
    for (;;)
      {
-       RGBA_Pipe_Thread_Info *info;
-       RGBA_Pipe *p;
-
-       /* wait for start signal */
-//     INF(" TH %i START...", thinfo->thread_num);
-       pthread_barrier_wait(&(thinfo->barrier[0]));
-       info = thinfo->info;
-//     if (info)
-//       {
-//          thinfo->info = NULL;
-//          INF(" TH %i GO", thinfo->thread_num);
-       EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->pipe), p)
-              {
-                 int i;
-
-                 for (i = 0; i < p->op_num; i++)
-                   {
-                      if (p->op[i].op_func)
-                        p->op[i].op_func(info->im, &(p->op[i]), info);
-                   }
-              }
-            free(info);
-//       }
-//     INF(" TH %i DONE", thinfo->thread_num);
-       /* send finished signal */
-       pthread_barrier_wait(&(thinfo->barrier[1]));
+        frame = NULL;
+               
+        /* 1. pick a frame to draw */
+        LKL(frameq->mutex);
+        while(frame == NULL)
+          {
+             EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), frame)
+               {
+                  if (!frame->in_process)
+                    {
+                       frame->in_process = 1;
+                       break;
+                    }
+               }
+             if (frame)
+               {
+                  break;
+               }
+             pthread_testcancel();
+             pthread_cond_wait(&(frameq->cond_new), &(frameq->mutex));
+          }
+        LKU(frameq->mutex);
+
+        /* 2. draw selected frame */
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(frame->surfaces), surface)
+          {
+             p_info.im = surface->im;
+             p_info.x = 0;
+             p_info.y = 0;
+             p_info.w = surface->im->cache_entry.w;
+             p_info.h = surface->im->cache_entry.h;
+
+             EINA_INLIST_FOREACH(EINA_INLIST_GET(p_info.im->pipe), p)
+               {
+                  int i;
+
+                  for (i = 0; i < p->op_num; i++)
+                    {
+                       if (p->op[i].op_func)
+                         {
+                            p->op[i].op_func(p_info.im, &(p->op[i]), &p_info);
+                         }
+                    }
+               }
+
+             /* push surface out */
+             if (! surface->dontpush)
+               {
+                  frame->output_redraws_next_update_push(frame->data,  
+                              surface->im, surface->x, surface->y, surface->w, surface->h);
+               }
+          }
+
+        // record frame ready time, will be used in post worker thread, evas_common_frameq_thread_post()
+        gettimeofday(&frame->ready_time, NULL);
+
+        LKL(frameq->mutex);
+        frame->ready = 1;
+        pthread_cond_signal(&frameq->cond_ready);
+        LKU(frameq->mutex);
+     }
+
+   // Remove cleanup handler
+   pthread_cleanup_pop(0);
+   return NULL;
+}
+
+
+#define INTERVAL_QSIZE 17  // Actual size is 'INTERVAL_QSIZE - 1' because of not using index
+#define SATISFACTION_THRESHOLD 4 // 4 ms --> 250 FPS
+#define RESET_RATIO 4   // RESET_RATIO * [Average Ready Gap | get_max_interval()] --> Reset Threshold
+#define DOUBLE_RESET_TIME_INTERVAL_THRESHOLD 16000 // make it double in case of less 16ms
+#define RESET_ABSOLUTE_INTERVAL 600000  // 600 msec
+
+struct iq_node
+{
+   long long rt;
+   long long ri;
+};
+
+static struct iq_node _IQ[INTERVAL_QSIZE];
+static int _IQ_head = 0, _IQ_tail = 0;
+static int _IQ_length = 0;
+static long long min_ready, max_ready;
+static long long average_interval;
+
+static int 
+_IQ_next_index(int i)
+{
+   return (i + 1) % INTERVAL_QSIZE;
+}
+
+static int 
+_IQ_previous_index(int i)
+{
+   if (--i < 0) i += INTERVAL_QSIZE;
+   return i;
+}
+
+static void 
+_IQ_init(void)
+{
+   _IQ_length = _IQ_head = _IQ_tail = 0;
+   min_ready = LLONG_MAX, max_ready = LLONG_MIN;
+   average_interval = 0;
+}
+
+static int 
+_IQ_empty(void)
+{
+   return (_IQ_head == _IQ_tail) ? 1 : 0;
+}
+
+static int 
+_IQ_full(void)
+{
+   return (_IQ_head == ((_IQ_tail + 1) % INTERVAL_QSIZE)) ? 1 : 0;
+}
+
+static void 
+_IQ_insert(long long ready_time, long long last_interval)
+{
+   if (_IQ_full()) return;
+
+   if (_IQ_empty())
+     {
+        if (last_interval < 0)
+          {
+             last_interval = -last_interval;
+          }
+        _IQ[_IQ_tail].rt = ready_time;
+        _IQ[_IQ_tail].ri = last_interval;
+        min_ready = ready_time - last_interval;
+        max_ready = ready_time;
+        _IQ_tail = _IQ_next_index(_IQ_tail);
+        _IQ_length++;
+     }
+   else
+     {
+        if (max_ready < ready_time)
+          {
+             _IQ[_IQ_tail].rt = ready_time;
+             _IQ[_IQ_tail].ri = ready_time - max_ready;
+             _IQ_tail = _IQ_next_index(_IQ_tail);
+             _IQ_length++;
+             max_ready = ready_time;
+          }
+        else if (ready_time < min_ready)
+          {
+             last_interval = _IQ[_IQ_head].ri;
+             _IQ[_IQ_head].ri = _IQ[_IQ_head].rt - ready_time;
+             _IQ_head = _IQ_previous_index(_IQ_head);
+             _IQ[_IQ_head].rt = ready_time;
+             _IQ[_IQ_head].ri = last_interval;
+             min_ready = ready_time;
+             _IQ_length++;
+          }
+        else
+          {
+             int i, j, k, l = 0;
+             for (i = _IQ_head; i != _IQ_tail; i = j)
+               {
+                  j = _IQ_next_index(i);
+                  if (_IQ[j].rt < ready_time)
+                    {
+                       continue;
+                    }
+                  break;
+               }
+             for (k = _IQ_tail; k != j; k = l)
+               {
+                  l = _IQ_previous_index(k);
+                  _IQ[k] = _IQ[l];
+               }
+             i = _IQ_next_index(j);
+             _IQ[j].ri -= (_IQ[j].rt - ready_time);
+             _IQ[j].rt = ready_time;
+             _IQ[i].ri = _IQ[i].rt - ready_time;
+             _IQ_tail = _IQ_next_index(_IQ_tail);
+             _IQ_length++;
+          }
+     }
+   average_interval = (max_ready - min_ready) / _IQ_length;
+}
+
+static long long 
+_IQ_delete()
+{
+   struct iq_node oldest;
+   if (_IQ_empty()) return 0;
+   oldest = _IQ[_IQ_head];
+   _IQ_head = ++_IQ_head % INTERVAL_QSIZE;
+   if (--_IQ_length == 0)
+     {
+        _IQ_init();
+     }
+   else
+     {
+        min_ready = _IQ[_IQ_head].rt;
+        average_interval = (max_ready - min_ready) / _IQ_length;
+     }
+
+   return oldest.ri;
+}
+
+static long long 
+get_max_interval()
+{
+   int i;
+   long long max = LLONG_MIN;
+
+   for ( i= _IQ_head ; i != _IQ_tail ; i = _IQ_next_index(i))
+     {
+        if (_IQ[i].ri > max)
+          {
+             max = _IQ[i].ri;
+          }
+     }
+
+   return max;
+}
+
+static long long 
+tv_to_long_long(struct timeval *tv)
+{
+   if (tv == NULL)
+     {
+        return 0;
+     }
+
+   return tv->tv_sec * 1000000LL + tv->tv_usec;
+}
+
+static long long
+evas_common_frameq_schedule_flush_time( 
+                     int frameq_sz, int thread_no, 
+                     long long last_ready_time, long long current_ready_time,
+                     long long last_flush_time, int ready_frames_num,
+                     int dont_schedule)
+{
+   // to get each time and to do others
+   long long current_time = 0LL;
+   long long current_ready_interval = 0LL;
+   long long theshold_time = SATISFACTION_THRESHOLD * 1000LL;  // ms -> usec
+   long long reset_time_interval;
+   long long sleep_time = 0LL;
+   long long saved_ready_time, saved_ready_interval;
+   long long time_slept = 0LL;
+   static long long time_lag = 0;
+   struct timeval now;
+   int frameq_full_threshold =0;
+   int need_reset = 0;
+   int need_schedule = 0;
+
+   frameq_full_threshold = frameq_sz -thread_no;       // Qsize - threads#
+   
+   /* 1.5 defer flush time of current frame if need */
+   // in case of the first time, just keep ready time only
+   if (last_ready_time == 0LL)
+     {
+        last_ready_time = current_ready_time;
+     }
+   else
+     {
+        /* 1.5.1 get current ready time & interval */
+        saved_ready_time = current_ready_time;
+        saved_ready_interval = current_ready_interval = current_ready_time - last_ready_time;
+        // compensate a case which current ready time is older than previous one, 
+        // doesn't work on the interval queue
+        if (current_ready_interval < 0)
+          {
+             current_ready_time = last_ready_time;
+             current_ready_interval = 0;
+          }
+
+        /* 1.5.2 get the reset time interval before keeping a new one */
+        if (!_IQ_empty())
+          {
+             reset_time_interval = RESET_RATIO * average_interval;
+             if (average_interval < DOUBLE_RESET_TIME_INTERVAL_THRESHOLD) 
+               {
+                  reset_time_interval *= 2;
+               }
+          }
+
+        /* 1.5.3 reset - if too late, discard all saved interval and start from here */
+        if (current_ready_interval > RESET_ABSOLUTE_INTERVAL)
+          {
+             need_reset = 1;
+          }
+        else if (_IQ_length >= thread_no * 2 && current_ready_interval > reset_time_interval)
+          {
+             need_reset = 1;
+          }
+        else if (_IQ_length >= thread_no && _IQ_length < thread_no * 2 
+             && current_ready_interval > get_max_interval() * RESET_RATIO)
+          {
+             need_reset = 1;
+          }
+       
+        if (need_reset)
+          {
+             _IQ_init();
+          }
+        else
+          {
+             /* 1.5.4 enqueue - keep a new interval for next average interval */
+             if (_IQ_full())
+               {
+                  _IQ_delete();
+               }
+             _IQ_insert(saved_ready_time, saved_ready_interval);
+
+             /* 1.5.5 schedule - if faster than average interval, figure out sleep time to meet it */
+             if (!dont_schedule)
+               {
+                  need_schedule = 0;
+                  sleep_time = 0;
+                  if (_IQ_length >= thread_no * 2 && average_interval > theshold_time)
+                    {
+                       need_schedule = 1;
+                    }
+                  // compensate the case that postworker blocks the workers from getting a new fresh frame
+                  // It's actually occurred when during the wait time of postworker, the frame queue is full
+                  // Consequently check the number of currently ready frames and apply some time drop to average time according to the number
+                  if (ready_frames_num >= frameq_full_threshold)
+                    {
+                       need_schedule = 0;
+                    }
+                  if (need_schedule)
+                    {
+                       gettimeofday(&now, NULL);
+                       current_time = tv_to_long_long(&now);
+                       time_lag += (current_time - last_flush_time);
+                       sleep_time = (average_interval < time_lag) ? 0 : (average_interval - time_lag);
+                    }
+               }
+
+             /* 1.5.6 sleep - actually sleep and get over-slept time (time_lag) for next frame */
+             if (sleep_time > 0)
+               {
+                  sleep_time = sleep_time * 9 / 10;
+                  usleep((unsigned int)sleep_time);
+                  gettimeofday(&now, NULL);
+                  time_slept = tv_to_long_long(&now) - current_time;
+                  time_lag = time_slept - sleep_time;
+               }
+             else
+               {
+                  time_lag = 0;
+               }
+          }
+        last_ready_time = current_ready_time;
+     }
+
+   return last_ready_time;
+}
+
+static void *
+evas_common_frameq_thread_post(void *data)
+{
+   Evas_FrameQ *frameq;
+   Evas_Frame *frame;
+   Evas_Surface *surface;
+   RGBA_Pipe *p;
+   Thinfo *thinfo;
+   Evas_Frameq_Thread_Info *fq_info;
+   RGBA_Pipe_Thread_Info p_info;
+   Eina_List   *pending_writes = NULL;
+   Eina_List   *prev_pending_writes = NULL;
+
+   long long last_ready_time = 0LL;
+   long long current_ready_time;
+   Evas_Frame *temp_frame = NULL;
+   int ready_frames_num;
+   long long last_flush_time = 0LL;
+   struct timeval now;
+   int dont_schedule = 0;
+
+   thinfo = data;
+   fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info);
+   frameq = fq_info->frameq;
+
+   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+   pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+   /* install  thread cancelation cleanup handler */
+   pthread_cleanup_push(evas_common_frameq_release, data); 
+
+   _IQ_init();
+
+   for (;;)
+     {
+        /* 1. wait the first frame being done */
+        LKL(frameq->mutex);
+        while(!frameq->frames || !frameq->frames->ready)
+          {
+             pthread_cond_wait(&(frameq->cond_ready), &(frameq->mutex));
+          }
+        frame = frameq->frames;
+
+        /* 1.5. prepare to schedule flush time */
+        current_ready_time = tv_to_long_long(&frame->ready_time);
+        ready_frames_num = 0;
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), temp_frame)
+          {
+             if (temp_frame->ready == 1)
+               {
+                  ready_frames_num++;
+               }
+          }
+        dont_schedule = (frame->dont_schedule)?1:0;
+        LKU(frameq->mutex);
+
+        /* 2. generate pending_writes */
+        EINA_INLIST_FOREACH(EINA_INLIST_GET(frame->surfaces), surface)
+         {
+            evas_common_pipe_flush(surface->im);
+            if (! surface->dontpush)
+              {
+                 pending_writes = eina_list_append(pending_writes, surface->im);
+              }
+         }
+
+        /* 2.5. schedule flush time */
+        last_ready_time = evas_common_frameq_schedule_flush_time(
+                                       frameq->frameq_sz, frameq->thread_num, 
+                                       last_ready_time, current_ready_time,
+                                       last_flush_time, ready_frames_num, dont_schedule);
+
+        /* 3. flush redraws */
+        frame->output_set_priv(frame->data, pending_writes, prev_pending_writes);
+        frame->output_flush(frame->data);
+        gettimeofday(&now, NULL);
+        // keep as the last flush time
+        last_flush_time = now.tv_sec * 1000000LL + now.tv_usec;
+
+        prev_pending_writes = pending_writes;
+        pending_writes = NULL;
+
+        /* 4. remove this frame from the frame queue */
+        LKL(frameq->mutex);
+        frameq->frames = 
+            (Evas_Frame *)eina_inlist_remove(EINA_INLIST_GET(frameq->frames), 
+                  EINA_INLIST_GET(frame));
+
+        LKU(frameq->mutex);
+        pthread_cond_broadcast(&frameq->cond_done);
+        evas_common_frame_dealloc(frame);
      }
+
+   // Remove cleanup handler
+   pthread_cleanup_pop(0);
    return NULL;
 }
+
+#endif /* EVAS_FRAME_QUEUING */
 #endif
 
 #ifdef BUILD_PTHREAD
@@ -122,6 +816,10 @@ evas_common_pipe_begin(RGBA_Image *im)
 #ifdef BUILD_PTHREAD
    int i, y, h;
 
+#ifdef EVAS_FRAME_QUEUING
+   return;
+#endif
+
    if (!im->pipe) return;
    if (thread_num == 1) return;
    y = 0;
@@ -129,34 +827,136 @@ evas_common_pipe_begin(RGBA_Image *im)
    if (h < 1) h = 1;
    for (i = 0; i < thread_num; i++)
      {
-       RGBA_Pipe_Thread_Info *info;
+        RGBA_Pipe_Thread_Info *info;
 
-//          if (y >= im->cache_entry.h) break;
-       info = calloc(1, sizeof(RGBA_Pipe_Thread_Info));
-       info->im = im;
+//      if (y >= im->cache_entry.h) break;
+        info = calloc(1, sizeof(RGBA_Pipe_Thread_Info));
+        info->im = im;
 #ifdef EVAS_SLI
-       info->x = 0;
-       info->w = im->cache_entry.w;
-       info->y = i;
-       info->h = thread_num;
+        info->x = 0;
+        info->w = im->cache_entry.w;
+        info->y = i;
+        info->h = thread_num;
 #else
-       info->x = 0;
-       info->y = y;
-       info->w = im->cache_entry.w;
-       if (i == (thread_num - 1))
-         info->h = im->cache_entry.h - y;
-       else
-         info->h = h;
-       y += info->h;
+        info->x = 0;
+        info->y = y;
+        info->w = im->cache_entry.w;
+        if (i == (thread_num - 1))
+          {
+             info->h = im->cache_entry.h - y;
+          }
+        else
+          {
+             info->h = h;
+          }
+        y += info->h;
 #endif
-       thinfo[i].info = info;
+        thinfo[i].info = info;
      }
    /* tell worker threads to start */
    pthread_barrier_wait(&(thbarrier[0]));
 #endif
 }
 
-static void
+#ifdef EVAS_FRAME_QUEUING
+EAPI void
+evas_common_frameq_begin()
+{
+#ifdef BUILD_PTHREAD
+   int i;
+   Evas_Frameq_Thread_Info *fp_info;
+   pthread_attr_t attr;
+   cpu_set_t cpu;
+
+   int set_cpu_affinity=1;
+       
+       if (!gframeq.initialised)
+     {
+        int cpunum;
+
+        cpunum = eina_cpu_count();
+        gframeq.thread_num = cpunum;
+        gframeq.frameq_sz = cpunum * FRAMEQ_SZ_PER_THREAD;
+
+        for (i = 0; i < gframeq.thread_num; i++)
+          {
+
+             fp_info = calloc(1, sizeof(Evas_Frameq_Thread_Info));
+             fp_info->frameq = &gframeq;
+
+             gframeq.thinfo[i].thread_num = i;
+             gframeq.thinfo[i].fq_info = fp_info;
+
+             pthread_attr_init(&attr);
+             if (set_cpu_affinity)
+               {
+                  CPU_ZERO(&cpu);
+                  CPU_SET((i+1) % cpunum, &cpu);
+                  pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
+               }
+
+             pthread_create(&(gframeq.thinfo[i].thread_id), &attr,
+                     evas_common_frameq_thread, &(gframeq.thinfo[i]));
+                               
+             pthread_attr_destroy(&attr);
+             pthread_detach(gframeq.thinfo[i].thread_id);
+          }
+
+          {
+             fp_info = calloc(1, sizeof(Evas_Frameq_Thread_Info));
+             fp_info->frameq = &gframeq;
+
+             gframeq.thinfo[i].thread_num = i;
+             gframeq.thinfo[i].fq_info = fp_info;
+
+             pthread_attr_init(&attr);
+             if (set_cpu_affinity)
+               {
+                  CPU_ZERO(&cpu);
+                  CPU_SET((i+1) % cpunum, &cpu);
+                  pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
+               }
+
+             pthread_create(&(gframeq.thinfo[i].thread_id), &attr,
+                     evas_common_frameq_thread_post, &(gframeq.thinfo[i]));
+             pthread_attr_destroy(&attr);
+             pthread_detach(gframeq.thinfo[i].thread_id);
+          }
+        gframeq.initialised = 1;       // now worker threads are created.
+     }
+#endif /* BUILD_PTHREAD */
+}
+
+EAPI void
+evas_common_frameq_finish()
+{
+   int i;
+   
+   /* 1. cancel all worker threads */
+   for (i = 0; i < gframeq.thread_num; i++)
+     {
+        pthread_cancel(gframeq.thinfo[i].thread_id);
+     }
+     // cancel post-worker thread
+     pthread_cancel(gframeq.thinfo[i].thread_id);
+
+   /* 2. send signal to worker threads so that they enter to the thread cancelation cleanup handler */
+   for (i = 0; i < gframeq.thread_num; i++)
+     {
+        pthread_cond_signal(&(gframeq.cond_new));
+     }
+   // send signal to post-worker thread
+   pthread_cond_signal(&(gframeq.cond_ready));
+
+   /* all the workers were created and detached before
+    *  so don't need to join them here.
+    */
+
+}
+
+#endif /* EVAS_FRAME_QUEUING */
+
+EAPI void
 evas_common_pipe_flush(RGBA_Image *im)
 {
 
@@ -164,25 +964,31 @@ evas_common_pipe_flush(RGBA_Image *im)
    int i;
 
    if (!im->pipe) return;
+
+#ifndef EVAS_FRAME_QUEUING
+
 #ifdef BUILD_PTHREAD
    if (thread_num > 1)
      {
-       /* sync worker threads */
-       pthread_barrier_wait(&(thbarrier[1]));
+            /* sync worker threads */
+        pthread_barrier_wait(&(thbarrier[1]));
      }
    else
 #endif
      {
-       /* process pipe - 1 thead */
-       for (p = im->pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
-         {
-            for (i = 0; i < p->op_num; i++)
-              {
-                 if (p->op[i].op_func)
-                   p->op[i].op_func(im, &(p->op[i]), NULL);
-              }
-         }
+        /* process pipe - 1 thead */
+        for (p = im->pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
+          {
+             for (i = 0; i < p->op_num; i++)
+               {
+                  if (p->op[i].op_func)
+                    {
+                       p->op[i].op_func(im, &(p->op[i]), NULL);
+                    }
+               }
+          }
      }
+#endif /* !EVAS_FRAME_QUEUING */
    evas_common_cpu_end_opt();
    evas_common_pipe_free(im);
 }
@@ -200,14 +1006,16 @@ evas_common_pipe_free(RGBA_Image *im)
    /* free pipe */
    while (im->pipe)
      {
-       p = im->pipe;
-       for (i = 0; i < p->op_num; i++)
-         {
-            if (p->op[i].free_func)
-              p->op[i].free_func(&(p->op[i]));
-         }
-       im->pipe = (RGBA_Pipe *)eina_inlist_remove(EINA_INLIST_GET(im->pipe), EINA_INLIST_GET(p));
-       free(p);
+        p = im->pipe;
+        for (i = 0; i < p->op_num; i++)
+          {
+             if (p->op[i].free_func)
+               {
+                  p->op[i].free_func(&(p->op[i]));
+               }
+          }
+        im->pipe = (RGBA_Pipe *)eina_inlist_remove(EINA_INLIST_GET(im->pipe), EINA_INLIST_GET(p));
+        free(p);
      }
 }
 
@@ -220,27 +1028,29 @@ evas_common_pipe_rectangle_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif
-       evas_common_rectangle_draw(dst, &(context),
-                                  op->op.rect.x, op->op.rect.y,
-                                  op->op.rect.w, op->op.rect.h);
+        evas_common_rectangle_draw(dst, &(context),
+               op->op.rect.x, op->op.rect.y,
+               op->op.rect.w, op->op.rect.h);
      }
    else
-     evas_common_rectangle_draw(dst, &(op->context),
-                               op->op.rect.x, op->op.rect.y,
-                               op->op.rect.w, op->op.rect.h);
+     {
+        evas_common_rectangle_draw(dst, &(op->context),
+               op->op.rect.x, op->op.rect.y,
+               op->op.rect.w, op->op.rect.h);
+     }
 }
 
 EAPI void
 evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
-                               int x, int y, int w, int h)
+            int x, int y, int w, int h)
 {
    RGBA_Pipe_Op *op;
 
@@ -262,27 +1072,29 @@ evas_common_pipe_line_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Threa
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif
-       evas_common_line_draw(dst, &(context),
-                             op->op.line.x0, op->op.line.y0,
-                             op->op.line.x1, op->op.line.y1);
+        evas_common_line_draw(dst, &(context),
+               op->op.line.x0, op->op.line.y0,
+               op->op.line.x1, op->op.line.y1);
      }
    else
-     evas_common_line_draw(dst, &(op->context),
-                          op->op.line.x0, op->op.line.y0,
-                          op->op.line.x1, op->op.line.y1);
+     {
+        evas_common_line_draw(dst, &(op->context),
+               op->op.line.x0, op->op.line.y0,
+               op->op.line.x1, op->op.line.y1);
+     }
 }
 
 EAPI void
 evas_common_pipe_line_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
-                          int x0, int y0, int x1, int y1)
+            int x0, int y0, int x1, int y1)
 {
    RGBA_Pipe_Op *op;
 
@@ -305,10 +1117,10 @@ evas_common_pipe_op_poly_free(RGBA_Pipe_Op *op)
 
    while (op->op.poly.points)
      {
-       p = op->op.poly.points;
-       op->op.poly.points = (RGBA_Polygon_Point *)eina_inlist_remove(EINA_INLIST_GET(op->op.poly.points),
-                                                                     EINA_INLIST_GET(p));
-       free(p);
+        p = op->op.poly.points;
+        op->op.poly.points = (RGBA_Polygon_Point *)eina_inlist_remove(EINA_INLIST_GET(op->op.poly.points),
+                                                      EINA_INLIST_GET(p));
+        free(p);
      }
    evas_common_pipe_op_free(op);
 }
@@ -318,25 +1130,27 @@ evas_common_pipe_poly_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Threa
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif
-       evas_common_polygon_draw(dst, &(context),
-                                op->op.poly.points, 0, 0);
+        evas_common_polygon_draw(dst, &(context),
+                     op->op.poly.points, 0, 0);
      }
    else
-     evas_common_polygon_draw(dst, &(op->context),
-                             op->op.poly.points, 0, 0);
+     {
+        evas_common_polygon_draw(dst, &(op->context),
+                     op->op.poly.points, 0, 0);
+     }
 }
 
 EAPI void
 evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
-                          RGBA_Polygon_Point *points, int x, int y)
+               RGBA_Polygon_Point *points, int x, int y)
 {
    RGBA_Pipe_Op *op;
    RGBA_Polygon_Point *pts = NULL, *p, *pp;
@@ -347,13 +1161,13 @@ evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
    /* FIXME: copy points - maybe we should refcount? */
    for (p = points; p; p = (RGBA_Polygon_Point *)(EINA_INLIST_GET(p))->next)
      {
-       pp = calloc(1, sizeof(RGBA_Polygon_Point));
-       if (pp)
-         {
-            pp->x = p->x + x;
-            pp->y = p->y + y;
-            pts = (RGBA_Polygon_Point *)eina_inlist_append(EINA_INLIST_GET(pts), EINA_INLIST_GET(pp));
-         }
+        pp = calloc(1, sizeof(RGBA_Polygon_Point));
+        if (pp)
+          {
+             pp->x = p->x + x;
+             pp->y = p->y + y;
+             pts = (RGBA_Polygon_Point *)eina_inlist_append(EINA_INLIST_GET(pts), EINA_INLIST_GET(pp));
+          }
      }
    op->op.poly.points = pts;
    op->op_func = evas_common_pipe_poly_draw_do;
@@ -365,38 +1179,65 @@ evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
 static void
 evas_common_pipe_op_grad_free(RGBA_Pipe_Op *op)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(op->op.grad.grad->ref_fq_del);
+   op->op.grad.grad->ref_fq[1]++;
+   LKU(op->op.grad.grad->ref_fq_del);
+   pthread_cond_signal(&(op->op.grad.grad->cond_fq_del)); 
+#else
    evas_common_gradient_free(op->op.grad.grad);
+#endif
    evas_common_pipe_op_free(op);
 }
 
+#ifdef EVAS_FRAME_QUEUING
+EAPI void
+evas_common_pipe_op_grad_flush(RGBA_Gradient *gr)
+{
+   if (! evas_common_frameq_enabled())
+      return;
+
+   LKL(gr->ref_fq_add);
+   LKL(gr->ref_fq_del);
+
+   while (gr->ref_fq[0] != gr->ref_fq[1])
+      pthread_cond_wait(&(gr->cond_fq_del), &(gr->ref_fq_del));
+
+   LKU(gr->ref_fq_del);
+   LKU(gr->ref_fq_add);
+}
+#endif
+
 static void
 evas_common_pipe_grad_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif
-       evas_common_gradient_draw(dst, &(context),
-                                 op->op.grad.x, op->op.grad.y,
-                                 op->op.grad.w, op->op.grad.h,
-                                 op->op.grad.grad);
+        evas_common_gradient_draw(dst, &(context),
+                  op->op.grad.x, op->op.grad.y,
+                  op->op.grad.w, op->op.grad.h,
+                  op->op.grad.grad);
      }
    else
-     evas_common_gradient_draw(dst, &(op->context),
-                              op->op.grad.x, op->op.grad.y,
-                              op->op.grad.w, op->op.grad.h,
-                              op->op.grad.grad);
+     {
+        evas_common_gradient_draw(dst, &(op->context),
+                  op->op.grad.x, op->op.grad.y,
+                  op->op.grad.w, op->op.grad.h,
+                  op->op.grad.grad);
+     }
 }
 
 EAPI void
 evas_common_pipe_grad_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
-                          int x, int y, int w, int h, RGBA_Gradient *gr)
+            int x, int y, int w, int h, RGBA_Gradient *gr)
 {
    RGBA_Pipe_Op *op;
 
@@ -407,7 +1248,13 @@ evas_common_pipe_grad_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
    op->op.grad.y = y;
    op->op.grad.w = w;
    op->op.grad.h = h;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(gr->ref_fq_add);
+   gr->ref_fq[0]++;
+   LKU(gr->ref_fq_add);
+#else
    gr->references++;
+#endif
    op->op.grad.grad = gr;
    op->op_func = evas_common_pipe_grad_draw_do;
    op->free_func = evas_common_pipe_op_grad_free;
@@ -418,38 +1265,65 @@ evas_common_pipe_grad_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
 static void
 evas_common_pipe_op_grad2_free(RGBA_Pipe_Op *op)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(op->op.grad2.grad->ref_fq_del);
+   op->op.grad2.grad->ref_fq[1]++;
+   LKU(op->op.grad2.grad->ref_fq_del);
+   pthread_cond_signal(&(op->op.grad2.grad->cond_fq_del)); 
+#else
    evas_common_gradient2_free(op->op.grad2.grad);
+#endif
    evas_common_pipe_op_free(op);
 }
 
+#ifdef EVAS_FRAME_QUEUING
+EAPI void
+evas_common_pipe_op_grad2_flush(RGBA_Gradient2 *gr)
+{
+   if (! evas_common_frameq_enabled())
+      return;
+
+   LKL(gr->ref_fq_add);
+   LKL(gr->ref_fq_del);
+
+   while (gr->ref_fq[0] != gr->ref_fq[1])
+      pthread_cond_wait(&(gr->cond_fq_del), &(gr->ref_fq_del));
+
+   LKU(gr->ref_fq_del);
+   LKU(gr->ref_fq_add);
+}
+#endif
+
 static void
 evas_common_pipe_grad2_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
        
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else  
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif 
-       evas_common_gradient2_draw(dst, &(context),
-                                 op->op.grad2.x, op->op.grad2.y,
-                                 op->op.grad2.w, op->op.grad2.h,
-                                 op->op.grad2.grad);
+        evas_common_gradient2_draw(dst, &(context),
+               op->op.grad2.x, op->op.grad2.y,
+               op->op.grad2.w, op->op.grad2.h,
+               op->op.grad2.grad);
      }
    else
-     evas_common_gradient2_draw(dst, &(op->context),
-                              op->op.grad2.x, op->op.grad2.y,
-                              op->op.grad2.w, op->op.grad2.h,
-                              op->op.grad2.grad);
+     {
+        evas_common_gradient2_draw(dst, &(op->context),
+               op->op.grad2.x, op->op.grad2.y,
+               op->op.grad2.w, op->op.grad2.h,
+               op->op.grad2.grad);
+     }
 }
 
 EAPI void
 evas_common_pipe_grad2_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
-                          int x, int y, int w, int h, RGBA_Gradient2 *gr)
+            int x, int y, int w, int h, RGBA_Gradient2 *gr)
 {
    RGBA_Pipe_Op *op;
 
@@ -460,7 +1334,13 @@ evas_common_pipe_grad2_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
    op->op.grad2.y = y;
    op->op.grad2.w = w;
    op->op.grad2.h = h;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(gr->ref_fq_add);
+   gr->ref_fq[0]++;
+   LKU(gr->ref_fq_add);
+#else
    gr->references++;
+#endif
    op->op.grad2.grad = gr;
    op->op_func = evas_common_pipe_grad2_draw_do;
    op->free_func = evas_common_pipe_op_grad2_free;
@@ -471,37 +1351,65 @@ evas_common_pipe_grad2_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
 static void
 evas_common_pipe_op_text_free(RGBA_Pipe_Op *op)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(op->op.text.font->ref_fq_del);
+   op->op.text.font->ref_fq[1]++;
+   LKU(op->op.text.font->ref_fq_del);
+   pthread_cond_signal(&(op->op.text.font->cond_fq_del));
+#else
    evas_common_font_free(op->op.text.font);
+#endif
    free(op->op.text.text);
    evas_common_pipe_op_free(op);
 }
 
+#ifdef EVAS_FRAME_QUEUING
+/* flush all op using @fn */
+EAPI void
+evas_common_pipe_op_text_flush(RGBA_Font *fn)
+{
+   if (! evas_common_frameq_enabled())
+      return;
+
+   LKL(fn->ref_fq_add);
+   LKL(fn->ref_fq_del);
+
+   while (fn->ref_fq[0] != fn->ref_fq[1])
+      pthread_cond_wait(&(fn->cond_fq_del), &(fn->ref_fq_del));
+
+   LKU(fn->ref_fq_del);
+   LKU(fn->ref_fq_add);
+}
+#endif
+
 static void
 evas_common_pipe_text_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif
-       evas_common_font_draw(dst, &(context),
-                             op->op.text.font, op->op.text.x, op->op.text.y,
-                             op->op.text.text);
+        evas_common_font_draw(dst, &(context),
+                  op->op.text.font, op->op.text.x, op->op.text.y,
+                  op->op.text.text);
      }
    else
-     evas_common_font_draw(dst, &(op->context),
-                          op->op.text.font, op->op.text.x, op->op.text.y,
-                          op->op.text.text);
+     {
+        evas_common_font_draw(dst, &(op->context),
+                  op->op.text.font, op->op.text.x, op->op.text.y,
+                  op->op.text.text);
+     }
 }
 
 EAPI void
 evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
-                          RGBA_Font *fn, int x, int y, const char *text)
+               RGBA_Font *fn, int x, int y, const char *text)
 {
    RGBA_Pipe_Op *op;
 
@@ -511,7 +1419,13 @@ evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
    op->op.text.x = x;
    op->op.text.y = y;
    op->op.text.text = strdup(text);
+#ifdef EVAS_FRAME_QUEUING
+   LKL(fn->ref_fq_add);
+   fn->ref_fq[0]++;
+   LKU(fn->ref_fq_add);
+#else
    fn->references++;
+#endif
    op->op.text.font = fn;
    op->op_func = evas_common_pipe_text_draw_do;
    op->free_func = evas_common_pipe_op_text_free;
@@ -522,24 +1436,51 @@ evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
 static void
 evas_common_pipe_op_image_free(RGBA_Pipe_Op *op)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(op->op.image.src->ref_fq_del);
+   op->op.image.src->ref_fq[1]++;
+   LKU(op->op.image.src->ref_fq_del);
+   pthread_cond_signal(&(op->op.image.src->cond_fq_del)); 
+#else
    op->op.image.src->ref--;
    if (op->op.image.src->ref == 0)
-     evas_cache_image_drop(&op->op.image.src->cache_entry);
+     {
+        evas_cache_image_drop(&op->op.image.src->cache_entry);
+     }
+#endif
    evas_common_pipe_op_free(op);
 }
 
+#ifdef EVAS_FRAME_QUEUING
+EAPI void
+evas_common_pipe_op_image_flush(RGBA_Image *im)
+{
+   if (! evas_common_frameq_enabled())
+      return;
+   
+   LKL(im->ref_fq_add);
+   LKL(im->ref_fq_del);
+
+   while (im->ref_fq[0] != im->ref_fq[1])
+      pthread_cond_wait(&(im->cond_fq_del), &(im->ref_fq_del));
+
+   LKU(im->ref_fq_del);
+   LKU(im->ref_fq_add);
+}
+#endif
+
 static void
 evas_common_pipe_image_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
 {
    if (info)
      {
-       RGBA_Draw_Context context;
+        RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
 #ifdef EVAS_SLI
-       evas_common_draw_context_set_sli(&(context), info->y, info->h);
+        evas_common_draw_context_set_sli(&(context), info->y, info->h);
 #else
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 #endif
 
 #ifdef SCALECACHE
@@ -555,67 +1496,75 @@ evas_common_pipe_image_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thre
                                              op->op.image.dw,
                                              op->op.image.dh);
 #else
-       if (op->op.image.smooth)
-         evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
-                                                      dst, &(context),
-                                                      op->op.image.sx,
-                                                      op->op.image.sy,
-                                                      op->op.image.sw,
-                                                      op->op.image.sh,
-                                                      op->op.image.dx,
-                                                      op->op.image.dy,
-                                                      op->op.image.dw,
-                                                      op->op.image.dh);
-       else
-         evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
-                                                      dst, &(context),
-                                                      op->op.image.sx,
-                                                      op->op.image.sy,
-                                                      op->op.image.sw,
-                                                      op->op.image.sh,
-                                                      op->op.image.dx,
-                                                      op->op.image.dy,
-                                                      op->op.image.dw,
-                                                      op->op.image.dh);
+        if (op->op.image.smooth)
+          {
+             evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
+                           dst, &(context),
+                           op->op.image.sx,
+                           op->op.image.sy,
+                           op->op.image.sw,
+                           op->op.image.sh,
+                           op->op.image.dx,
+                           op->op.image.dy,
+                           op->op.image.dw,
+                           op->op.image.dh);
+          }
+        else
+          {
+             evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
+                           dst, &(context),
+                           op->op.image.sx,
+                           op->op.image.sy,
+                           op->op.image.sw,
+                           op->op.image.sh,
+                           op->op.image.dx,
+                           op->op.image.dy,
+                           op->op.image.dw,
+                           op->op.image.dh);
+                   }
 #endif
      }
    else
      {
 #ifdef SCALECACHE
         evas_common_rgba_image_scalecache_do(op->op.image.src,
-                                             dst, &(op->context),
-                                             op->op.image.smooth,
-                                             op->op.image.sx,
-                                             op->op.image.sy,
-                                             op->op.image.sw,
-                                             op->op.image.sh,
-                                             op->op.image.dx,
-                                             op->op.image.dy,
-                                             op->op.image.dw,
-                                             op->op.image.dh);
+                           dst, &(op->context),
+                           op->op.image.smooth,
+                           op->op.image.sx,
+                           op->op.image.sy,
+                           op->op.image.sw,
+                           op->op.image.sh,
+                           op->op.image.dx,
+                           op->op.image.dy,
+                           op->op.image.dw,
+                           op->op.image.dh);
 #else
-       if (op->op.image.smooth)
-         evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
-                                                      dst, &(op->context),
-                                                      op->op.image.sx,
-                                                      op->op.image.sy,
-                                                      op->op.image.sw,
-                                                      op->op.image.sh,
-                                                      op->op.image.dx,
-                                                      op->op.image.dy,
-                                                      op->op.image.dw,
-                                                      op->op.image.dh);
-       else
-         evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
-                                                      dst, &(op->context),
-                                                      op->op.image.sx,
-                                                      op->op.image.sy,
-                                                      op->op.image.sw,
-                                                      op->op.image.sh,
-                                                      op->op.image.dx,
-                                                      op->op.image.dy,
-                                                      op->op.image.dw,
-                                                      op->op.image.dh);
+        if (op->op.image.smooth)
+          {
+             evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
+                                 dst, &(op->context),
+                                 op->op.image.sx,
+                                 op->op.image.sy,
+                                 op->op.image.sw,
+                                 op->op.image.sh,
+                                 op->op.image.dx,
+                                 op->op.image.dy,
+                                 op->op.image.dw,
+                                 op->op.image.dh);
+          }
+        else
+                {
+             evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
+                                 dst, &(op->context),
+                                 op->op.image.sx,
+                                 op->op.image.sy,
+                                 op->op.image.sw,
+                                 op->op.image.sh,
+                                 op->op.image.dx,
+                                 op->op.image.dy,
+                                 op->op.image.dw,
+                                 op->op.image.dh);
+           }
 #endif
      }
 }
@@ -643,21 +1592,44 @@ evas_common_pipe_image_draw(RGBA_Image *src, RGBA_Image *dst,
    op->op.image.dy = dst_region_y;
    op->op.image.dw = dst_region_w;
    op->op.image.dh = dst_region_h;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(src->ref_fq_add);
+   src->ref_fq[0]++;
+   LKU(src->ref_fq_add);
+#else
    src->ref++;
+#endif
    op->op.image.src = src;
    op->op_func = evas_common_pipe_image_draw_do;
    op->free_func = evas_common_pipe_op_image_free;
    evas_common_pipe_draw_context_copy(dc, op);
 
+#ifdef EVAS_FRAME_QUEUING
+   /* laod every src image here.
+    * frameq utilize all cpu cores already by worker threads
+    * so another threads and barrier waiting can't be of any benefit.
+    * therefore, not instantiate loader threads.
+    */
+   if (src->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+      evas_cache_image_load_data(&src->cache_entry);
+   evas_common_image_colorspace_normalize(src);
+#else
    evas_common_pipe_image_load(src);
+#endif
 }
 
 static void
 evas_common_pipe_op_map4_free(RGBA_Pipe_Op *op)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(op->op.image.src->ref_fq_del);
+   op->op.image.src->ref_fq[1]++;
+   LKU(op->op.image.src->ref_fq_del);
+#else
    op->op.map4.src->ref--;
    if (op->op.map4.src->ref == 0)
      evas_cache_image_drop(&op->op.map4.src->cache_entry);
+#endif
    free(op->op.map4.p);
    evas_common_pipe_op_free(op);
 }
@@ -712,14 +1684,31 @@ evas_common_pipe_map4_draw(RGBA_Image *src, RGBA_Image *dst,
 
    op->op.map4.smooth = smooth;
    op->op.map4.level = level;
+#ifdef EVAS_FRAME_QUEUING
+   LKL(src->ref_fq_add);
+   src->ref_fq[0]++;
+   LKU(src->ref_fq_add);
+#else
    src->ref++;
+#endif
    op->op.map4.src = src;
    op->op.map4.p = pts_copy;
    op->op_func = evas_common_pipe_map4_draw_do;
    op->free_func = evas_common_pipe_op_map4_free;
    evas_common_pipe_draw_context_copy(dc, op);
 
+#ifdef EVAS_FRAME_QUEUING
+   /* laod every src image here.
+    * frameq utilize all cpu cores already by worker threads
+    * so another threads and barrier waiting can't be of any benefit.
+    * therefore, not instantiate loader threads.
+    */
+   if (src->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
+      evas_cache_image_load_data(&src->cache_entry);
+   evas_common_image_colorspace_normalize(src);
+#else
    evas_common_pipe_image_load(src);
+#endif
 }
 
 static void
@@ -908,4 +1897,5 @@ evas_common_pipe_map4_begin(RGBA_Image *root)
 
   evas_common_pipe_map4_render(root);
 }
+
 #endif
index 77c5dd3..651582c 100644 (file)
@@ -1,6 +1,82 @@
 #ifndef _EVAS_PIPE_H
 #define _EVAS_PIPE_H
 
+#ifdef BUILD_PTHREAD
+typedef struct _Thinfo
+{
+   int                    thread_num;
+   pthread_t              thread_id;
+   pthread_barrier_t     *barrier;
+   RGBA_Pipe_Thread_Info *info;
+#ifdef EVAS_FRAME_QUEUING
+   void                 *fq_info;
+#endif
+} Thinfo;
+#endif
+
+#ifdef EVAS_FRAME_QUEUING
+struct _Evas_Surface
+{
+   EINA_INLIST;
+   RGBA_Image *im;
+   int x, y, w, h;
+   int dontpush; // dont push the surface out after drawing done
+};
+typedef struct _Evas_Surface Evas_Surface;
+
+struct _Evas_Frame
+{
+   EINA_INLIST;
+   Evas_Surface *surfaces;
+   void *data;
+   int in_process;
+   int ready;
+   int dont_schedule;
+   struct timeval ready_time;
+
+   void (*output_redraws_next_update_push) (void *data, void *surface, int x, int y, int w, int h);
+   void (*output_flush)  (void *data);
+   void (*output_set_priv)(void *data, void *cur, void *prev);
+};
+typedef struct _Evas_Frame Evas_Frame;
+
+
+struct _Evas_FrameQ
+{
+   int initialised;
+   Evas_Frame   *frames;
+   pthread_cond_t cond_new;
+   pthread_cond_t cond_ready;
+   pthread_cond_t cond_done;
+   LK(mutex);
+
+   int               thread_num;
+   Thinfo          thinfo[TH_MAX];
+   int            frameq_sz;
+
+   Evas_Frame *cur_frame;       
+};
+typedef struct _Evas_FrameQ Evas_FrameQ;
+#define FRAMEQ_SZ_PER_THREAD 2
+
+struct _Evas_Frameq_Thread_Info
+{
+   Evas_FrameQ *frameq;
+};
+typedef struct _Evas_Frameq_Thread_Info Evas_Frameq_Thread_Info;
+
+EAPI Evas_Surface *evas_common_frameq_new_surface (void *surface, int x, int y, int w, int h);
+EAPI void evas_common_frameq_add_surface(Evas_Surface *surface);
+EAPI void evas_common_frameq_set_frame_data(void *data, 
+     void (*fn_output_redraws_next_update_push) (void *data, void *surface, int x, int y, int w, int h),
+     void (*fn_output_flush)  (void *data),
+     void (*fn_output_set_priv)(void *data, void *cur, void *prev));
+EAPI void evas_common_frameq_prepare_frame();
+EAPI void evas_common_frameq_ready_frame();
+EAPI void evas_common_frameq_init();
+EAPI void evas_common_frameq_flush();
+EAPI void evas_common_frameq_flush_ready ();
+#endif
 
 /* image rendering pipelines... new optional system - non-immediate and
  * threadable
@@ -19,4 +95,11 @@ EAPI void evas_common_pipe_map4_draw(RGBA_Image *src, RGBA_Image *dst,
                                     RGBA_Draw_Context *dc, RGBA_Map_Point *p,
                                     int smooth, int level);
 
+#ifdef EVAS_FRAME_QUEUING
+EAPI void evas_common_pipe_op_grad_flush(RGBA_Gradient *gr);
+EAPI void evas_common_pipe_op_grad2_flush(RGBA_Gradient2 *gr);
+EAPI void evas_common_pipe_op_text_flush(RGBA_Font *fn);
+EAPI void evas_common_pipe_op_image_flush(RGBA_Image *im);
+#endif
+
 #endif /* _EVAS_PIPE_H */
index dff7224..9e76263 100644 (file)
@@ -136,7 +136,14 @@ extern EAPI int _evas_log_dom_global;
 # include <pthread.h>
 # include <sched.h>
 # define LK(x)  pthread_mutex_t x
+#ifndef EVAS_FRAME_QUEUING
 # define LKI(x) pthread_mutex_init(&(x), NULL);
+#else
+# define LKI(x) {pthread_mutexattr_t    attr;\
+         pthread_mutexattr_init(&attr); \
+         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);    \
+         pthread_mutex_init(&(x), &attr);}
+#endif
 # define LKD(x) pthread_mutex_destroy(&(x));
 # define LKL(x) pthread_mutex_lock(&(x));
 # define LKT(x) pthread_mutex_trylock(&(x));
@@ -145,6 +152,15 @@ extern EAPI int _evas_log_dom_global;
 # define THI(x) int x
 # define TH_MAX 8
 
+/* for rwlocks */
+#define RWLK(x) pthread_rwlock_t x
+#define RWLKI(x) pthread_rwlock_init(&(x), NULL);
+#define RWLKD(x) pthread_rwlock_destroy(&(x));
+#define RDLKL(x) pthread_rwlock_rdlock(&(x));
+#define WRLKL(x) pthread_rwlock_wrlock(&(x));
+#define RWLKU(x) pthread_rwlock_unlock(&(x));
+
+
 // even though in theory having every Nth rendered line done by a different
 // thread might even out load across threads - it actually slows things down.
 //#define EVAS_SLI 1
@@ -159,6 +175,15 @@ extern EAPI int _evas_log_dom_global;
 # define TH(x)
 # define THI(x)
 # define TH_MAX 0
+
+/* for rwlocks */
+#define RWLK(x) 
+#define RWLKI(x) 
+#define RWLKD(x)
+#define RDLKL(x) 
+#define WRLKL(x)
+#define RWLKU(x)
+
 #endif
 
 #ifdef HAVE_ALLOCA_H
@@ -521,6 +546,9 @@ struct _Image_Entry
    time_t                 laststat;
 
    int                    references;
+#ifdef EVAS_FRAME_QUEUING
+   LK(lock_references);   // needed for accessing references
+#endif
 
    unsigned char          scale;
 
@@ -630,6 +658,8 @@ struct _RGBA_Draw_Context
 };
 
 #ifdef BUILD_PIPE_RENDER
+#include "../engines/common/evas_map_image.h"
+
 struct _RGBA_Pipe_Op
 {
    RGBA_Draw_Context         context;
@@ -707,6 +737,12 @@ struct _RGBA_Image
    void                *extended_info;
 #ifdef BUILD_PIPE_RENDER
    RGBA_Pipe           *pipe;
+#ifdef EVAS_FRAME_QUEUING
+   LK(ref_fq_add);
+   LK(ref_fq_del);
+   pthread_cond_t cond_fq_del;
+   int ref_fq[2];              // ref_fq[0] is for addition, ref_fq[1] is for deletion
+#endif
 #endif
    int                  ref;
 
@@ -790,6 +826,13 @@ struct _RGBA_Gradient
      } type;
 
    int references;
+#ifdef EVAS_FRAME_QUEUING
+   LK(ref_fq_add);
+   LK(ref_fq_del);
+   pthread_cond_t cond_fq_del;
+   int ref_fq[2];      //ref_fq[0] is for addition,
+                         //ref_fq[1] is for deletion
+#endif
 
    Eina_Bool imported_data : 1;
    Eina_Bool has_alpha : 1;
@@ -847,6 +890,13 @@ struct _RGBA_Gradient2
      } type;
 
    int references;
+#ifdef EVAS_FRAME_QUEUING
+   LK(ref_fq_add);
+   LK(ref_fq_del);
+   pthread_cond_t cond_fq_del;
+   int ref_fq[2];      //ref_fq[0] is for addition,
+                         //ref_fq[1] is for deletion
+#endif
 
    Eina_Bool has_alpha : 1;
 };
@@ -922,6 +972,12 @@ struct _RGBA_Font
    Fash_Int *fash;
    unsigned char sizeok : 1;
    LK(lock);
+#ifdef EVAS_FRAME_QUEUING
+   LK(ref_fq_add);
+   LK(ref_fq_del);
+   pthread_cond_t cond_fq_del;
+   int ref_fq[2];              //ref_fq[0] is for addition, ref_fq[1] is for deletion
+#endif
 };
 
 struct _RGBA_Font_Int
index 02dea14..e6d11d1 100644 (file)
@@ -31,6 +31,9 @@ struct _Evas_Engine_Info_Buffer
         void   (*free_update_region) (int x, int y, int w, int h, void *data);
       } func;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index 1c6abc0..0add001 100644 (file)
@@ -126,6 +126,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Buffer));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index 3a7d64a..65503a0 100644 (file)
@@ -21,6 +21,9 @@ struct _Evas_Engine_Info_Cairo_X11
    } info;
    /* engine specific function calls to query stuff about the destination */
    /* engine (what visual & colormap & depth to use, performance info etc. */
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index df81a2f..36c834d 100644 (file)
@@ -267,6 +267,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Cairo_X11));
    if (!info) return NULL;
    info->magic.magic = rand();   
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index 05359a3..f9b7a9c 100644 (file)
@@ -27,6 +27,9 @@ struct _Evas_Engine_Info_Direct3D
       unsigned short height;
       unsigned char *mask;
    } *shape;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 
index 8514f75..5fcd89d 100644 (file)
@@ -77,6 +77,7 @@ eng_info(Evas *e)
    if (!info) return NULL;
    info->magic.magic = rand();
    memset(&info->info, 0, sizeof(info->info));
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index f4177e1..a2e9d3a 100644 (file)
@@ -16,6 +16,9 @@ struct _Evas_Engine_Info_DirectFB
       IDirectFB                 *dfb;
       IDirectFBSurface          *surface;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index 7166e42..b548237 100644 (file)
@@ -16,6 +16,9 @@ struct _Evas_Engine_Info_FB
       int refresh;
       int rotation;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index 47386ba..a0b5e3d 100644 (file)
@@ -81,6 +81,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_FB));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index c254fd0..a83496e 100644 (file)
@@ -20,6 +20,9 @@ struct _Evas_Engine_Info_GL_Glew
       HWND  window;
       int   depth;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 
index 1fabf66..37b0f43 100644 (file)
@@ -20,6 +20,7 @@ eng_info(Evas *e __UNUSED__)
    info = calloc(1, sizeof(Evas_Engine_Info_GL_Glew));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
 }
 
index 2e0461c..7224f9c 100644 (file)
@@ -29,13 +29,16 @@ struct _Evas_Engine_Info_GL_X11
       Colormap  (*best_colormap_get) (Evas_Engine_Info_GL_X11 *einfo);
       int       (*best_depth_get)    (Evas_Engine_Info_GL_X11 *einfo);
    } func;
-   
+
    struct {
       void      (*pre_swap)          (void *data, Evas *e);
       void      (*post_swap)         (void *data, Evas *e);
       
       void       *data; // data for callback calls
    } callback;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
    
    unsigned char vsync : 1; // does nothing right now
    unsigned char indirect : 1; // use indirect rendering
index 243f40d..e9d2484 100644 (file)
@@ -184,6 +184,7 @@ eng_info(Evas *e)
    info->func.best_visual_get = eng_best_visual_get;
    info->func.best_colormap_get = eng_best_colormap_get;
    info->func.best_depth_get = eng_best_depth_get;
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index abca922..0a277f4 100644 (file)
@@ -15,6 +15,9 @@ struct _Evas_Engine_Info_Quartz
    struct {
       CGContextRef context;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 #endif
index 6843702..160f043 100644 (file)
@@ -44,6 +44,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Quartz));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
 }
 
index 7c3d888..3c1547a 100644 (file)
@@ -23,6 +23,9 @@ struct _Evas_Engine_Info_Software_16_DDraw
 
       int                 rotation;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 
index 6e2abb0..90f1162 100644 (file)
@@ -54,6 +54,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Software_16_DDraw));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index 20adccf..5a133fe 100644 (file)
@@ -17,6 +17,9 @@ struct _Evas_Engine_Info_SDL_16
     int                         noframe : 1;
     int                         alpha : 1;
   } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 #endif
index d9d45a5..e94b7c2 100644 (file)
@@ -26,6 +26,9 @@ struct _Evas_Engine_Info_Software_16_WinCE
       int   (*suspend) (int backend);
       int   (*resume)  (int backend);
    } func;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 
index 886fa0f..b994a9a 100644 (file)
@@ -95,6 +95,7 @@ eng_info(Evas *e)
    info->magic.magic = rand();
    info->func.suspend = _suspend;
    info->func.resume = _resume;
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index 47885fa..9768f0a 100644 (file)
@@ -17,6 +17,9 @@ struct _Evas_Engine_Info_Software_16_X11
       Drawable  drawable;
       int rotation;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index 32a88ba..7f753fc 100644 (file)
@@ -103,6 +103,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Software_16_X11));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index e06ef4e..9735bb7 100644 (file)
@@ -21,6 +21,9 @@ struct _Evas_Engine_Info_Software_DDraw
       int          rotation;
       unsigned int fullscreen : 1;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 
index 426f949..114f586 100644 (file)
@@ -97,6 +97,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Software_DDraw));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index a95b07e..032ec8d 100644 (file)
@@ -23,6 +23,9 @@ struct _Evas_Engine_Info_Software_Gdi
       unsigned int layered    : 1;
       unsigned int fullscreen : 1;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 
index 77671be..a28185e 100644 (file)
@@ -150,7 +150,11 @@ static void
 eng_rectangle_draw(void *data __UNUSED__, void *context, void *surface, int x, int y, int w, int h)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      evas_common_pipe_rectangle_draw(surface, context, x, y, w, h);
    else
 #endif
@@ -164,8 +168,12 @@ static void
 eng_line_draw(void *data __UNUSED__, void *context, void *surface, int x1, int y1, int x2, int y2)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
-     evas_common_pipe_line_draw(surface, context, x1, y1, x2, y2);
+   if ((cpunum > 1)
+ #ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
+    evas_common_pipe_line_draw(surface, context, x1, y1, x2, y2);
    else
 #endif   
      {
@@ -190,7 +198,11 @@ static void
 eng_polygon_draw(void *data __UNUSED__, void *context, void *surface, void *polygon, int x, int y)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      evas_common_pipe_poly_draw(surface, context, polygon, x, y);
    else
 #endif
@@ -284,7 +296,11 @@ static void
 eng_gradient2_linear_draw(void *data __UNUSED__, void *context, void *surface, void *linear_gradient, int x, int y, int w, int h)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      evas_common_pipe_grad2_draw(surface, context, x, y, w, h, linear_gradient);
    else
 #endif
@@ -351,7 +367,11 @@ static void
 eng_gradient2_radial_draw(void *data __UNUSED__, void *context, void *surface, void *radial_gradient, int x, int y, int w, int h)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      evas_common_pipe_grad2_draw(surface, context, x, y, w, h, radial_gradient);
    else
 #endif
@@ -484,7 +504,11 @@ static void
 eng_gradient_draw(void *data __UNUSED__, void *context, void *surface, void *gradient, int x, int y, int w, int h)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      evas_common_pipe_grad_draw(surface, context, x, y, w, h, gradient);
    else
 #endif   
@@ -745,7 +769,11 @@ eng_image_draw(void *data __UNUSED__, void *context, void *surface, void *image,
    if (!image) return;
    im = image;
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      {
         evas_common_rgba_image_scalecache_prepare(im, surface, context, smooth,
                                                   src_x, src_y, src_w, src_h,
@@ -810,7 +838,7 @@ eng_image_map4_draw(void *data __UNUSED__, void *context, void *surface, void *i
        (p[3].col == 0xffffffff))
      {
         int dx, dy, dw, dh;
-        
+
         dx = p[0].x >> FP;
         dy = p[0].y >> FP;
         dw = (p[2].x >> FP) - dx;
@@ -823,13 +851,18 @@ eng_image_map4_draw(void *data __UNUSED__, void *context, void *surface, void *i
    else
      {
 #ifdef BUILD_PIPE_RENDER
-        if (cpunum > 1)
+        if ((cpunum > 1)
+# ifdef EVAS_FRAME_QUEUING
+       && evas_common_frameq_enabled()
+# endif
+        )
           evas_common_pipe_map4_draw(im, surface, context, p, smooth, level);
         else
 #endif
           evas_common_map4_rgba(im, surface, context, p, smooth, level);
      }
    evas_common_cpu_end_opt();
+
 }
 
 static void *
@@ -1000,7 +1033,11 @@ static void
 eng_font_draw(void *data __UNUSED__, void *context, void *surface, void *font, int x, int y, int w __UNUSED__, int h __UNUSED__, int ow __UNUSED__, int oh __UNUSED__, const char *text)
 {
 #ifdef BUILD_PIPE_RENDER
-   if (cpunum > 1)
+   if ((cpunum > 1)
+#ifdef EVAS_FRAME_QUEUING
+        && evas_common_frameq_enabled()
+#endif
+        )
      evas_common_pipe_text_draw(surface, context, font, x, y, text);
    else
 #endif   
index 5b863b0..6878b05 100644 (file)
@@ -25,6 +25,9 @@ struct _Evas_Engine_Info_Software_Qtopia
       QWidget *target;
       int      rotation;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index 89b139a..bee5a80 100644 (file)
@@ -90,6 +90,7 @@ eng_info(Evas *e)
    info = calloc(1, sizeof(Evas_Engine_Info_Software_Qtopia));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
    e = NULL;
 }
index 71efa8a..3cce6ec 100644 (file)
@@ -18,6 +18,9 @@ struct _Evas_Engine_Info_SDL
      int                       noframe : 1;
      int                        alpha : 1;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
 
index 6b0f692..de6da96 100644 (file)
@@ -53,6 +53,8 @@ struct _Evas_Engine_Info_Software_X11
    } func;
 
    int mask_changed;
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 
 #endif
index 2788fc6..0812e4c 100644 (file)
@@ -84,7 +84,10 @@ struct _Render_Engine
       int        dpi; // xres - dpi
    } xr; // xres - dpi
 #endif
-   
+#ifdef EVAS_FRAME_QUEUING
+   Evas_Engine_Render_Mode render_mode;
+#endif
+
    void        (*outbuf_free)(Outbuf *ob);
    void        (*outbuf_reconfigure)(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth);
    int         (*outbuf_get_rot)(Outbuf *ob);
@@ -94,6 +97,9 @@ struct _Render_Engine
    void        (*outbuf_flush)(Outbuf *ob);
    void        (*outbuf_idle_flush)(Outbuf *ob);
    Eina_Bool   (*outbuf_alpha_get)(Outbuf *ob);
+#ifdef EVAS_FRAME_QUEUING
+   void                (*outbuf_set_priv)(Outbuf *ob, void *cur, void *prev);
+#endif
 };
 
 /* prototypes we will use here */
@@ -441,6 +447,7 @@ eng_info(Evas *e __UNUSED__)
    info->func.best_visual_get = _best_visual_get;
    info->func.best_colormap_get = _best_colormap_get;
    info->func.best_depth_get = _best_depth_get;
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
 }
 
@@ -502,6 +509,10 @@ eng_setup(Evas *e, void *in)
              re->outbuf_flush = evas_software_xlib_outbuf_flush;
              re->outbuf_idle_flush = evas_software_xlib_outbuf_idle_flush;
             re->outbuf_alpha_get = evas_software_xlib_outbuf_alpha_get;
+#ifdef EVAS_FRAME_QUEUING
+             re->outbuf_set_priv = evas_software_xlib_outbuf_set_priv;
+             re->render_mode = info->render_mode;
+#endif
           }
 #endif
 
@@ -542,6 +553,9 @@ eng_setup(Evas *e, void *in)
      {
        int            ponebuf = 0;
 
+#ifdef EVAS_FRAME_QUEUING
+        evas_common_frameq_flush ();
+#endif
        re = e->engine.data.output;
        ponebuf = re->ob->onebuf;
 
@@ -564,6 +578,9 @@ eng_setup(Evas *e, void *in)
                                                         info->info.shape_dither,
                                                         info->info.destination_alpha);
              evas_software_xlib_outbuf_debug_set(re->ob, info->info.debug);
+#ifdef EVAS_FRAME_QUEUING
+             re->render_mode = info->render_mode;
+#endif
           }
 #endif
 
@@ -714,18 +731,74 @@ static void
 eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
 {
    Render_Engine *re;
+#ifdef EVAS_FRAME_QUEUING
+   Evas_Surface *e_surface;
+#endif
 
    re = (Render_Engine *)data;
-#ifdef BUILD_PIPE_RENDER
+#if defined(BUILD_PIPE_RENDER) && !defined(EVAS_FRAME_QUEUING)
    evas_common_pipe_map4_begin(surface);
-#endif   
+#endif /* BUILD_PIPE_RENDER  && !EVAS_FRAME_QUEUING*/
+
+#ifdef EVAS_FRAME_QUEUING
+   if (re->render_mode == EVAS_RENDER_MODE_NONBLOCKING)
+     {
+        /* create a new frame if this is the first surface of this frame */
+        evas_common_frameq_prepare_frame();
+        /* add surface into the frame */
+        e_surface = evas_common_frameq_new_surface(surface, x, y, w, h);
+        evas_common_frameq_add_surface(e_surface);
+        return;
+     }
+#endif
+
    re->outbuf_push_updated_region(re->ob, surface, x, y, w, h);
    re->outbuf_free_region_for_update(re->ob, surface);
    evas_common_cpu_end_opt();
 }
 
+#ifdef EVAS_FRAME_QUEUING
+static void *
+eng_image_map_surface_new(void *data , int w, int h, int alpha)
+{
+   void *surface;
+   DATA32 *pixels;
+   Render_Engine *re;
+   Evas_Surface *e_surface;
+
+   re = (Render_Engine *)data;
+
+   surface = evas_cache_image_copied_data(evas_common_image_cache_get(), 
+                                          w, h, NULL, alpha, 
+                                          EVAS_COLORSPACE_ARGB8888);
+   pixels = evas_cache_image_pixels(surface);
+
+   if (re->render_mode == EVAS_RENDER_MODE_NONBLOCKING)
+     {
+        /* create a new frame if this is the first surface of this frame */
+        evas_common_frameq_prepare_frame();
+
+        /* add surface into the frame */
+        e_surface = evas_common_frameq_new_surface (surface, 0, 0, w, h);
+        e_surface->dontpush = 1; // this surface is not going to be pushed to screen
+        evas_common_frameq_add_surface(e_surface);
+     }
+   return surface;
+}
+
 static void
-eng_output_flush(void *data)
+eng_output_frameq_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
+{
+   Render_Engine *re;
+
+   re = (Render_Engine *)data;
+   re->outbuf_push_updated_region(re->ob, surface, x, y, w, h);
+   re->outbuf_free_region_for_update(re->ob, surface);
+   evas_common_cpu_end_opt();
+}
+
+static void
+eng_output_frameq_flush(void *data)
 {
    Render_Engine *re;
 
@@ -734,6 +807,39 @@ eng_output_flush(void *data)
 }
 
 static void
+eng_output_frameq_set_priv(void *data, void *cur, void *prev)
+{
+   Render_Engine *re;
+
+   re = (Render_Engine *)data;
+   re->outbuf_set_priv(re->ob, cur, prev);
+}
+#endif
+
+static void
+eng_output_flush(void *data)
+{
+   Render_Engine *re;
+
+   re = (Render_Engine *)data;
+#ifdef EVAS_FRAME_QUEUING
+   if (re->render_mode == EVAS_RENDER_MODE_NONBLOCKING)
+     {
+        evas_common_frameq_set_frame_data(data,
+                        eng_output_frameq_redraws_next_update_push,
+                        eng_output_frameq_flush,
+                        eng_output_frameq_set_priv);
+        evas_common_frameq_ready_frame();
+        evas_common_frameq_begin();
+     } 
+   else
+#endif
+     {
+        re->outbuf_flush(re->ob);
+     }
+}
+
+static void
 eng_output_idle_flush(void *data)
 {
    Render_Engine *re;
@@ -751,6 +857,7 @@ eng_canvas_alpha_get(void *data, void *context __UNUSED__)
    return (re->ob->priv.destination_alpha) || (re->outbuf_alpha_get(re->ob));
 }
 
+
 /* module advertising code */
 static int
 module_open(Evas_Module *em)
@@ -793,6 +900,10 @@ module_open(Evas_Module *em)
    ORD(output_flush);
    ORD(output_idle_flush);
    /* now advertise out own api */
+#ifdef EVAS_FRAME_QUEUING
+   ORD(image_map_surface_new);
+#endif
+
    em->functions = (void *)(&func);
    return 1;
 }
index e3eb184..808a3e5 100644 (file)
@@ -113,6 +113,10 @@ struct _Outbuf
       Eina_List   *pending_writes;
       /* a list of previous frame pending regions to write to the target */
       Eina_List   *prev_pending_writes;
+#ifdef EVAS_FRAME_QUEUING
+      /* protecting prev_pending_writes */
+      LK(lock);
+#endif
 
       unsigned char mask_dither : 1;
       unsigned char destination_alpha : 1;
index a077963..873a67e 100644 (file)
@@ -305,7 +305,18 @@ evas_software_xlib_x_output_buffer_new(Display *d, Visual *v, int depth, int w,
                                  ph = XSetErrorHandler((XErrorHandler)
                                                        x_output_tmp_x_err);
                               }
+#if defined(EVAS_FRAME_QUEUING) && defined(LIBXEXT_VERSION_LOW)
+                    /* workaround for libXext of lower then 1.1.1 */
+                    if (evas_common_frameq_enabled())
+                       XLockDisplay(d);
+#endif
                            XShmAttach(d, xob->shm_info);
+#if defined(EVAS_FRAME_QUEUING) && defined(LIBXEXT_VERSION_LOW)
+                    /* workaround for libXext of lower then 1.1.1 */
+                    if (evas_common_frameq_enabled())
+                       XUnlockDisplay(d);
+#endif
+
                             if (try_shm == 2) // only needed during testing
                               {
                                  XSync(d, False); 
index 6e1ac92..7274c1a 100644 (file)
@@ -25,6 +25,15 @@ static int shmsize = 0;
 static int shmmemlimit = 10 * 1024 * 1024;
 static int shmcountlimit = 32;
 
+#ifdef EVAS_FRAME_QUEUING
+static LK(lock_shmpool);
+#define SHMPOOL_LOCK()         LKL(lock_shmpool)
+#define SHMPOOL_UNLOCK()       LKU(lock_shmpool)
+#else
+#define SHMPOOL_LOCK()
+#define SHMPOOL_UNLOCK()
+#endif
+
 static X_Output_Buffer *
 _find_xob(Display *d, Visual *v, int depth, int w, int h, int shm, void *data)
 {
@@ -46,6 +55,7 @@ _find_xob(Display *d, Visual *v, int depth, int w, int h, int shm, void *data)
    else
      lbytes = ((w + 31) / 32) * 4;
    sz = lbytes * h;
+   SHMPOOL_LOCK();
    EINA_LIST_FOREACH(shmpool, l, xob2)
      {
        int szdif;
@@ -69,8 +79,12 @@ _find_xob(Display *d, Visual *v, int depth, int w, int h, int shm, void *data)
          }
      }
    if ((fitness > (100 * 100)) || (!xob))
-     return evas_software_xlib_x_output_buffer_new(d, v, depth, w, h, shm, data);
-
+     {
+        SHMPOOL_UNLOCK();
+        xob = evas_software_xlib_x_output_buffer_new(d, v, depth, w, h, shm, data);
+        return xob;
+     }
+   
    have_xob:
    shmpool = eina_list_remove_list(shmpool, xl);
    xob->w = w;
@@ -80,6 +94,7 @@ _find_xob(Display *d, Visual *v, int depth, int w, int h, int shm, void *data)
    xob->xim->height = xob->h;
    xob->xim->bytes_per_line = xob->bpl;
    shmsize -= xob->psize * (xob->xim->depth / 8);
+   SHMPOOL_UNLOCK();
    return xob;
 }
 
@@ -89,6 +104,7 @@ _unfind_xob(X_Output_Buffer *xob, int sync)
 //   evas_software_xlib_x_output_buffer_free(xob, sync); return;
    if (xob->shm_info)
      {
+        SHMPOOL_LOCK();
        shmpool = eina_list_prepend(shmpool, xob);
        shmsize += xob->psize * xob->xim->depth / 8;
        while ((shmsize > (shmmemlimit)) ||
@@ -103,9 +119,11 @@ _unfind_xob(X_Output_Buffer *xob, int sync)
                  break;
               }
             xob = xl->data;
-            shmpool = eina_list_remove_list(shmpool, xl);
+             shmpool = eina_list_remove_list(shmpool, xl);
+             shmsize -= xob->psize * xob->xim->depth / 8;
             evas_software_xlib_x_output_buffer_free(xob, sync);
          }
+        SHMPOOL_UNLOCK();
      }
    else
      evas_software_xlib_x_output_buffer_free(xob, sync);
@@ -114,6 +132,7 @@ _unfind_xob(X_Output_Buffer *xob, int sync)
 static void
 _clear_xob(int sync)
 {
+   SHMPOOL_LOCK();
    while (shmpool)
      {
        X_Output_Buffer *xob;
@@ -123,16 +142,23 @@ _clear_xob(int sync)
        evas_software_xlib_x_output_buffer_free(xob, sync);
      }
    shmsize = 0;
+   SHMPOOL_UNLOCK();
 }
 
 void
 evas_software_xlib_outbuf_init(void)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKI(lock_shmpool);
+#endif
 }
 
 void
 evas_software_xlib_outbuf_free(Outbuf *buf)
 {
+#ifdef EVAS_FRAME_QUEUING
+   LKL(buf->priv.lock);
+#endif
    while (buf->priv.pending_writes)
      {
        RGBA_Image *im;
@@ -146,6 +172,9 @@ evas_software_xlib_outbuf_free(Outbuf *buf)
        if (obr->mxob) _unfind_xob(obr->mxob, 0);
        free(obr);
      }
+#ifdef EVAS_FRAME_QUEUING
+   LKU(buf->priv.lock);
+#endif
    evas_software_xlib_outbuf_idle_flush(buf);
    evas_software_xlib_outbuf_flush(buf);
    if (buf->priv.x11.xlib.gc)
@@ -155,6 +184,9 @@ evas_software_xlib_outbuf_free(Outbuf *buf)
    if (buf->priv.pal)
       evas_software_xlib_x_color_deallocate(buf->priv.x11.xlib.disp, buf->priv.x11.xlib.cmap,
                                           buf->priv.x11.xlib.vis, buf->priv.pal);
+#ifdef EVAS_FRAME_QUEUING
+   LKD(buf->priv.lock);
+#endif
    free(buf);
    _clear_xob(0);
 }
@@ -331,6 +363,9 @@ evas_software_xlib_outbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth,
       evas_software_xlib_outbuf_drawable_set(buf, draw);
       evas_software_xlib_outbuf_mask_set(buf, mask);
    }
+#ifdef EVAS_FRAME_QUEUING
+   LKI(buf->priv.lock);
+#endif
    return buf;
 }
 
@@ -578,7 +613,10 @@ evas_software_xlib_outbuf_new_region_for_update(Outbuf *buf, int x, int y, int w
      /* FIXME: faster memset! */
      memset(im->image.data, 0, w * h * sizeof(DATA32));
 
-   buf->priv.pending_writes = eina_list_append(buf->priv.pending_writes, im);
+#ifdef EVAS_FRAME_QUEUING
+   if (!evas_common_frameq_enabled())
+#endif
+      buf->priv.pending_writes = eina_list_append(buf->priv.pending_writes, im);
    return im;
 }
 
@@ -653,6 +691,9 @@ evas_software_xlib_outbuf_flush(Outbuf *buf)
                                                       buf->priv.x11.xlib.gcm,
                                                       obr->x, obr->y, 0);
          }
+#ifdef EVAS_FRAME_QUEUING
+     LKL(buf->priv.lock);
+#endif
        while (buf->priv.prev_pending_writes)
          {
             im = buf->priv.prev_pending_writes->data;
@@ -670,6 +711,9 @@ evas_software_xlib_outbuf_flush(Outbuf *buf)
             free(obr);
          }
        buf->priv.prev_pending_writes = buf->priv.pending_writes;
+#ifdef EVAS_FRAME_QUEUING
+     LKU(buf->priv.lock);
+#endif
        buf->priv.pending_writes = NULL;
        XFlush(buf->priv.x11.xlib.disp);
 #else
@@ -734,6 +778,9 @@ evas_software_xlib_outbuf_idle_flush(Outbuf *buf)
      }
    else
      {
+#ifdef EVAS_FRAME_QUEUING
+     LKL(buf->priv.lock);
+#endif
        if (buf->priv.prev_pending_writes) XSync(buf->priv.x11.xlib.disp, False);
        while (buf->priv.prev_pending_writes)
          {
@@ -750,6 +797,9 @@ evas_software_xlib_outbuf_idle_flush(Outbuf *buf)
             if (obr->mxob) _unfind_xob(obr->mxob, 0);
             free(obr);
          }
+#ifdef EVAS_FRAME_QUEUING
+     LKU(buf->priv.lock);
+#endif
        _clear_xob(0);
      }
 }
@@ -1036,3 +1086,12 @@ evas_software_xlib_outbuf_alpha_get(Outbuf *buf)
 {
    return buf->priv.x11.xlib.mask;
 }
+
+#ifdef EVAS_FRAME_QUEUING
+void
+evas_software_xlib_outbuf_set_priv(Outbuf *buf, void *cur, void *prev)
+{
+   buf->priv.pending_writes = (Eina_List *)cur;
+}
+
+#endif
index 8745a1a..d70eb8d 100644 (file)
@@ -83,5 +83,10 @@ void         evas_software_xlib_outbuf_debug_show (Outbuf  *buf,
                                                    int      h);
 
 Eina_Bool    evas_software_xlib_outbuf_alpha_get (Outbuf *buf);
+#ifdef EVAS_FRAME_QUEUING
+void         evas_software_xlib_outbuf_set_priv (Outbuf *buf,
+                                                  void *cur,
+                                                  void *prev);
+#endif
 
 #endif
index 0b5b81a..b329ae4 100644 (file)
@@ -37,5 +37,8 @@ struct _Evas_Engine_Info_XRender_X11
       void                            *visual;
       unsigned char                    destination_alpha : 1;
    } info;
+
+   /* non-blocking or blocking mode */
+   Evas_Engine_Render_Mode render_mode;
 };
 #endif
index 174287d..fcb4f09 100644 (file)
@@ -462,6 +462,7 @@ eng_info(Evas *e __UNUSED__)
    info = calloc(1, sizeof(Evas_Engine_Info_XRender_X11));
    if (!info) return NULL;
    info->magic.magic = rand();
+   info->render_mode = EVAS_RENDER_MODE_BLOCKING;
    return info;
 }