evas: Async render

SVN revision: 81282
This commit is contained in:
Leandro Pereira 2012-12-18 16:26:44 +00:00
parent 645dcff9d2
commit a7b4a3c12d
6 changed files with 280 additions and 45 deletions

View File

@ -1670,6 +1670,31 @@ EAPI void evas_obscured_rectangle_add(Evas *e, int x, int y, int w,
*/
EAPI void evas_obscured_clear(Evas *e) EINA_ARG_NONNULL(1);
/**
* Render the given Evas canvas asynchronously.
*
* @param e The canvas to render.
* @param func Optional function to call with the list of updated areas.
* @param data User data to pass to @p func.
*
* @return EINA_TRUE if the canvas will render, EINA_FALSE otherwise.
*
* This function only returns EINA_TRUE whne a frame will be rendered. If the
* previous frame is still rendering, EINA_FALSE will be returned so the users
* know not to wait for the updates callback and just return to their main
* loop.
*
* If a @p func callback is given, a list of updated areas will be generated
* and the function will be called from the main thread after the rendered
* frame is flushed to the screen. The resulting list should be freed with
* @f evas_render_updates_free().
* The list is given in the @p event_info parameter of the callback function.
*
* @ingroup Evas_Canvas
* @since 1.8
*/
EAPI Eina_Bool evas_render_async(Evas *e, Evas_Event_Cb func, void *data) EINA_ARG_NONNULL(1);
/**
* Force immediate renderization of the given Evas canvas.
*
@ -2425,6 +2450,7 @@ enum
EVAS_CANVAS_SUB_ID_OBJECTS_IN_RECTANGLE_GET,
EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE,
EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE_COUNT_GET,
EVAS_CANVAS_SUB_ID_RENDER_ASYNC,
EVAS_CANVAS_SUB_ID_LAST
};
@ -3692,6 +3718,19 @@ enum
*/
#define evas_canvas_smart_objects_calculate_count_get(ret) EVAS_CANVAS_ID(EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE_COUNT_GET), EO_TYPECHECK(int *, ret)
/**
* @def evas_canvas_render_async
* @since 1.8
*
* Render canvas asynchronously
*
* @param[in] func Callback function for list of updates
* @param[in] data User data pointer to pass to func
* @param[out] ret Whether or not a frame will get rendered after the call
*
* @see evas_render_async
*/
#define evas_canvas_render_async(func, data, ret) EVAS_CANVAS_ID(EVAS_CANVAS_SUB_ID_RENDER_ASYNC), EO_TYPECHECK(Evas_Event_Cb, func), EO_TYPECHECK(void *, data), EO_TYPECHECK(Eina_Bool *, ret)

View File

@ -105,33 +105,20 @@ evas_async_events_fd_get(void)
return _fd_read;
}
EAPI int
evas_async_events_process(void)
static int
_evas_async_events_process_single(void)
{
Evas_Event_Async *ev;
int check;
int count = 0;
int ret;
if (_fd_read == -1) return 0;
_evas_async_events_fork_handle();
do
ret = read(_fd_read, &ev, sizeof(Evas_Event_Async *));
if (ret == sizeof(Evas_Event_Async *))
{
check = read(_fd_read, &ev, sizeof (Evas_Event_Async *));
if (check == sizeof (Evas_Event_Async *))
{
if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info);
free(ev);
count++;
}
if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info);
free(ev);
return 1;
}
while (check > 0);
evas_cache_image_wakeup();
if (check < 0)
else if (ret < 0)
{
switch (errno)
{
@ -139,13 +126,55 @@ evas_async_events_process(void)
case EINVAL:
case EIO:
case EISDIR:
_fd_read = -1;
_fd_read = -1;
}
}
return ret;
}
EAPI int
evas_async_events_process(void)
{
int count = 0;
if (_fd_read == -1) return 0;
_evas_async_events_fork_handle();
while (_evas_async_events_process_single() > 0) count++;
evas_cache_image_wakeup();
return count;
}
static void
_evas_async_events_fd_blocking_set(Eina_Bool blocking)
{
long flags = fcntl(_fd_read, F_GETFL);
if (blocking) flags &= ~O_NONBLOCK;
else flags |= O_NONBLOCK;
fcntl(_fd_read, F_SETFL, flags);
}
int
evas_async_events_process_blocking(void)
{
int ret;
_evas_async_events_fork_handle();
_evas_async_events_fd_blocking_set(EINA_TRUE);
ret = _evas_async_events_process_single();
evas_cache_image_wakeup(); /* FIXME: is this needed ? */
_evas_async_events_fd_blocking_set(EINA_FALSE);
return ret;
}
EAPI Eina_Bool
evas_async_events_put(const void *target, Evas_Callback_Type type, void *event_info, Evas_Async_Events_Put_Cb func)
{

View File

@ -152,6 +152,8 @@ evas_free(Evas *eo_e)
MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
return;
MAGIC_CHECK_END();
Evas_Public_Data *e = eo_data_get(eo_e, EVAS_CLASS);
e->requested_free = EINA_TRUE;
eo_unref(eo_e);
}
@ -1064,6 +1066,7 @@ _class_constructor(Eo_Class *klass)
EO_OP_FUNC(EVAS_CANVAS_ID(EVAS_CANVAS_SUB_ID_OBJECTS_IN_RECTANGLE_GET), _canvas_objects_in_rectangle_get),
EO_OP_FUNC(EVAS_CANVAS_ID(EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE), _canvas_smart_objects_calculate),
EO_OP_FUNC(EVAS_CANVAS_ID(EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE_COUNT_GET), _canvas_smart_objects_calculate_count_get),
EO_OP_FUNC(EVAS_CANVAS_ID(EVAS_CANVAS_SUB_ID_RENDER_ASYNC), _canvas_render_async),
EO_OP_FUNC_SENTINEL
};
@ -1163,6 +1166,7 @@ static const Eo_Op_Description op_desc[] = {
EO_OP_DESCRIPTION(EVAS_CANVAS_SUB_ID_OBJECTS_IN_RECTANGLE_GET, "Retrieves the objects in the given rectangle region."),
EO_OP_DESCRIPTION(EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE, "Call user-provided calculate() smart functions."),
EO_OP_DESCRIPTION(EVAS_CANVAS_SUB_ID_SMART_OBJECTS_CALCULATE_COUNT_GET, "Get the internal counter that counts the number of smart calculations."),
EO_OP_DESCRIPTION(EVAS_CANVAS_SUB_ID_RENDER_ASYNC, "Renders the canvas asynchronously."),
EO_OP_DESCRIPTION_SENTINEL
};

