From eaad0eb095bd06277b68fdf6fc7d32542b9e159d Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Fri, 21 May 2010 07:10:45 +0000 Subject: [PATCH] big patch from Samsung SAIT (Advanced research group) for async multi-frame 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 SVN revision: 49087 --- legacy/ecore/AUTHORS | 2 + legacy/ecore/src/lib/ecore/ecore_private.h | 2 + .../ecore/src/lib/ecore_evas/ecore_evas_x.c | 48 +- legacy/ecore/src/lib/ecore_x/xlib/ecore_x.c | 3 + legacy/evas/AUTHORS | 2 + legacy/evas/README.in | 5 + legacy/evas/configure.ac | 33 + legacy/evas/src/lib/Evas.h | 7 + legacy/evas/src/lib/cache/evas_cache.h | 3 + legacy/evas/src/lib/cache/evas_cache_image.c | 211 ++- legacy/evas/src/lib/canvas/evas_main.c | 19 + .../src/lib/canvas/evas_object_gradient.c | 52 +- .../src/lib/canvas/evas_object_gradient2.c | 21 +- .../evas/src/lib/canvas/evas_object_image.c | 26 +- legacy/evas/src/lib/canvas/evas_object_main.c | 4 + legacy/evas/src/lib/canvas/evas_object_text.c | 10 + .../src/lib/canvas/evas_object_textblock.c | 9 +- legacy/evas/src/lib/canvas/evas_render.c | 34 +- .../evas/src/lib/engines/common/Makefile.am | 1 + .../src/lib/engines/common/evas_font_draw.c | 30 + .../src/lib/engines/common/evas_font_load.c | 49 + .../src/lib/engines/common/evas_font_main.c | 6 + .../lib/engines/common/evas_font_private.h | 81 + .../src/lib/engines/common/evas_font_query.c | 6 + .../lib/engines/common/evas_gradient2_main.c | 9 + .../lib/engines/common/evas_gradient_main.c | 9 + .../src/lib/engines/common/evas_image_main.c | 11 + .../engines/common/evas_image_scalecache.c | 88 +- .../src/lib/engines/common/evas_intl_utils.c | 9 +- .../evas/src/lib/engines/common/evas_pipe.c | 1430 ++++++++++++++--- .../evas/src/lib/engines/common/evas_pipe.h | 83 + legacy/evas/src/lib/include/evas_common.h | 56 + .../engines/buffer/Evas_Engine_Buffer.h | 3 + .../src/modules/engines/buffer/evas_engine.c | 1 + .../engines/cairo_x11/Evas_Engine_Cairo_X11.h | 3 + .../modules/engines/cairo_x11/evas_engine.c | 1 + .../engines/direct3d/Evas_Engine_Direct3D.h | 3 + .../modules/engines/direct3d/evas_engine.c | 1 + .../engines/directfb/Evas_Engine_DirectFB.h | 3 + .../src/modules/engines/fb/Evas_Engine_FB.h | 3 + .../evas/src/modules/engines/fb/evas_engine.c | 1 + .../engines/gl_glew/Evas_Engine_GL_Glew.h | 3 + .../src/modules/engines/gl_glew/evas_engine.c | 1 + .../engines/gl_x11/Evas_Engine_GL_X11.h | 5 +- .../src/modules/engines/gl_x11/evas_engine.c | 1 + .../engines/quartz/Evas_Engine_Quartz.h | 3 + .../src/modules/engines/quartz/evas_engine.c | 1 + .../Evas_Engine_Software_16_DDraw.h | 3 + .../engines/software_16_ddraw/evas_engine.c | 1 + .../software_16_sdl/Evas_Engine_SDL_16.h | 3 + .../Evas_Engine_Software_16_WinCE.h | 3 + .../engines/software_16_wince/evas_engine.c | 1 + .../Evas_Engine_Software_16_X11.h | 3 + .../engines/software_16_x11/evas_engine.c | 1 + .../Evas_Engine_Software_DDraw.h | 3 + .../engines/software_ddraw/evas_engine.c | 1 + .../software_gdi/Evas_Engine_Software_Gdi.h | 3 + .../engines/software_generic/evas_engine.c | 59 +- .../Evas_Engine_Software_Qtopia.h | 3 + .../engines/software_qtopia/evas_engine.c | 1 + .../engines/software_sdl/Evas_Engine_SDL.h | 3 + .../software_x11/Evas_Engine_Software_X11.h | 2 + .../engines/software_x11/evas_engine.c | 119 +- .../engines/software_x11/evas_engine.h | 4 + .../engines/software_x11/evas_xlib_buffer.c | 11 + .../engines/software_x11/evas_xlib_outbuf.c | 67 +- .../engines/software_x11/evas_xlib_outbuf.h | 5 + .../xrender_x11/Evas_Engine_XRender_X11.h | 3 + .../modules/engines/xrender_x11/evas_engine.c | 1 + 69 files changed, 2399 insertions(+), 293 deletions(-) create mode 100644 legacy/evas/src/lib/engines/common/evas_font_private.h diff --git a/legacy/ecore/AUTHORS b/legacy/ecore/AUTHORS index 4acdbfbb7e..e9bda2057b 100644 --- a/legacy/ecore/AUTHORS +++ b/legacy/ecore/AUTHORS @@ -29,3 +29,5 @@ Lars Munch Andre Dieb Mathieu Taillefumier Rui Miguel Silva Seabra +Saumsung Electronics +Samsung SAIT diff --git a/legacy/ecore/src/lib/ecore/ecore_private.h b/legacy/ecore/src/lib/ecore/ecore_private.h index ea59794055..86c0d71f82 100644 --- a/legacy/ecore/src/lib/ecore/ecore_private.h +++ b/legacy/ecore/src/lib/ecore/ecore_private.h @@ -57,6 +57,8 @@ extern int _ecore_log_dom ; # define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) #endif +#define EVAS_FRAME_QUEUING 1 /* for test */ + #define READBUFSIZ 65536 #define ECORE_MAGIC_NONE 0x1234fedc diff --git a/legacy/ecore/src/lib/ecore_evas/ecore_evas_x.c b/legacy/ecore/src/lib/ecore_evas/ecore_evas_x.c index ff5a36eeb9..c322f65b89 100644 --- a/legacy/ecore/src/lib/ecore_evas/ecore_evas_x.c +++ b/legacy/ecore/src/lib/ecore_evas/ecore_evas_x.c @@ -237,9 +237,21 @@ _ecore_evas_x_render(Ecore_Evas *ee) EINA_LIST_FOREACH(updates, l, r) ecore_x_window_area_clear(ee->prop.window, r->x, r->y, r->w, r->h); if ((ee->shaped) && (updates)) - ecore_x_window_shape_mask_set(ee->prop.window, ee->engine.x.mask); -// if ((ee->alpha) && (updates)) -// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask); + { +#ifdef EVAS_FRAME_QUEUING + /* wait until ee->engine.x.mask being updated */ + evas_sync(ee->evas); +#endif + ecore_x_window_shape_mask_set(ee->prop.window, ee->engine.x.mask); + } + if ((ee->alpha) && (updates)) + { +#ifdef EVAS_FRAME_QUEUING + /* wait until ee->engine.x.mask being updated */ +// evas_sync(ee->evas); +#endif +// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask); + } evas_render_updates_free(updates); _ecore_evas_idle_timeout_update(ee); rend = 1; @@ -351,14 +363,25 @@ _ecore_evas_x_render(Ecore_Evas *ee) ((ee->should_be_visible) && (ee->prop.fullscreen)) || ((ee->should_be_visible) && (ee->prop.override))) { - updates = evas_render_updates(ee->evas); if (updates) { if (ee->shaped) - ecore_x_window_shape_mask_set(ee->prop.window, ee->engine.x.mask); -// if (ee->alpha) -// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask); + { +#ifdef EVAS_FRAME_QUEUING + /* wait until ee->engine.x.mask being updated */ + evas_sync(ee->evas); +#endif + ecore_x_window_shape_mask_set(ee->prop.window, ee->engine.x.mask); + } + if (ee->alpha) + { +#ifdef EVAS_FRAME_QUEUING + /* wait until ee->engine.x.mask being updated */ +// evas_sync(ee->evas); +#endif +// ecore_x_window_shape_input_mask_set(ee->prop.window, ee->engine.x.mask); + } evas_render_updates_free(updates); _ecore_evas_idle_timeout_update(ee); rend = 1; @@ -2829,6 +2852,17 @@ ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB; einfo->info.connection = ecore_x_display_get(); einfo->info.screen = NULL; +#ifdef EVAS_FRAME_QUEUING + { + char *render_mode; + render_mode = getenv("EVAS_RENDER_MODE"); + if (render_mode && !strcmp(render_mode, "non-blocking")) + { + einfo->render_mode = EVAS_RENDER_MODE_NONBLOCKING; + } + } +#endif + # endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ einfo->info.drawable = ee->prop.window; if (argb) diff --git a/legacy/ecore/src/lib/ecore_x/xlib/ecore_x.c b/legacy/ecore/src/lib/ecore_x/xlib/ecore_x.c index 547b7ba7f1..32c27f5416 100644 --- a/legacy/ecore/src/lib/ecore_x/xlib/ecore_x.c +++ b/legacy/ecore/src/lib/ecore_x/xlib/ecore_x.c @@ -254,6 +254,9 @@ ecore_x_init(const char *name) _ecore_xlib_log_dom = -1; return --_ecore_x_init_count; } +#ifdef EVAS_FRAME_QUEUING + XInitThreads(); +#endif _ecore_x_disp = XOpenDisplay((char *)name); if (!_ecore_x_disp) goto shutdown_ecore_event; diff --git a/legacy/evas/AUTHORS b/legacy/evas/AUTHORS index fce4857826..d9c7f7be02 100644 --- a/legacy/evas/AUTHORS +++ b/legacy/evas/AUTHORS @@ -18,3 +18,5 @@ Tom Hacohen Mathieu Taillefumier Iván Briano Gustavo Lima Chaves +Saumsung Electronics +Samsung SAIT diff --git a/legacy/evas/README.in b/legacy/evas/README.in index b0897f995c..1e3e6c96af 100644 --- a/legacy/evas/README.in +++ b/legacy/evas/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 diff --git a/legacy/evas/configure.ac b/legacy/evas/configure.ac index e865dd8422..a30d5f9e4c 100644 --- a/legacy/evas/configure.ac +++ b/legacy/evas/configure.ac @@ -760,6 +760,38 @@ else build_pipe_render="no" 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" @@ -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 diff --git a/legacy/evas/src/lib/Evas.h b/legacy/evas/src/lib/Evas.h index 05900496e9..f5f9628d86 100644 --- a/legacy/evas/src/lib/Evas.h +++ b/legacy/evas/src/lib/Evas.h @@ -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); /** diff --git a/legacy/evas/src/lib/cache/evas_cache.h b/legacy/evas/src/lib/cache/evas_cache.h index 462d35a05f..80aedcf4b4 100644 --- a/legacy/evas/src/lib/cache/evas_cache.h +++ b/legacy/evas/src/lib/cache/evas_cache.h @@ -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 diff --git a/legacy/evas/src/lib/cache/evas_cache_image.c b/legacy/evas/src/lib/cache/evas_cache_image.c index 68a1d607b0..5bf0e84373 100644 --- a/legacy/evas/src/lib/cache/evas_cache_image.c +++ b/legacy/evas/src/lib/cache/evas_cache_image.c @@ -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; } diff --git a/legacy/evas/src/lib/canvas/evas_main.c b/legacy/evas/src/lib/canvas/evas_main.c index c60cb2152d..5c7e60617d 100644 --- a/legacy/evas/src/lib/canvas/evas_main.c +++ b/legacy/evas/src/lib/canvas/evas_main.c @@ -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; diff --git a/legacy/evas/src/lib/canvas/evas_object_gradient.c b/legacy/evas/src/lib/canvas/evas_object_gradient.c index 54b50c9028..73dbc9f844 100644 --- a/legacy/evas/src/lib/canvas/evas_object_gradient.c +++ b/legacy/evas/src/lib/canvas/evas_object_gradient.c @@ -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); diff --git a/legacy/evas/src/lib/canvas/evas_object_gradient2.c b/legacy/evas/src/lib/canvas/evas_object_gradient2.c index ab003ce4b2..6511aa5409 100644 --- a/legacy/evas/src/lib/canvas/evas_object_gradient2.c +++ b/legacy/evas/src/lib/canvas/evas_object_gradient2.c @@ -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); diff --git a/legacy/evas/src/lib/canvas/evas_object_image.c b/legacy/evas/src/lib/canvas/evas_object_image.c index 233c5d8dd4..109af58569 100644 --- a/legacy/evas/src/lib/canvas/evas_object_image.c +++ b/legacy/evas/src/lib/canvas/evas_object_image.c @@ -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; } diff --git a/legacy/evas/src/lib/canvas/evas_object_main.c b/legacy/evas/src/lib/canvas/evas_object_main.c index 8173d4ad0f..1cbb9aada3 100644 --- a/legacy/evas/src/lib/canvas/evas_object_main.c +++ b/legacy/evas/src/lib/canvas/evas_object_main.c @@ -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); diff --git a/legacy/evas/src/lib/canvas/evas_object_text.c b/legacy/evas/src/lib/canvas/evas_object_text.c index 575b449d5c..1b89f7ed1f 100644 --- a/legacy/evas/src/lib/canvas/evas_object_text.c +++ b/legacy/evas/src/lib/canvas/evas_object_text.c @@ -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, diff --git a/legacy/evas/src/lib/canvas/evas_object_textblock.c b/legacy/evas/src/lib/canvas/evas_object_textblock.c index 50f5295c10..ca0fd87bc5 100644 --- a/legacy/evas/src/lib/canvas/evas_object_textblock.c +++ b/legacy/evas/src/lib/canvas/evas_object_textblock.c @@ -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; diff --git a/legacy/evas/src/lib/canvas/evas_render.c b/legacy/evas/src/lib/canvas/evas_render.c index e871e9e819..a30f32cf1c 100644 --- a/legacy/evas/src/lib/canvas/evas_render.c +++ b/legacy/evas/src/lib/canvas/evas_render.c @@ -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; } diff --git a/legacy/evas/src/lib/engines/common/Makefile.am b/legacy/evas/src/lib/engines/common/Makefile.am index f8669ae937..b0d0d350e4 100644 --- a/legacy/evas/src/lib/engines/common/Makefile.am +++ b/legacy/evas/src/lib/engines/common/Makefile.am @@ -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 \ diff --git a/legacy/evas/src/lib/engines/common/evas_font_draw.c b/legacy/evas/src/lib/engines/common/evas_font_draw.c index 87372de2ca..d629718c85 100644 --- a/legacy/evas/src/lib/engines/common/evas_font_draw.c +++ b/legacy/evas/src/lib/engines/common/evas_font_draw.c @@ -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 } diff --git a/legacy/evas/src/lib/engines/common/evas_font_load.c b/legacy/evas/src/lib/engines/common/evas_font_load.c index d754cf08db..a6b07e12be 100644 --- a/legacy/evas/src/lib/engines/common/evas_font_load.c +++ b/legacy/evas/src/lib/engines/common/evas_font_load.c @@ -7,6 +7,8 @@ #include +#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); } diff --git a/legacy/evas/src/lib/engines/common/evas_font_main.c b/legacy/evas/src/lib/engines/common/evas_font_main.c index afe1b11a66..d1aa51eaeb 100644 --- a/legacy/evas/src/lib/engines/common/evas_font_main.c +++ b/legacy/evas/src/lib/engines/common/evas_font_main.c @@ -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/legacy/evas/src/lib/engines/common/evas_font_private.h b/legacy/evas/src/lib/engines/common/evas_font_private.h new file mode 100644 index 0000000000..12ab17b2fc --- /dev/null +++ b/legacy/evas/src/lib/engines/common/evas_font_private.h @@ -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 */ + diff --git a/legacy/evas/src/lib/engines/common/evas_font_query.c b/legacy/evas/src/lib/engines/common/evas_font_query.c index c626612d3c..d1b2f99bd7 100644 --- a/legacy/evas/src/lib/engines/common/evas_font_query.c +++ b/legacy/evas/src/lib/engines/common/evas_font_query.c @@ -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];) { diff --git a/legacy/evas/src/lib/engines/common/evas_gradient2_main.c b/legacy/evas/src/lib/engines/common/evas_gradient2_main.c index e2b0d9762f..5d3893e187 100644 --- a/legacy/evas/src/lib/engines/common/evas_gradient2_main.c +++ b/legacy/evas/src/lib/engines/common/evas_gradient2_main.c @@ -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); diff --git a/legacy/evas/src/lib/engines/common/evas_gradient_main.c b/legacy/evas/src/lib/engines/common/evas_gradient_main.c index 3d11fba726..9aa9b67a0b 100644 --- a/legacy/evas/src/lib/engines/common/evas_gradient_main.c +++ b/legacy/evas/src/lib/engines/common/evas_gradient_main.c @@ -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); diff --git a/legacy/evas/src/lib/engines/common/evas_image_main.c b/legacy/evas/src/lib/engines/common/evas_image_main.c index 899a769da6..a86962e2c7 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_main.c +++ b/legacy/evas/src/lib/engines/common/evas_image_main.c @@ -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); diff --git a/legacy/evas/src/lib/engines/common/evas_image_scalecache.c b/legacy/evas/src/lib/engines/common/evas_image_scalecache.c index 4391bebe2d..71ae93ed89 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_scalecache.c +++ b/legacy/evas/src/lib/engines/common/evas_image_scalecache.c @@ -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) diff --git a/legacy/evas/src/lib/engines/common/evas_intl_utils.c b/legacy/evas/src/lib/engines/common/evas_intl_utils.c index 90ccfcb183..0cf52121f4 100644 --- a/legacy/evas/src/lib/engines/common/evas_intl_utils.c +++ b/legacy/evas/src/lib/engines/common/evas_intl_utils.c @@ -4,6 +4,8 @@ #include "evas_common.h" #include "evas_intl_utils.h" +#include "evas_font_private.h" + #ifdef INTERNATIONAL_SUPPORT #include @@ -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; diff --git a/legacy/evas/src/lib/engines/common/evas_pipe.c b/legacy/evas/src/lib/engines/common/evas_pipe.c index bafb95adac..b2f686a929 100644 --- a/legacy/evas/src/lib/engines/common/evas_pipe.c +++ b/legacy/evas/src/lib/engines/common/evas_pipe.c @@ -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 -{ - int thread_num; - pthread_t thread_id; - pthread_barrier_t *barrier; - RGBA_Pipe_Thread_Info *info; -} Thinfo; - +/* main api calls */ static void * evas_common_pipe_thread(void *data) { Thinfo *thinfo; -// INF("TH [..........."); +// INF("TH [..........."); thinfo = data; for (;;) { - RGBA_Pipe_Thread_Info *info; - RGBA_Pipe *p; + 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; + /* 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])); + 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_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; + + 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 (;;) + { + 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 diff --git a/legacy/evas/src/lib/engines/common/evas_pipe.h b/legacy/evas/src/lib/engines/common/evas_pipe.h index 77c5dd32d9..651582c46d 100644 --- a/legacy/evas/src/lib/engines/common/evas_pipe.h +++ b/legacy/evas/src/lib/engines/common/evas_pipe.h @@ -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 */ diff --git a/legacy/evas/src/lib/include/evas_common.h b/legacy/evas/src/lib/include/evas_common.h index dff7224c82..9e7626399b 100644 --- a/legacy/evas/src/lib/include/evas_common.h +++ b/legacy/evas/src/lib/include/evas_common.h @@ -136,7 +136,14 @@ extern EAPI int _evas_log_dom_global; # include # include # 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 diff --git a/legacy/evas/src/modules/engines/buffer/Evas_Engine_Buffer.h b/legacy/evas/src/modules/engines/buffer/Evas_Engine_Buffer.h index 02dea14bac..e6d11d145a 100644 --- a/legacy/evas/src/modules/engines/buffer/Evas_Engine_Buffer.h +++ b/legacy/evas/src/modules/engines/buffer/Evas_Engine_Buffer.h @@ -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 diff --git a/legacy/evas/src/modules/engines/buffer/evas_engine.c b/legacy/evas/src/modules/engines/buffer/evas_engine.c index 1c6abc047c..0add00190d 100644 --- a/legacy/evas/src/modules/engines/buffer/evas_engine.c +++ b/legacy/evas/src/modules/engines/buffer/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/cairo_x11/Evas_Engine_Cairo_X11.h b/legacy/evas/src/modules/engines/cairo_x11/Evas_Engine_Cairo_X11.h index 3a7d64aa54..65503a0935 100644 --- a/legacy/evas/src/modules/engines/cairo_x11/Evas_Engine_Cairo_X11.h +++ b/legacy/evas/src/modules/engines/cairo_x11/Evas_Engine_Cairo_X11.h @@ -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 diff --git a/legacy/evas/src/modules/engines/cairo_x11/evas_engine.c b/legacy/evas/src/modules/engines/cairo_x11/evas_engine.c index df81a2fd9e..36c834d502 100644 --- a/legacy/evas/src/modules/engines/cairo_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/cairo_x11/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/direct3d/Evas_Engine_Direct3D.h b/legacy/evas/src/modules/engines/direct3d/Evas_Engine_Direct3D.h index 05359a3044..f9b7a9c592 100644 --- a/legacy/evas/src/modules/engines/direct3d/Evas_Engine_Direct3D.h +++ b/legacy/evas/src/modules/engines/direct3d/Evas_Engine_Direct3D.h @@ -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; }; diff --git a/legacy/evas/src/modules/engines/direct3d/evas_engine.c b/legacy/evas/src/modules/engines/direct3d/evas_engine.c index 8514f75254..5fcd89d7c3 100644 --- a/legacy/evas/src/modules/engines/direct3d/evas_engine.c +++ b/legacy/evas/src/modules/engines/direct3d/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/directfb/Evas_Engine_DirectFB.h b/legacy/evas/src/modules/engines/directfb/Evas_Engine_DirectFB.h index f4177e1e3e..a2e9d3ae43 100644 --- a/legacy/evas/src/modules/engines/directfb/Evas_Engine_DirectFB.h +++ b/legacy/evas/src/modules/engines/directfb/Evas_Engine_DirectFB.h @@ -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 diff --git a/legacy/evas/src/modules/engines/fb/Evas_Engine_FB.h b/legacy/evas/src/modules/engines/fb/Evas_Engine_FB.h index 7166e42a10..b548237857 100644 --- a/legacy/evas/src/modules/engines/fb/Evas_Engine_FB.h +++ b/legacy/evas/src/modules/engines/fb/Evas_Engine_FB.h @@ -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 diff --git a/legacy/evas/src/modules/engines/fb/evas_engine.c b/legacy/evas/src/modules/engines/fb/evas_engine.c index 47386bad1e..a0b5e3d729 100644 --- a/legacy/evas/src/modules/engines/fb/evas_engine.c +++ b/legacy/evas/src/modules/engines/fb/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/gl_glew/Evas_Engine_GL_Glew.h b/legacy/evas/src/modules/engines/gl_glew/Evas_Engine_GL_Glew.h index c254fd09bc..a83496e0b9 100644 --- a/legacy/evas/src/modules/engines/gl_glew/Evas_Engine_GL_Glew.h +++ b/legacy/evas/src/modules/engines/gl_glew/Evas_Engine_GL_Glew.h @@ -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; }; diff --git a/legacy/evas/src/modules/engines/gl_glew/evas_engine.c b/legacy/evas/src/modules/engines/gl_glew/evas_engine.c index 1fabf66823..37b0f435e8 100644 --- a/legacy/evas/src/modules/engines/gl_glew/evas_engine.c +++ b/legacy/evas/src/modules/engines/gl_glew/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/gl_x11/Evas_Engine_GL_X11.h b/legacy/evas/src/modules/engines/gl_x11/Evas_Engine_GL_X11.h index 2e0461cb24..7224f9c936 100644 --- a/legacy/evas/src/modules/engines/gl_x11/Evas_Engine_GL_X11.h +++ b/legacy/evas/src/modules/engines/gl_x11/Evas_Engine_GL_X11.h @@ -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 diff --git a/legacy/evas/src/modules/engines/gl_x11/evas_engine.c b/legacy/evas/src/modules/engines/gl_x11/evas_engine.c index 243f40d224..e9d2484aeb 100644 --- a/legacy/evas/src/modules/engines/gl_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/gl_x11/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h b/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h index abca92276e..0a277f4597 100644 --- a/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h +++ b/legacy/evas/src/modules/engines/quartz/Evas_Engine_Quartz.h @@ -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 diff --git a/legacy/evas/src/modules/engines/quartz/evas_engine.c b/legacy/evas/src/modules/engines/quartz/evas_engine.c index 68437029ad..160f043037 100644 --- a/legacy/evas/src/modules/engines/quartz/evas_engine.c +++ b/legacy/evas/src/modules/engines/quartz/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h b/legacy/evas/src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h index 7c3d888f43..3c1547a26d 100644 --- a/legacy/evas/src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h +++ b/legacy/evas/src/modules/engines/software_16_ddraw/Evas_Engine_Software_16_DDraw.h @@ -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; }; diff --git a/legacy/evas/src/modules/engines/software_16_ddraw/evas_engine.c b/legacy/evas/src/modules/engines/software_16_ddraw/evas_engine.c index 6e2abb0309..90f11620c6 100644 --- a/legacy/evas/src/modules/engines/software_16_ddraw/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_16_ddraw/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_16_sdl/Evas_Engine_SDL_16.h b/legacy/evas/src/modules/engines/software_16_sdl/Evas_Engine_SDL_16.h index 20adccffae..5a133fecf1 100644 --- a/legacy/evas/src/modules/engines/software_16_sdl/Evas_Engine_SDL_16.h +++ b/legacy/evas/src/modules/engines/software_16_sdl/Evas_Engine_SDL_16.h @@ -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 diff --git a/legacy/evas/src/modules/engines/software_16_wince/Evas_Engine_Software_16_WinCE.h b/legacy/evas/src/modules/engines/software_16_wince/Evas_Engine_Software_16_WinCE.h index d9d45a5934..e94b7c2384 100644 --- a/legacy/evas/src/modules/engines/software_16_wince/Evas_Engine_Software_16_WinCE.h +++ b/legacy/evas/src/modules/engines/software_16_wince/Evas_Engine_Software_16_WinCE.h @@ -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; }; diff --git a/legacy/evas/src/modules/engines/software_16_wince/evas_engine.c b/legacy/evas/src/modules/engines/software_16_wince/evas_engine.c index 886fa0f706..b994a9aa81 100644 --- a/legacy/evas/src/modules/engines/software_16_wince/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_16_wince/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_16_x11/Evas_Engine_Software_16_X11.h b/legacy/evas/src/modules/engines/software_16_x11/Evas_Engine_Software_16_X11.h index 47885fa2d6..9768f0a4fd 100644 --- a/legacy/evas/src/modules/engines/software_16_x11/Evas_Engine_Software_16_X11.h +++ b/legacy/evas/src/modules/engines/software_16_x11/Evas_Engine_Software_16_X11.h @@ -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 diff --git a/legacy/evas/src/modules/engines/software_16_x11/evas_engine.c b/legacy/evas/src/modules/engines/software_16_x11/evas_engine.c index 32a88ba2e0..7f753fcf46 100644 --- a/legacy/evas/src/modules/engines/software_16_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_16_x11/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_ddraw/Evas_Engine_Software_DDraw.h b/legacy/evas/src/modules/engines/software_ddraw/Evas_Engine_Software_DDraw.h index e06ef4e025..9735bb7c8b 100644 --- a/legacy/evas/src/modules/engines/software_ddraw/Evas_Engine_Software_DDraw.h +++ b/legacy/evas/src/modules/engines/software_ddraw/Evas_Engine_Software_DDraw.h @@ -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; }; diff --git a/legacy/evas/src/modules/engines/software_ddraw/evas_engine.c b/legacy/evas/src/modules/engines/software_ddraw/evas_engine.c index 426f949d92..114f5860cc 100644 --- a/legacy/evas/src/modules/engines/software_ddraw/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_ddraw/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_gdi/Evas_Engine_Software_Gdi.h b/legacy/evas/src/modules/engines/software_gdi/Evas_Engine_Software_Gdi.h index a95b07eb0d..032ec8da16 100644 --- a/legacy/evas/src/modules/engines/software_gdi/Evas_Engine_Software_Gdi.h +++ b/legacy/evas/src/modules/engines/software_gdi/Evas_Engine_Software_Gdi.h @@ -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; }; diff --git a/legacy/evas/src/modules/engines/software_generic/evas_engine.c b/legacy/evas/src/modules/engines/software_generic/evas_engine.c index 77671bedef..a28185edb2 100644 --- a/legacy/evas/src/modules/engines/software_generic/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_generic/evas_engine.c @@ -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 diff --git a/legacy/evas/src/modules/engines/software_qtopia/Evas_Engine_Software_Qtopia.h b/legacy/evas/src/modules/engines/software_qtopia/Evas_Engine_Software_Qtopia.h index 5b863b0e22..6878b053a3 100644 --- a/legacy/evas/src/modules/engines/software_qtopia/Evas_Engine_Software_Qtopia.h +++ b/legacy/evas/src/modules/engines/software_qtopia/Evas_Engine_Software_Qtopia.h @@ -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 diff --git a/legacy/evas/src/modules/engines/software_qtopia/evas_engine.c b/legacy/evas/src/modules/engines/software_qtopia/evas_engine.c index 89b139a212..bee5a80711 100644 --- a/legacy/evas/src/modules/engines/software_qtopia/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_qtopia/evas_engine.c @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_sdl/Evas_Engine_SDL.h b/legacy/evas/src/modules/engines/software_sdl/Evas_Engine_SDL.h index 71efa8aade..3cce6ece82 100644 --- a/legacy/evas/src/modules/engines/software_sdl/Evas_Engine_SDL.h +++ b/legacy/evas/src/modules/engines/software_sdl/Evas_Engine_SDL.h @@ -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 diff --git a/legacy/evas/src/modules/engines/software_x11/Evas_Engine_Software_X11.h b/legacy/evas/src/modules/engines/software_x11/Evas_Engine_Software_X11.h index 6b0f692c03..de6da96f99 100644 --- a/legacy/evas/src/modules/engines/software_x11/Evas_Engine_Software_X11.h +++ b/legacy/evas/src/modules/engines/software_x11/Evas_Engine_Software_X11.h @@ -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 diff --git a/legacy/evas/src/modules/engines/software_x11/evas_engine.c b/legacy/evas/src/modules/engines/software_x11/evas_engine.c index 2788fc6c64..0812e4c55a 100644 --- a/legacy/evas/src/modules/engines/software_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/software_x11/evas_engine.c @@ -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,23 +731,112 @@ 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_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; + + re = (Render_Engine *)data; + re->outbuf_flush(re->ob); +} + +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; - re->outbuf_flush(re->ob); +#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 @@ -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; } diff --git a/legacy/evas/src/modules/engines/software_x11/evas_engine.h b/legacy/evas/src/modules/engines/software_x11/evas_engine.h index e3eb1842cb..808a3e5be3 100644 --- a/legacy/evas/src/modules/engines/software_x11/evas_engine.h +++ b/legacy/evas/src/modules/engines/software_x11/evas_engine.h @@ -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; diff --git a/legacy/evas/src/modules/engines/software_x11/evas_xlib_buffer.c b/legacy/evas/src/modules/engines/software_x11/evas_xlib_buffer.c index a077963e16..873a67e7a3 100644 --- a/legacy/evas/src/modules/engines/software_x11/evas_xlib_buffer.c +++ b/legacy/evas/src/modules/engines/software_x11/evas_xlib_buffer.c @@ -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); diff --git a/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c b/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c index 6e1ac92e56..7274c1a9d9 100644 --- a/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c +++ b/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.c @@ -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 diff --git a/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.h b/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.h index 8745a1abfd..d70eb8d053 100644 --- a/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.h +++ b/legacy/evas/src/modules/engines/software_x11/evas_xlib_outbuf.h @@ -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 diff --git a/legacy/evas/src/modules/engines/xrender_x11/Evas_Engine_XRender_X11.h b/legacy/evas/src/modules/engines/xrender_x11/Evas_Engine_XRender_X11.h index 0b5b81a9ff..b329ae4334 100644 --- a/legacy/evas/src/modules/engines/xrender_x11/Evas_Engine_XRender_X11.h +++ b/legacy/evas/src/modules/engines/xrender_x11/Evas_Engine_XRender_X11.h @@ -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 diff --git a/legacy/evas/src/modules/engines/xrender_x11/evas_engine.c b/legacy/evas/src/modules/engines/xrender_x11/evas_engine.c index 174287d409..fcb4f0911d 100644 --- a/legacy/evas/src/modules/engines/xrender_x11/evas_engine.c +++ b/legacy/evas/src/modules/engines/xrender_x11/evas_engine.c @@ -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; }