Mathieu Taillefumier <mathieu.taillefumier@free.fr>
Iván Briano <ivan@profusion.mobi>
Gustavo Lima Chaves <glima@profusion.mobi>
+Saumsung Electronics <tbd>
+Samsung SAIT <tbd>
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
fi
#######################################
+## Async Renderer
+build_async_render="no"
+AC_MSG_CHECKING(whether to build Asynchronously Threaded Pipe Rendering support)
+AC_ARG_ENABLE(async-render,
+ AC_HELP_STRING([--enable-async-render], [enable asynchronously threaded pipe rendering support]),
+ [ build_async_render=$enableval ]
+)
+AC_MSG_RESULT($build_async_render)
+
+AC_MSG_CHECKING(whether we can build Asynchronously Threaded Pipe Rendering support)
+if test \( "x$build_async_render" = "xyes" \); then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(EVAS_FRAME_QUEUING, 1, [Build async render support])
+ build_async_render="yes"
+ AC_DEFINE(BUILD_PIPE_RENDER, 1, [Build pipe render support])
+ build_pipe_render="yes"
+ need_pthreads="yes"
+
+ PKG_CHECK_MODULES([XEXT],
+ [xext < 1.1.1],
+ [ build_avoid_libXext_bug=yes ],
+ [ build_avoid_libXext_bug=no ]
+ )
+ if test \( "x$build_avoid_libXext_bug" = "xyes" \); then
+ AC_DEFINE(LIBXEXT_VERSION_LOW, 1, [To avoid bug on old libXext version])
+ fi
+else
+ AC_MSG_RESULT(no)
+ build_async_render="no"
+fi
+
+#######################################
## Async events
build_async_events="auto"
AC_MSG_CHECKING(whether to build Async Events support)
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
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,
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);
/**
int usage;
int limit;
int references;
+#ifdef EVAS_FRAME_QUEUING
+ LK(lock);
+#endif
};
struct _Evas_Cache_Engine_Image_Func
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)
{
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
{
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
{
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
{
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
{
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));
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;
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);
#ifdef BUILD_ASYNC_PRELOAD
LKD(ie->lock);
#endif
+#ifdef EVAS_FRAME_QUEUING
+ LKD(ie->lock_references);
+#endif
cache->func.dealloc(ie);
}
ie->allocated.w = 0;
ie->allocated.h = 0;
+#ifdef EVAS_FRAME_QUEUING
+ LKI(ie->lock_references);
+#endif
ie->references = 0;
ie->cache = cache;
_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
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 *
new->preload = NULL;
new->pending = NULL;
+#ifdef EVAS_FRAME_QUEUING
+ LKI(new->lock);
+#endif
+
return new;
}
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)
eina_hash_free(cache->activ);
eina_hash_free(cache->inactiv);
+#ifdef EVAS_FRAME_QUEUING
+ LKU(cache->lock);
+ LKD(cache->lock);
+#endif
+
free(cache);
}
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;
_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;
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;
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)
{
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);
{
Image_Entry *im_dirty = im;
Evas_Cache_Image *cache;
+ int references;
assert(im);
assert(im->cache);
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
{
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);
}
{
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))
{
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);
}
_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);
_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);
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))
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);
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;
}
#ifdef BUILD_ASYNC_PRELOAD
_evas_preload_thread_init();
#endif
+#ifdef EVAS_FRAME_QUEUING
+ evas_common_frameq_init();
+#endif
return _evas_init_count;
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
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;
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;
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);
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);
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;
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);
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);
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);
}
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);
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)
{
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,
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);
}
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,
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;
}
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);
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)
{
MAGIC_CHECK_END();
if (e->hinting == hinting) return;
e->hinting = hinting;
+
EINA_INLIST_FOREACH(e->layers, lay)
{
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,
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;
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;
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);
}
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);
}
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.
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;
}
evas_convert_yuv.h \
evas_draw.h \
evas_font.h \
+evas_font_private.h \
evas_gradient.h \
evas_gradient_private.h \
evas_image.h \
#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)
// 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();
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);
}
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;
_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);
// 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);
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);
}
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
}
#include <assert.h>
+#include "evas_font_private.h" /* for Frame-Queuing support */
+
extern FT_Library evas_ft_lib;
static int font_cache_usage = 0;
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
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);
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);
}
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;
{
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;
}
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;
}
{
if (fi->src->current_size != fi->size)
{
+ FTLOCK();
FT_Activate_Size(fi->ft.size);
+ FTUNLOCK();
fi->src->current_size = fi->size;
}
}
int ret;
int error;
+ FTLOCK();
error = FT_New_Size(fi->src->ft.face, &(fi->ft.size));
if (!error)
{
fi->real_size = fi->size;
error = FT_Set_Pixel_Sizes(fi->src->ft.face, 0, fi->real_size);
}
+ FTUNLOCK();
if (error)
{
int i;
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? */
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;
}
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;
}
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--;
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);
}
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
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;
}
--- /dev/null
+#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 */
+
#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,
* 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);
goto on_correct;
}
+ FTUNLOCK();
error = 0;
on_correct:
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];)
{
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);
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);
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;
}
#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);
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;
{
#ifdef SCALECACHE
init--;
- LKD(cache_lock);
+ if (init ==0)
+ LKD(cache_lock);
#endif
}
{
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)
{
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);
{
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))
// 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
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;
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);
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);
}
}
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)
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)
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,
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)
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)
}
#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)
#include "evas_common.h"
#include "evas_intl_utils.h"
+#include "evas_font_private.h"
+
#ifdef INTERNATIONAL_SUPPORT
#include <fribidi/fribidi.h>
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));
}
fribidi_unicode_to_utf8(unicode_out, len, text_out);
-
+ FBDUNLOCK();
+
*ret_len = len;
return text_out;
#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);
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;
}
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
evas_common_draw_context_apply_clean_cutouts(&op->context.cutout);
}
-/* main api calls */
#ifdef BUILD_PTHREAD
-typedef struct _Thinfo
+/* main api calls */
+static void *
+evas_common_pipe_thread(void *data)
{
- int thread_num;
- pthread_t thread_id;
- pthread_barrier_t *barrier;
- RGBA_Pipe_Thread_Info *info;
-} Thinfo;
+ Thinfo *thinfo;
+
+// INF("TH [...........");
+ thinfo = data;
+ for (;;)
+ {
+ RGBA_Pipe_Thread_Info *info;
+ RGBA_Pipe *p;
+
+ /* wait for start signal */
+// INF(" TH %i START...", thinfo->thread_num);
+ pthread_barrier_wait(&(thinfo->barrier[0]));
+ info = thinfo->info;
+// if (info)
+// {
+// thinfo->info = NULL;
+// INF(" TH %i GO", thinfo->thread_num);
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->pipe), p)
+ {
+ int i;
+
+ for (i = 0; i < p->op_num; i++)
+ {
+ if (p->op[i].op_func)
+ p->op[i].op_func(info->im, &(p->op[i]), info);
+ }
+ }
+ free(info);
+// }
+// INF(" TH %i DONE", thinfo->thread_num);
+ /* send finished signal */
+ pthread_barrier_wait(&(thinfo->barrier[1]));
+ }
+ return NULL;
+}
+
+#ifdef EVAS_FRAME_QUEUING
+static void
+evas_common_frameq_release(void *data)
+{
+ Evas_FrameQ *frameq;
+ Evas_Frameq_Thread_Info *fq_info;
+ Thinfo *thinfo;
+
+ thinfo = data;
+ fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info);
+ frameq = fq_info->frameq;
+
+ /* This thread may or may not own the mutex.
+ * But there's no way to determine the ownership of the mutex, so release it anyway
+ */
+ LKU(frameq->mutex);
+}
static void *
-evas_common_pipe_thread(void *data)
+evas_common_frameq_thread(void *data)
{
+ Evas_FrameQ *frameq;
+ Evas_Frame *frame;
+ Evas_Surface *surface;
+ RGBA_Pipe *p;
Thinfo *thinfo;
+ Evas_Frameq_Thread_Info *fq_info;
+ RGBA_Pipe_Thread_Info p_info;
-// INF("TH [...........");
thinfo = data;
+ fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info);
+ frameq = fq_info->frameq;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ /* install thread cancelation cleanup handler */
+ pthread_cleanup_push(evas_common_frameq_release, data);
+
for (;;)
{
- RGBA_Pipe_Thread_Info *info;
- RGBA_Pipe *p;
-
- /* wait for start signal */
-// INF(" TH %i START...", thinfo->thread_num);
- pthread_barrier_wait(&(thinfo->barrier[0]));
- info = thinfo->info;
-// if (info)
-// {
-// thinfo->info = NULL;
-// INF(" TH %i GO", thinfo->thread_num);
- EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->pipe), p)
- {
- int i;
-
- for (i = 0; i < p->op_num; i++)
- {
- if (p->op[i].op_func)
- p->op[i].op_func(info->im, &(p->op[i]), info);
- }
- }
- free(info);
-// }
-// INF(" TH %i DONE", thinfo->thread_num);
- /* send finished signal */
- pthread_barrier_wait(&(thinfo->barrier[1]));
+ frame = NULL;
+
+ /* 1. pick a frame to draw */
+ LKL(frameq->mutex);
+ while(frame == NULL)
+ {
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), frame)
+ {
+ if (!frame->in_process)
+ {
+ frame->in_process = 1;
+ break;
+ }
+ }
+ if (frame)
+ {
+ break;
+ }
+ pthread_testcancel();
+ pthread_cond_wait(&(frameq->cond_new), &(frameq->mutex));
+ }
+ LKU(frameq->mutex);
+
+ /* 2. draw selected frame */
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(frame->surfaces), surface)
+ {
+ p_info.im = surface->im;
+ p_info.x = 0;
+ p_info.y = 0;
+ p_info.w = surface->im->cache_entry.w;
+ p_info.h = surface->im->cache_entry.h;
+
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(p_info.im->pipe), p)
+ {
+ int i;
+
+ for (i = 0; i < p->op_num; i++)
+ {
+ if (p->op[i].op_func)
+ {
+ p->op[i].op_func(p_info.im, &(p->op[i]), &p_info);
+ }
+ }
+ }
+
+ /* push surface out */
+ if (! surface->dontpush)
+ {
+ frame->output_redraws_next_update_push(frame->data,
+ surface->im, surface->x, surface->y, surface->w, surface->h);
+ }
+ }
+
+ // record frame ready time, will be used in post worker thread, evas_common_frameq_thread_post()
+ gettimeofday(&frame->ready_time, NULL);
+
+ LKL(frameq->mutex);
+ frame->ready = 1;
+ pthread_cond_signal(&frameq->cond_ready);
+ LKU(frameq->mutex);
+ }
+
+ // Remove cleanup handler
+ pthread_cleanup_pop(0);
+ return NULL;
+}
+
+
+#define INTERVAL_QSIZE 17 // Actual size is 'INTERVAL_QSIZE - 1' because of not using index
+#define SATISFACTION_THRESHOLD 4 // 4 ms --> 250 FPS
+#define RESET_RATIO 4 // RESET_RATIO * [Average Ready Gap | get_max_interval()] --> Reset Threshold
+#define DOUBLE_RESET_TIME_INTERVAL_THRESHOLD 16000 // make it double in case of less 16ms
+#define RESET_ABSOLUTE_INTERVAL 600000 // 600 msec
+
+struct iq_node
+{
+ long long rt;
+ long long ri;
+};
+
+static struct iq_node _IQ[INTERVAL_QSIZE];
+static int _IQ_head = 0, _IQ_tail = 0;
+static int _IQ_length = 0;
+static long long min_ready, max_ready;
+static long long average_interval;
+
+static int
+_IQ_next_index(int i)
+{
+ return (i + 1) % INTERVAL_QSIZE;
+}
+
+static int
+_IQ_previous_index(int i)
+{
+ if (--i < 0) i += INTERVAL_QSIZE;
+ return i;
+}
+
+static void
+_IQ_init(void)
+{
+ _IQ_length = _IQ_head = _IQ_tail = 0;
+ min_ready = LLONG_MAX, max_ready = LLONG_MIN;
+ average_interval = 0;
+}
+
+static int
+_IQ_empty(void)
+{
+ return (_IQ_head == _IQ_tail) ? 1 : 0;
+}
+
+static int
+_IQ_full(void)
+{
+ return (_IQ_head == ((_IQ_tail + 1) % INTERVAL_QSIZE)) ? 1 : 0;
+}
+
+static void
+_IQ_insert(long long ready_time, long long last_interval)
+{
+ if (_IQ_full()) return;
+
+ if (_IQ_empty())
+ {
+ if (last_interval < 0)
+ {
+ last_interval = -last_interval;
+ }
+ _IQ[_IQ_tail].rt = ready_time;
+ _IQ[_IQ_tail].ri = last_interval;
+ min_ready = ready_time - last_interval;
+ max_ready = ready_time;
+ _IQ_tail = _IQ_next_index(_IQ_tail);
+ _IQ_length++;
+ }
+ else
+ {
+ if (max_ready < ready_time)
+ {
+ _IQ[_IQ_tail].rt = ready_time;
+ _IQ[_IQ_tail].ri = ready_time - max_ready;
+ _IQ_tail = _IQ_next_index(_IQ_tail);
+ _IQ_length++;
+ max_ready = ready_time;
+ }
+ else if (ready_time < min_ready)
+ {
+ last_interval = _IQ[_IQ_head].ri;
+ _IQ[_IQ_head].ri = _IQ[_IQ_head].rt - ready_time;
+ _IQ_head = _IQ_previous_index(_IQ_head);
+ _IQ[_IQ_head].rt = ready_time;
+ _IQ[_IQ_head].ri = last_interval;
+ min_ready = ready_time;
+ _IQ_length++;
+ }
+ else
+ {
+ int i, j, k, l = 0;
+ for (i = _IQ_head; i != _IQ_tail; i = j)
+ {
+ j = _IQ_next_index(i);
+ if (_IQ[j].rt < ready_time)
+ {
+ continue;
+ }
+ break;
+ }
+ for (k = _IQ_tail; k != j; k = l)
+ {
+ l = _IQ_previous_index(k);
+ _IQ[k] = _IQ[l];
+ }
+ i = _IQ_next_index(j);
+ _IQ[j].ri -= (_IQ[j].rt - ready_time);
+ _IQ[j].rt = ready_time;
+ _IQ[i].ri = _IQ[i].rt - ready_time;
+ _IQ_tail = _IQ_next_index(_IQ_tail);
+ _IQ_length++;
+ }
+ }
+ average_interval = (max_ready - min_ready) / _IQ_length;
+}
+
+static long long
+_IQ_delete()
+{
+ struct iq_node oldest;
+ if (_IQ_empty()) return 0;
+ oldest = _IQ[_IQ_head];
+ _IQ_head = ++_IQ_head % INTERVAL_QSIZE;
+ if (--_IQ_length == 0)
+ {
+ _IQ_init();
+ }
+ else
+ {
+ min_ready = _IQ[_IQ_head].rt;
+ average_interval = (max_ready - min_ready) / _IQ_length;
+ }
+
+ return oldest.ri;
+}
+
+static long long
+get_max_interval()
+{
+ int i;
+ long long max = LLONG_MIN;
+
+ for ( i= _IQ_head ; i != _IQ_tail ; i = _IQ_next_index(i))
+ {
+ if (_IQ[i].ri > max)
+ {
+ max = _IQ[i].ri;
+ }
+ }
+
+ return max;
+}
+
+static long long
+tv_to_long_long(struct timeval *tv)
+{
+ if (tv == NULL)
+ {
+ return 0;
+ }
+
+ return tv->tv_sec * 1000000LL + tv->tv_usec;
+}
+
+static long long
+evas_common_frameq_schedule_flush_time(
+ int frameq_sz, int thread_no,
+ long long last_ready_time, long long current_ready_time,
+ long long last_flush_time, int ready_frames_num,
+ int dont_schedule)
+{
+ // to get each time and to do others
+ long long current_time = 0LL;
+ long long current_ready_interval = 0LL;
+ long long theshold_time = SATISFACTION_THRESHOLD * 1000LL; // ms -> usec
+ long long reset_time_interval;
+ long long sleep_time = 0LL;
+ long long saved_ready_time, saved_ready_interval;
+ long long time_slept = 0LL;
+ static long long time_lag = 0;
+ struct timeval now;
+ int frameq_full_threshold =0;
+ int need_reset = 0;
+ int need_schedule = 0;
+
+ frameq_full_threshold = frameq_sz -thread_no; // Qsize - threads#
+
+ /* 1.5 defer flush time of current frame if need */
+ // in case of the first time, just keep ready time only
+ if (last_ready_time == 0LL)
+ {
+ last_ready_time = current_ready_time;
+ }
+ else
+ {
+ /* 1.5.1 get current ready time & interval */
+ saved_ready_time = current_ready_time;
+ saved_ready_interval = current_ready_interval = current_ready_time - last_ready_time;
+ // compensate a case which current ready time is older than previous one,
+ // doesn't work on the interval queue
+ if (current_ready_interval < 0)
+ {
+ current_ready_time = last_ready_time;
+ current_ready_interval = 0;
+ }
+
+ /* 1.5.2 get the reset time interval before keeping a new one */
+ if (!_IQ_empty())
+ {
+ reset_time_interval = RESET_RATIO * average_interval;
+ if (average_interval < DOUBLE_RESET_TIME_INTERVAL_THRESHOLD)
+ {
+ reset_time_interval *= 2;
+ }
+ }
+
+ /* 1.5.3 reset - if too late, discard all saved interval and start from here */
+ if (current_ready_interval > RESET_ABSOLUTE_INTERVAL)
+ {
+ need_reset = 1;
+ }
+ else if (_IQ_length >= thread_no * 2 && current_ready_interval > reset_time_interval)
+ {
+ need_reset = 1;
+ }
+ else if (_IQ_length >= thread_no && _IQ_length < thread_no * 2
+ && current_ready_interval > get_max_interval() * RESET_RATIO)
+ {
+ need_reset = 1;
+ }
+
+ if (need_reset)
+ {
+ _IQ_init();
+ }
+ else
+ {
+ /* 1.5.4 enqueue - keep a new interval for next average interval */
+ if (_IQ_full())
+ {
+ _IQ_delete();
+ }
+ _IQ_insert(saved_ready_time, saved_ready_interval);
+
+ /* 1.5.5 schedule - if faster than average interval, figure out sleep time to meet it */
+ if (!dont_schedule)
+ {
+ need_schedule = 0;
+ sleep_time = 0;
+ if (_IQ_length >= thread_no * 2 && average_interval > theshold_time)
+ {
+ need_schedule = 1;
+ }
+ // compensate the case that postworker blocks the workers from getting a new fresh frame
+ // It's actually occurred when during the wait time of postworker, the frame queue is full
+ // Consequently check the number of currently ready frames and apply some time drop to average time according to the number
+ if (ready_frames_num >= frameq_full_threshold)
+ {
+ need_schedule = 0;
+ }
+ if (need_schedule)
+ {
+ gettimeofday(&now, NULL);
+ current_time = tv_to_long_long(&now);
+ time_lag += (current_time - last_flush_time);
+ sleep_time = (average_interval < time_lag) ? 0 : (average_interval - time_lag);
+ }
+ }
+
+ /* 1.5.6 sleep - actually sleep and get over-slept time (time_lag) for next frame */
+ if (sleep_time > 0)
+ {
+ sleep_time = sleep_time * 9 / 10;
+ usleep((unsigned int)sleep_time);
+ gettimeofday(&now, NULL);
+ time_slept = tv_to_long_long(&now) - current_time;
+ time_lag = time_slept - sleep_time;
+ }
+ else
+ {
+ time_lag = 0;
+ }
+ }
+ last_ready_time = current_ready_time;
+ }
+
+ return last_ready_time;
+}
+
+static void *
+evas_common_frameq_thread_post(void *data)
+{
+ Evas_FrameQ *frameq;
+ Evas_Frame *frame;
+ Evas_Surface *surface;
+ RGBA_Pipe *p;
+ Thinfo *thinfo;
+ Evas_Frameq_Thread_Info *fq_info;
+ RGBA_Pipe_Thread_Info p_info;
+ Eina_List *pending_writes = NULL;
+ Eina_List *prev_pending_writes = NULL;
+
+ long long last_ready_time = 0LL;
+ long long current_ready_time;
+ Evas_Frame *temp_frame = NULL;
+ int ready_frames_num;
+ long long last_flush_time = 0LL;
+ struct timeval now;
+ int dont_schedule = 0;
+
+ thinfo = data;
+ fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info);
+ frameq = fq_info->frameq;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+ /* install thread cancelation cleanup handler */
+ pthread_cleanup_push(evas_common_frameq_release, data);
+
+ _IQ_init();
+
+ for (;;)
+ {
+ /* 1. wait the first frame being done */
+ LKL(frameq->mutex);
+ while(!frameq->frames || !frameq->frames->ready)
+ {
+ pthread_cond_wait(&(frameq->cond_ready), &(frameq->mutex));
+ }
+ frame = frameq->frames;
+
+ /* 1.5. prepare to schedule flush time */
+ current_ready_time = tv_to_long_long(&frame->ready_time);
+ ready_frames_num = 0;
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), temp_frame)
+ {
+ if (temp_frame->ready == 1)
+ {
+ ready_frames_num++;
+ }
+ }
+ dont_schedule = (frame->dont_schedule)?1:0;
+ LKU(frameq->mutex);
+
+ /* 2. generate pending_writes */
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(frame->surfaces), surface)
+ {
+ evas_common_pipe_flush(surface->im);
+ if (! surface->dontpush)
+ {
+ pending_writes = eina_list_append(pending_writes, surface->im);
+ }
+ }
+
+ /* 2.5. schedule flush time */
+ last_ready_time = evas_common_frameq_schedule_flush_time(
+ frameq->frameq_sz, frameq->thread_num,
+ last_ready_time, current_ready_time,
+ last_flush_time, ready_frames_num, dont_schedule);
+
+ /* 3. flush redraws */
+ frame->output_set_priv(frame->data, pending_writes, prev_pending_writes);
+ frame->output_flush(frame->data);
+ gettimeofday(&now, NULL);
+ // keep as the last flush time
+ last_flush_time = now.tv_sec * 1000000LL + now.tv_usec;
+
+ prev_pending_writes = pending_writes;
+ pending_writes = NULL;
+
+ /* 4. remove this frame from the frame queue */
+ LKL(frameq->mutex);
+ frameq->frames =
+ (Evas_Frame *)eina_inlist_remove(EINA_INLIST_GET(frameq->frames),
+ EINA_INLIST_GET(frame));
+
+ LKU(frameq->mutex);
+ pthread_cond_broadcast(&frameq->cond_done);
+ evas_common_frame_dealloc(frame);
}
+
+ // Remove cleanup handler
+ pthread_cleanup_pop(0);
return NULL;
}
+
+#endif /* EVAS_FRAME_QUEUING */
#endif
#ifdef BUILD_PTHREAD
#ifdef BUILD_PTHREAD
int i, y, h;
+#ifdef EVAS_FRAME_QUEUING
+ return;
+#endif
+
if (!im->pipe) return;
if (thread_num == 1) return;
y = 0;
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)
{
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);
}
/* 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);
}
}
{
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;
{
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;
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);
}
{
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;
/* 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;
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;
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;
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;
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;
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;
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;
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
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
}
}
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);
}
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
evas_common_pipe_map4_render(root);
}
+
#endif
#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
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 */
# include <pthread.h>
# include <sched.h>
# define LK(x) pthread_mutex_t x
+#ifndef EVAS_FRAME_QUEUING
# define LKI(x) pthread_mutex_init(&(x), NULL);
+#else
+# define LKI(x) {pthread_mutexattr_t attr;\
+ pthread_mutexattr_init(&attr); \
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
+ pthread_mutex_init(&(x), &attr);}
+#endif
# define LKD(x) pthread_mutex_destroy(&(x));
# define LKL(x) pthread_mutex_lock(&(x));
# define LKT(x) pthread_mutex_trylock(&(x));
# 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
# 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
time_t laststat;
int references;
+#ifdef EVAS_FRAME_QUEUING
+ LK(lock_references); // needed for accessing references
+#endif
unsigned char scale;
};
#ifdef BUILD_PIPE_RENDER
+#include "../engines/common/evas_map_image.h"
+
struct _RGBA_Pipe_Op
{
RGBA_Draw_Context context;
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;
} 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;
} 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;
};
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
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
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;
}
} 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
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;
}
unsigned short height;
unsigned char *mask;
} *shape;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
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;
}
IDirectFB *dfb;
IDirectFBSurface *surface;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
int refresh;
int rotation;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
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;
}
HWND window;
int depth;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
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;
}
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
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;
}
struct {
CGContextRef context;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
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;
}
int rotation;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
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;
}
int noframe : 1;
int alpha : 1;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
int (*suspend) (int backend);
int (*resume) (int backend);
} func;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
info->magic.magic = rand();
info->func.suspend = _suspend;
info->func.resume = _resume;
+ info->render_mode = EVAS_RENDER_MODE_BLOCKING;
return info;
e = NULL;
}
Drawable drawable;
int rotation;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
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;
}
int rotation;
unsigned int fullscreen : 1;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
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;
}
unsigned int layered : 1;
unsigned int fullscreen : 1;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
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
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
{
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
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
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
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
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,
(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;
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 *
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
QWidget *target;
int rotation;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
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;
}
int noframe : 1;
int alpha : 1;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
} func;
int mask_changed;
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
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);
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 */
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;
}
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
{
int ponebuf = 0;
+#ifdef EVAS_FRAME_QUEUING
+ evas_common_frameq_flush ();
+#endif
re = e->engine.data.output;
ponebuf = re->ob->onebuf;
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
eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
{
Render_Engine *re;
+#ifdef EVAS_FRAME_QUEUING
+ Evas_Surface *e_surface;
+#endif
re = (Render_Engine *)data;
-#ifdef BUILD_PIPE_RENDER
+#if defined(BUILD_PIPE_RENDER) && !defined(EVAS_FRAME_QUEUING)
evas_common_pipe_map4_begin(surface);
-#endif
+#endif /* BUILD_PIPE_RENDER && !EVAS_FRAME_QUEUING*/
+
+#ifdef EVAS_FRAME_QUEUING
+ if (re->render_mode == EVAS_RENDER_MODE_NONBLOCKING)
+ {
+ /* create a new frame if this is the first surface of this frame */
+ evas_common_frameq_prepare_frame();
+ /* add surface into the frame */
+ e_surface = evas_common_frameq_new_surface(surface, x, y, w, h);
+ evas_common_frameq_add_surface(e_surface);
+ return;
+ }
+#endif
+
re->outbuf_push_updated_region(re->ob, surface, x, y, w, h);
re->outbuf_free_region_for_update(re->ob, surface);
evas_common_cpu_end_opt();
}
+#ifdef EVAS_FRAME_QUEUING
+static void *
+eng_image_map_surface_new(void *data , int w, int h, int alpha)
+{
+ void *surface;
+ DATA32 *pixels;
+ Render_Engine *re;
+ Evas_Surface *e_surface;
+
+ re = (Render_Engine *)data;
+
+ surface = evas_cache_image_copied_data(evas_common_image_cache_get(),
+ w, h, NULL, alpha,
+ EVAS_COLORSPACE_ARGB8888);
+ pixels = evas_cache_image_pixels(surface);
+
+ if (re->render_mode == EVAS_RENDER_MODE_NONBLOCKING)
+ {
+ /* create a new frame if this is the first surface of this frame */
+ evas_common_frameq_prepare_frame();
+
+ /* add surface into the frame */
+ e_surface = evas_common_frameq_new_surface (surface, 0, 0, w, h);
+ e_surface->dontpush = 1; // this surface is not going to be pushed to screen
+ evas_common_frameq_add_surface(e_surface);
+ }
+ return surface;
+}
+
static void
-eng_output_flush(void *data)
+eng_output_frameq_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ re->outbuf_push_updated_region(re->ob, surface, x, y, w, h);
+ re->outbuf_free_region_for_update(re->ob, surface);
+ evas_common_cpu_end_opt();
+}
+
+static void
+eng_output_frameq_flush(void *data)
{
Render_Engine *re;
}
static void
+eng_output_frameq_set_priv(void *data, void *cur, void *prev)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+ re->outbuf_set_priv(re->ob, cur, prev);
+}
+#endif
+
+static void
+eng_output_flush(void *data)
+{
+ Render_Engine *re;
+
+ re = (Render_Engine *)data;
+#ifdef EVAS_FRAME_QUEUING
+ if (re->render_mode == EVAS_RENDER_MODE_NONBLOCKING)
+ {
+ evas_common_frameq_set_frame_data(data,
+ eng_output_frameq_redraws_next_update_push,
+ eng_output_frameq_flush,
+ eng_output_frameq_set_priv);
+ evas_common_frameq_ready_frame();
+ evas_common_frameq_begin();
+ }
+ else
+#endif
+ {
+ re->outbuf_flush(re->ob);
+ }
+}
+
+static void
eng_output_idle_flush(void *data)
{
Render_Engine *re;
return (re->ob->priv.destination_alpha) || (re->outbuf_alpha_get(re->ob));
}
+
/* module advertising code */
static int
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;
}
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;
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);
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)
{
else
lbytes = ((w + 31) / 32) * 4;
sz = lbytes * h;
+ SHMPOOL_LOCK();
EINA_LIST_FOREACH(shmpool, l, xob2)
{
int szdif;
}
}
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;
xob->xim->height = xob->h;
xob->xim->bytes_per_line = xob->bpl;
shmsize -= xob->psize * (xob->xim->depth / 8);
+ SHMPOOL_UNLOCK();
return xob;
}
// 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)) ||
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);
static void
_clear_xob(int sync)
{
+ SHMPOOL_LOCK();
while (shmpool)
{
X_Output_Buffer *xob;
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;
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)
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);
}
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;
}
/* 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;
}
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;
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
}
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)
{
if (obr->mxob) _unfind_xob(obr->mxob, 0);
free(obr);
}
+#ifdef EVAS_FRAME_QUEUING
+ LKU(buf->priv.lock);
+#endif
_clear_xob(0);
}
}
{
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
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
void *visual;
unsigned char destination_alpha : 1;
} info;
+
+ /* non-blocking or blocking mode */
+ Evas_Engine_Render_Mode render_mode;
};
#endif
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;
}