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.
*
* @param e The given canvas pointer.
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
};
*/
#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)
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;
-
- if (_fd_read == -1) return 0;
+ int ret;
- _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)
{
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)
{
}
}
-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;
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())
&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;
#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)
{
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
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)
{
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)
{
*ret = NULL;
return;
}
- *ret = evas_render_updates_internal(eo_e, 1, 1);
+ *ret = evas_render_updates_internal_wait(eo_e, 1, 1);
}
EAPI void
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
_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
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;
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;
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);
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);