View File

@ -1291,15 +1291,23 @@ _evas_render_cutout_add(Evas *eo_e, Evas_Object *eo_obj, int off_x, int off_y)
}
}
static Eina_List *
void
evas_render_rendering_wait(Evas_Public_Data *evas)
{
while (evas->rendering) evas_async_events_process_blocking();
}
static Eina_Bool
evas_render_updates_internal(Evas *eo_e,
unsigned char make_updates,
unsigned char do_draw)
unsigned char do_draw,
Evas_Render_Done_Cb done_func,
void *done_data,
Eina_Bool do_async)
{
Evas_Object *eo_obj;
Evas_Object_Protected_Data *obj;
Evas_Public_Data *e;
Eina_List *updates = NULL;
Eina_List *ll;
void *surface;
Eina_Bool clean_them = EINA_FALSE;
@ -1312,11 +1320,16 @@ evas_render_updates_internal(Evas *eo_e,
Eina_Bool haveup = 0;
MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
return NULL;
return EINA_FALSE;
MAGIC_CHECK_END();
e = eo_data_get(eo_e, EVAS_CLASS);
if (!e->changed) return NULL;
if (!e->changed) return EINA_FALSE;
if (e->rendering) return EINA_FALSE;
e->rendering = EINA_TRUE;
if (do_async) eo_ref(eo_e);
#ifdef EVAS_CSERVE2
if (evas_cserve2_use_get())
@ -1537,15 +1550,25 @@ evas_render_updates_internal(Evas *eo_e,
&cx, &cy, &cw, &ch)))
{
int off_x, off_y;
Render_Updates *ru;
RD(" [--- UPDATE %i %i %ix%i\n", ux, uy, uw, uh);
if (make_updates)
if (do_async)
{
ru = malloc(sizeof(*ru));
ru->surface = surface;
NEW_RECT(ru->area, ux, uy, uw, uh);
e->render.updates = eina_list_append(e->render.updates, ru);
evas_cache_image_ref(surface);
}
else if (make_updates)
{
Eina_Rectangle *rect;
NEW_RECT(rect, ux, uy, uw, uh);
if (rect)
updates = eina_list_append(updates, rect);
e->render.updates = eina_list_append(e->render.updates,
rect);
}
haveup = EINA_TRUE;
off_x = cx - ux;
@ -1647,30 +1670,41 @@ evas_render_updates_internal(Evas *eo_e,
#ifdef REND_DBG
, 1
#endif
);
, do_async);
e->engine.func->context_cutout_clear(e->engine.data.output,
e->engine.data.context);
}
}
}
/* punch rect out */
e->engine.func->output_redraws_next_update_push(e->engine.data.output,
surface,
ux, uy, uw, uh);
if (!do_async)
e->engine.func->output_redraws_next_update_push(e->engine.data.output,
surface,
ux, uy, uw, uh);
/* free obscuring objects list */
eina_array_clean(&e->temporary_objects);
RD(" ---]\n");
}
/* flush redraws */
if (haveup)
if (do_async)
{
evas_thread_queue_flush((Evas_Thread_Command_Cb)done_func, done_data, 0);
}
else if (haveup)
{
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
e->engine.func->output_flush(e->engine.data.output);
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
}
}
/* clear redraws */
e->engine.func->output_redraws_clear(e->engine.data.output);
if (!do_async)
{
/* clear redraws */
e->engine.func->output_redraws_clear(e->engine.data.output);
}
/* and do a post render pass */
for (i = 0; i < e->active_objects.count; ++i)
{
@ -1753,11 +1787,85 @@ evas_render_updates_internal(Evas *eo_e,
evas_module_clean();
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL);
if (!do_async)
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL);
RD("---]\n");
return updates;
return EINA_TRUE;
}
static void
evas_render_wakeup(Evas *eo_e)
{
Render_Updates *ru;
Eina_Bool haveup = EINA_FALSE;
Eina_List *ret_updates = NULL;
Evas_Public_Data *e = eo_data_get(eo_e, EVAS_CLASS);
if (e->requested_free)
{
EINA_LIST_FREE(e->render.updates, ru)
{
eina_rectangle_free(ru->area);
free(ru);
}
goto end;
}
EINA_LIST_FREE(e->render.updates, ru)
{
/* punch rect out */
e->engine.func->output_redraws_next_update_push(e->engine.data.output,
ru->surface,
ru->area->x,
ru->area->y,
ru->area->w,
ru->area->h);
if (e->render.updates_cb)
ret_updates = eina_list_append(ret_updates, ru->area);
else
eina_rectangle_free(ru->area);
evas_cache_image_drop(ru->surface);
free(ru);
haveup = EINA_TRUE;
}
/* flush redraws */
if (haveup)
{
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
e->engine.func->output_flush(e->engine.data.output);
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
}
/* clear redraws */
e->engine.func->output_redraws_clear(e->engine.data.output);
evas_event_callback_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL);
if (e->render.updates_cb)
e->render.updates_cb(e->render.data, eo_e, ret_updates);
e->rendering = EINA_FALSE;
e->render.updates_cb = NULL;
e->render.data = NULL;
end:
eo_unref(eo_e);
}
static void
evas_render_async_wakeup(void *target, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Public_Data *e = target;
evas_render_wakeup(e->evas);
}
static void
evas_render_pipe_wakeup(void *data)
{
evas_async_events_put(data, 0, NULL, evas_render_async_wakeup);
}
EAPI void
@ -1769,6 +1877,30 @@ evas_render_updates_free(Eina_List *updates)
eina_rectangle_free(r);
}
EAPI Eina_Bool
evas_render_async(Evas *eo_e, Evas_Event_Cb func, void *data)
{
MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
return EINA_FALSE;
MAGIC_CHECK_END();
Eina_Bool ret = EINA_FALSE;
eo_do(eo_e, evas_canvas_render_async(func, data, &ret));
return ret;
}
void
_canvas_render_async(Eo *eo_e, void *_pd, va_list *list)
{
Evas_Event_Cb func = va_arg(*list, Evas_Event_Cb);
void *data = va_arg(*list, void *);
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
Evas_Public_Data *e = _pd;
e->render.updates_cb = func;
e->render.data = data;
*ret = evas_render_updates_internal(eo_e, 1, 1, evas_render_pipe_wakeup, e, EINA_TRUE);
}
EAPI Eina_List *
evas_render_updates(Evas *eo_e)
{
@ -1780,6 +1912,25 @@ evas_render_updates(Evas *eo_e)
return ret;
}
static Eina_List *
evas_render_updates_internal_wait(Evas *eo_e,
unsigned char make_updates,
unsigned char do_draw)
{
Eina_List *ret = NULL;
Evas_Public_Data *e = eo_data_get(eo_e, EVAS_CLASS);
if (!evas_render_updates_internal(eo_e, make_updates, do_draw, NULL, NULL,
EINA_FALSE))
return NULL;
ret = e->render.updates;
e->render.updates = NULL;
e->rendering = EINA_FALSE;
return ret;
}
void
_canvas_render_updates(Eo *eo_e, void *_pd, va_list *list)
{
@ -1792,7 +1943,7 @@ _canvas_render_updates(Eo *eo_e, void *_pd, va_list *list)
*ret = NULL;
return;
}
*ret = evas_render_updates_internal(eo_e, 1, 1);
*ret = evas_render_updates_internal_wait(eo_e, 1, 1);
}
EAPI void
@ -1810,7 +1961,7 @@ _canvas_render(Eo *eo_e, void *_pd, va_list *list EINA_UNUSED)
Evas_Public_Data *e = _pd;
if (!e->changed) return;
evas_render_updates_internal(eo_e, 0, 1);
evas_render_updates_internal_wait(eo_e, 0, 1);
}
EAPI void
@ -1826,7 +1977,7 @@ void
_canvas_norender(Eo *eo_e, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
{
// if (!e->changed) return;
evas_render_updates_internal(eo_e, 0, 0);
evas_render_updates_internal_wait(eo_e, 0, 0);
}
EAPI void

View File

@ -1264,6 +1264,9 @@ Tilebuf_Rect *evas_common_regionbuf_rects_get (Regionbuf *rb);
void evas_font_dir_cache_free(void);
int evas_async_events_process_blocking(void);
void evas_render_rendering_wait(Evas_Public_Data *evas);
void evas_thread_init(void);
void evas_thread_shutdown(void);
EAPI void evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data, size_t size);

View File

@ -371,6 +371,12 @@ struct _Evas_Public_Data
int info_magic;
} engine;
struct {
Eina_List *updates;
Evas_Event_Cb updates_cb;
void *data;
} render;
Eina_Array delete_objects;
Eina_Array active_objects;
Eina_Array restack_objects;
@ -414,6 +420,8 @@ struct _Evas_Public_Data
unsigned char cleanup : 1;
unsigned char focus : 1;
Eina_Bool is_frozen : 1;
Eina_Bool rendering : 1;
Eina_Bool requested_free : 1;
Eina_List *touch_points;
Eina_List *devices;
@ -718,7 +726,7 @@ struct _Evas_Device
struct _Evas_Object_Func
{
void (*free) (Evas_Object *obj, Evas_Object_Protected_Data *pd);
void (*render) (Evas_Object *obj, Evas_Object_Protected_Data *pd, void *output, void *context, void *surface, int x, int y);
void (*render) (Evas_Object *obj, Evas_Object_Protected_Data *pd, void *output, void *context, void *surface, int x, int y, Eina_Bool do_async);
void (*render_pre) (Evas_Object *obj, Evas_Object_Protected_Data *pd);
void (*render_post) (Evas_Object *obj, Evas_Object_Protected_Data *pd);
@ -1127,6 +1135,7 @@ void _canvas_key_modifier_mask_get(Eo *e, void *_pd, va_list *list);
void _canvas_damage_rectangle_add(Eo *obj, void *_pd, va_list *list);
void _canvas_obscured_rectangle_add(Eo *obj, void *_pd, va_list *list);
void _canvas_obscured_clear(Eo *obj, void *_pd, va_list *list);
void _canvas_render_async(Eo *obj, void *_pd, va_list *list);
void _canvas_render_updates(Eo *obj, void *_pd, va_list *list);
void _canvas_render(Eo *e, void *_pd, va_list *list);
void _canvas_norender(Eo *e, void *_pd, va_list *list);