return: bool;
}
+ render2_updates {
+ /*@
+ Render the given Evas canvas using the new rendering infra.
+
+ This is experimental and will change over time until noted here.
+
+ @return A newly allocated list of updated rectangles of thecanvas
+ (@c Eina.Rectangle structs). Free this list with
+ evas_render_updates_free().
+
+ @ingroup Evas_Canvas
+ @since 1.15 */
+
+ return: free(own(list<Eina.Rectangle *> *), evas_render_updates_free)
+ @warn_unused;
+ }
focus_out {
/*@
Inform to the evas that it lost the focus.
Evas_Object_Protected_Data *obj,
void *type_private_data);
+static void evas_object_rectangle_render2_walk(Evas_Object *eo_obj,
+ Evas_Object_Protected_Data *obj,
+ void *type_private_data,
+ void *updates,
+ int offx,
+ int offy);
+
#if 0 /* usless calls for a rect object. much more useful for images etc. */
static void evas_object_rectangle_store(Evas_Object *eo_obj);
static void evas_object_rectangle_unstore(Evas_Object *eo_obj);
NULL,
NULL,
NULL,
- NULL
+ NULL,
+ evas_object_rectangle_render2_walk
};
/* the actual api call to add a rect */
}
static void
+evas_object_rectangle_render2_walk(Evas_Object *eo_obj,
+ Evas_Object_Protected_Data *obj,
+ void *type_private_data EINA_UNUSED,
+ void *updates, int offx, int offy)
+{
+ Eina_Bool visible_is, visible_was;
+ unsigned int col_prev, col_cur;
+
+ if (obj->clip.clipees) return;
+ visible_is = evas_object_is_visible(eo_obj, obj);
+ if (!obj->changed) goto nochange;
+
+ if ((obj->cur->clipper) && (obj->cur->cache.clip.dirty))
+ evas_object_clip_recalc(obj->cur->clipper);
+ visible_was = evas_object_was_visible(eo_obj,obj);
+ // just became visible or invisible
+ if (visible_is != visible_was)
+ {
+ printf(" UP1 %p - %i %i %ix%i\n", eo_obj,
+ obj->cur->cache.clip.x, obj->cur->cache.clip.y,
+ obj->cur->cache.clip.w, obj->cur->cache.clip.h);
+ evas_common_tilebuf_add_redraw
+ (updates,
+ obj->cur->cache.clip.x - offx, obj->cur->cache.clip.y - offy,
+ obj->cur->cache.clip.w, obj->cur->cache.clip.h);
+ return;
+ }
+ // general change (prev and cur clip geom change)
+ col_prev = (obj->prev->color.a << 24) | (obj->prev->color.r << 16) |
+ (obj->prev->color.g << 8) | (obj->prev->color.b );
+ col_cur = (obj->cur->color.a << 24) | (obj->cur->color.r << 16) |
+ (obj->cur->color.g << 8) | (obj->cur->color.b );
+ if ((col_prev != col_cur) ||
+ ((obj->cur->cache.clip.x != obj->prev->cache.clip.x) ||
+ (obj->cur->cache.clip.y != obj->prev->cache.clip.y) ||
+ (obj->cur->cache.clip.w != obj->prev->cache.clip.w) ||
+ (obj->cur->cache.clip.h != obj->prev->cache.clip.h)) ||
+ (obj->cur->render_op != obj->prev->render_op) ||
+ (obj->restack)
+ )
+ {
+ printf(" UP2 %p - %i %i %ix%i\n", eo_obj,
+ obj->prev->cache.clip.x, obj->prev->cache.clip.y,
+ obj->prev->cache.clip.w, obj->prev->cache.clip.h);
+ evas_common_tilebuf_add_redraw
+ (updates,
+ obj->prev->cache.clip.x - offx, obj->prev->cache.clip.y - offy,
+ obj->prev->cache.clip.w, obj->prev->cache.clip.h);
+ evas_common_tilebuf_add_redraw
+ (updates,
+ obj->cur->cache.clip.x - offx, obj->cur->cache.clip.y - offy,
+ obj->cur->cache.clip.w, obj->cur->cache.clip.h);
+ return;
+ }
+nochange:
+ // object hasn't really changed
+ if ((visible_is) && (evas_object_is_opaque(eo_obj, obj)))
+ {
+ printf(" NO- %p - %i %i %ix%i\n", eo_obj,
+ obj->cur->cache.clip.x, obj->cur->cache.clip.y,
+ obj->cur->cache.clip.w, obj->cur->cache.clip.h);
+ evas_common_tilebuf_del_redraw
+ (updates,
+ obj->cur->cache.clip.x - offx, obj->cur->cache.clip.y - offy,
+ obj->cur->cache.clip.w, obj->cur->cache.clip.h);
+ }
+}
+
+static void
evas_object_rectangle_render(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data EINA_UNUSED,
Eina_List *members = NULL;
Eina_Inlist *member;
- evas_object_async_block(obj);
for (member = o->contained; member; member = member->next)
members = eina_list_append(members, ((Evas_Object_Protected_Data *)member)->object);
MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
return NULL;
MAGIC_CHECK_END();
- evas_object_async_block(obj);
if (!eo_isa(eo_obj, MY_CLASS)) return NULL;
Evas_Smart_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
return o->contained;
return ret;
}
+EOLIAN Eina_List *
+_evas_canvas_render2_updates(Eo *eo_e, Evas_Public_Data *e)
+{
+ Eina_List *updates = NULL;
+
+ eina_evlog("+render2_updates", eo_e, 0.0, NULL);
+ updates = _evas_render2_updates(eo_e, e);
+ eina_evlog("-render2_updates", eo_e, 0.0, NULL);
+ return updates;
+}
+
EOLIAN Eina_Bool
_evas_canvas_render_async(Eo *eo_e, Evas_Public_Data *e)
{
#include "evas_render2.h"
-#ifdef EVAS_RENDER_DEBUG_TIMING
#include <sys/time.h>
#ifndef _WIN32
out_time(double t)
{
double b = (t * 100.0) / (1.0 / 60.0);
- printf("%1.8fs (%1.2f%% 60fps budget)\n", t, b);
+ printf("%1.2f%% / 60fps\n", b);
}
-#endif
-
-// a list of canvases currently rendering
-static Eina_List *_rendering = NULL;
static void
_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info)
for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_freeze());
}
+// a list of canvases currently rendering
+static Eina_List *_rendering = NULL;
+
+// just put the thread code inlined here for now as opposed to separate files
+#include "evas_render2_th_main.c"
+
+// init all relevant render threads if needed
+static void
+_evas_render2_th_init(void)
+{
+ static Eina_Bool initted = EINA_FALSE;
+
+ if (initted) return;
+ initted = EINA_TRUE;
+ _th_main_queue = eina_thread_queue_new();
+ if (!eina_thread_create(&_th_main, EINA_THREAD_URGENT, 0,
+ _evas_render2_th_main, NULL))
+ ERR("Cannot create render2 thread");
+}
Eina_Bool
_evas_render2(Eo *eo_e, Evas_Public_Data *e)
{
+ double t;
+
// if nothing changed at all since last render - skip this frame
if (!e->changed) return EINA_FALSE;
// we are still rendering while being asked to render - skip this
if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
ERR("viewport size != output size!");
+ // if render threads not initted - init them - maybe move this later?
+ _evas_render2_th_init();
+
+ printf("------------------------------------------------ %p %p\n", eo_e, e);
// wait for any previous render pass to do its thing
+ t = get_time();
evas_canvas_async_block(e);
+ t = get_time() - t;
+ printf("T: block wait: "); out_time(t);
// we have to calculate smare objects before render so do that here
+ t = get_time();
evas_call_smarts_calculate(eo_e);
+ t = get_time() - t;
+ printf("T: smart calc: "); out_time(t);
// call canvas callbacks saying we are in the pre-render state
_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL);
// bock any susbequent rneders from doing this walk
eina_lock_take(&(e->lock_objects));
- // XXX: gain a reference
+ // gain a reference
eo_ref(eo_e);
- // XXX: put into the "i'm rendering" pool
+ // put into the "i'm rendering" pool
e->rendering = EINA_TRUE;
_rendering = eina_list_append(_rendering, eo_e);
- // XXX; should wake up thread here to begin doing it's work
-
-
- // XXX: call this from object walk thread
- eina_lock_release(&(e->lock_objects));
- // XXX: remove from the "i'm rendering" pool - do back in mainloop
- e->rendering = EINA_FALSE;
- _rendering = eina_list_remove(_rendering, eo_e);
-
-
-
- // XXX: like below - call from thread messages - figure out if they just
- // should be dumbly called before render post anyway
+ // call our flush pre at this point before rendering begins...
_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
- _always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
- // XXX: call render post - should be a result from thread message called
- // from mainloop - also fill in post struct
- Evas_Event_Render_Post post;
- _always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
- // XXX: release our reference
- eo_unref(eo_e);
+ // tell main render thread to wake up and begin processing this canvas
+ _evas_render2_th_main_msg_render(eo_e, e);
- printf("%p %p\n", eo_e, e);
return EINA_FALSE;
}
-void
-_evas_norender2(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
+Eina_List *
+_evas_render2_updates(Eo *eo_e, Evas_Public_Data *e)
{
- evas_canvas_async_block(e);
+ if (!_evas_render2(eo_e, e)) return NULL;
+ return _evas_render2_updates_wait(eo_e, e);
}
Eina_List *
_evas_render2_updates_wait(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
{
evas_canvas_async_block(e);
+ while (e->rendering) evas_async_events_process_blocking();
return NULL;
}
void
+_evas_norender2(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
+{
+ evas_canvas_async_block(e);
+}
+
+void
_evas_render2_idle_flush(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
{
evas_canvas_async_block(e);
#endif
Eina_Bool _evas_render2(Eo *eo_e, Evas_Public_Data *e);
-void _evas_norender2(Eo *eo_e, Evas_Public_Data *e);
+Eina_List *_evas_render2_updates(Eo *eo_e, Evas_Public_Data *e);
Eina_List *_evas_render2_updates_wait(Eo *eo_e, Evas_Public_Data *e);
+void _evas_norender2(Eo *eo_e, Evas_Public_Data *e);
void _evas_render2_idle_flush(Eo *eo_e, Evas_Public_Data *e);
void _evas_render2_sync(Eo *eo_e, Evas_Public_Data *e);
void _evas_render2_dump(Eo *eo_e, Evas_Public_Data *e);
--- /dev/null
+//#define DBG_OBJTREE 1
+
+#define OBJ_ARRAY_PUSH(array, obj) \
+ do \
+ { \
+ eina_array_push(array, obj); \
+ eo_data_ref(obj->object, NULL); \
+ } while (0)
+
+#define OBJS_ARRAY_CLEAN(array) \
+ do \
+ { \
+ Evas_Object_Protected_Data *item; \
+ Eina_Array_Iterator iterator; \
+ unsigned int idx; \
+ EINA_ARRAY_ITER_NEXT(array, idx, item, iterator) \
+ eo_data_unref(item->object, item); \
+ eina_array_clean(array); \
+ } while (0)
+
+typedef struct _Msg_Main_Render Msg_Main_Render;
+typedef struct _Render2_Finish_Data Render2_Finish_Data;
+
+struct _Msg_Main_Render
+{
+ Eina_Thread_Queue_Msg head;
+ Eo *eo_e;
+ Evas_Public_Data *e;
+};
+
+struct _Render2_Finish_Data
+{
+ Eo *eo_e;
+ Evas_Public_Data *e;
+ Eina_List *updates;
+};
+
+static Eina_Thread_Queue *_th_main_queue = NULL;
+static Eina_Thread _th_main;
+
+#ifdef DBG_OBJTREE
+static void
+indent(int l)
+{
+ int i; for (i = 0; i < l; i++) printf(" ");
+}
+#endif
+
+static void
+_evas_render2_th_main_delete_objects_clean(Evas_Public_Data *e)
+{
+ Evas_Object_Protected_Data *obj;
+ unsigned int i;
+ double t;
+
+ // cleanup deferred object deletion
+ t = get_time();
+ for (i = 0; i < e->delete_objects.count; ++i)
+ {
+ obj = eina_array_data_get(&e->delete_objects, i);
+ evas_object_free(obj->object, 1);
+ }
+// OBJS_ARRAY_CLEAN(&e->delete_objects);
+ eina_array_clean(&e->delete_objects);
+ t = get_time() - t;
+ printf("T: object deletion: "); out_time(t);
+}
+
+static void
+_evas_render2_th_main_mainloop_done(void *data, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Render2_Finish_Data *render_finish_data = data;
+ Evas_Event_Render_Post post;
+ Eo *eo_e;
+ Evas_Public_Data *e;
+ Eina_Rectangle *rect;
+
+ e = render_finish_data->e;
+ eo_e = render_finish_data->eo_e;
+ // call the flush post callbacks
+ _always_call(render_finish_data->eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
+
+ // and now call the actual render post callbacks with updates list
+ post.updated_area = render_finish_data->updates;
+ _always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
+
+ EINA_LIST_FREE(render_finish_data->updates, rect) free(rect);
+ free(render_finish_data);
+ _evas_render2_th_main_delete_objects_clean(e);
+}
+
+static Eina_Bool
+_evas_render2_th_main_obj_del_handle(Evas_Public_Data *e,
+ Evas_Object_Protected_Data *obj)
+{
+ if (obj->delete_me == 2)
+ {
+ OBJ_ARRAY_PUSH(&e->delete_objects, obj);
+ obj->delete_me++;
+ return EINA_FALSE;
+ }
+ else if (obj->delete_me != 0) obj->delete_me++;
+ return EINA_TRUE;
+}
+
+static void
+_evas_render2_th_main_obj_basic_process(Evas_Public_Data *e,
+ Evas_Object_Protected_Data *obj,
+ void *updates,
+ int offx,
+ int offy,
+ int l EINA_UNUSED)
+{
+ Evas_Object *eo_obj = obj->object;
+
+ if (!_evas_render2_th_main_obj_del_handle(e, obj)) return;
+ evas_object_clip_recalc(obj);
+#ifdef DBG_OBJTREE
+ indent(l); printf("BASIC %p %p [%10s]\n", e, eo_obj, obj->type);
+#endif
+ if (obj->func->render2_walk)
+ obj->func->render2_walk(eo_obj, obj, obj->private_data,
+ updates, offx, offy);
+ if (obj->changed)
+ {
+ evas_object_clip_changes_clean(eo_obj);
+ evas_object_cur_prev(eo_obj);
+ evas_object_change_reset(eo_obj);
+ }
+}
+
+static void
+_evas_render2_th_main_obj_process(Evas_Public_Data *e,
+ Evas_Object_Protected_Data *obj,
+ void *updates,
+ int offx,
+ int offy,
+ int l EINA_UNUSED)
+{
+ // process object OR walk through child objects if smart and process those
+ Evas_Object_Protected_Data *obj2;
+ Evas_Object *eo_obj = obj->object;
+ const Eina_Inlist *il;
+
+ if (!obj->changed) return;
+ il = evas_object_smart_members_get_direct(eo_obj);
+ if (il)
+ {
+ if (!_evas_render2_th_main_obj_del_handle(e, obj)) return;
+ evas_object_clip_recalc(obj);
+#ifdef DBG_OBJTREE
+ indent(l); printf("SMART %p %p [%10s] ch %i\n", e, eo_obj, obj->type, obj->changed);
+#endif
+ if (obj->func->render2_walk)
+ obj->func->render2_walk(eo_obj, obj, obj->private_data,
+ updates, offx, offy);
+ EINA_INLIST_FOREACH(il, obj2)
+ _evas_render2_th_main_obj_process(e, obj2, updates,
+ offx, offy, l + 1);
+ if (obj->changed)
+ {
+ evas_object_clip_changes_clean(eo_obj);
+ evas_object_cur_prev(eo_obj);
+ evas_object_change_reset(eo_obj);
+ }
+ }
+ else _evas_render2_th_main_obj_basic_process(e, obj, updates,
+ offx, offy, l);
+}
+
+static void
+_evas_render2_th_main_do(Eo *eo_e, Evas_Public_Data *e)
+{
+ Render2_Finish_Data *render_finish_data;
+ Evas_Layer *lay;
+ Evas_Object_Protected_Data *obj;
+ double t;
+ Tilebuf *updates = NULL;
+ Tilebuf_Rect *rects, *r;
+ Eina_List *updates_list = NULL;
+ Eina_Rectangle *rect;
+
+ updates = evas_common_tilebuf_new(e->output.w, e->output.h);
+ evas_common_tilebuf_set_tile_size(updates, TILESIZE, TILESIZE);
+// evas_common_tilebuf_tile_strict_set(updates, EINA_TRUE);
+ static int num = 0;
+ printf("........... updates # %i\n", num++);
+ t = get_time();
+ EINA_INLIST_FOREACH(e->layers, lay)
+ {
+ EINA_INLIST_FOREACH(lay->objects, obj)
+ {
+ _evas_render2_th_main_obj_process(e, obj,
+ updates, 0, 0,
+ 0);
+ }
+ }
+ t = get_time() - t;
+ printf("T: update generation: "); out_time(t);
+
+ rects = evas_common_tilebuf_get_render_rects(updates);
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
+ {
+ rect = malloc(sizeof(Eina_Rectangle));
+ if (rect)
+ {
+ printf(" %i %i %ix%i\n", r->x, r->y, r->w, r->h);
+ rect->x = r->x; rect->y = r->y;
+ rect->w = r->w; rect->h = r->h;
+ updates_list = eina_list_append(updates_list, rect);
+ }
+ }
+ evas_common_tilebuf_free_render_rects(rects);
+
+ evas_common_tilebuf_free(updates);
+
+ e->changed = EINA_FALSE;
+ // remove from the "i'm rendering" pool - do back in mainloop
+ e->rendering = EINA_FALSE;
+ _rendering = eina_list_remove(_rendering, eo_e);
+ // unblock mainlopp that may be waiting on the render thread
+ eina_lock_release(&(e->lock_objects));
+
+ // send back
+ render_finish_data = calloc(1, sizeof(Render2_Finish_Data));
+ if (render_finish_data)
+ {
+ render_finish_data->eo_e = eo_e;
+ render_finish_data->e = e;
+ render_finish_data->updates = updates_list;
+ evas_async_events_put(render_finish_data, 0, NULL,
+ _evas_render2_th_main_mainloop_done);
+ }
+ else
+ {
+ EINA_LIST_FREE(updates_list, rect) free(rect);
+ }
+ eo_unref(eo_e);
+}
+
+static void *
+_evas_render2_th_main(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED)
+{
+ void *ref = NULL;
+ Msg_Main_Render *msg;
+
+ for (;;)
+ {
+ msg = eina_thread_queue_wait(_th_main_queue, &ref);
+ _evas_render2_th_main_do(msg->eo_e, msg->e);
+ eina_thread_queue_wait_done(_th_main_queue, ref);
+ }
+ return NULL;
+}
+
+static void
+_evas_render2_th_main_msg_render(Eo *eo_e, Evas_Public_Data *e)
+{
+ void *ref;
+ Msg_Main_Render *msg =
+ eina_thread_queue_send(_th_main_queue, sizeof(Msg_Main_Render), &ref);
+ msg->eo_e = eo_e;
+ msg->e = e;
+ eina_thread_queue_send_done(_th_main_queue, ref);
+}
Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
int (*can_map) (Evas_Object *obj);
+
+// new render2 functions
+
+ void (*render2_walk) (Evas_Object *obj, Evas_Object_Protected_Data *pd,
+ void *type_private_data, void *updates,
+ int offx, int offy);
+// void (*render2) (Evas_Object *obj, Evas_Object_Protected_Data *pd,
+// void *type_private_data, void *output, void *context,
+// void *surface, int x, int y);
};
struct _Evas_Func
Eina_List *ll;
Ecore_Evas *ee2;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
+ static int render2 = -1;
if ((!ee->no_comp_sync) && (_ecore_evas_app_comp_sync) &&
(edata->sync_counter) && (!edata->sync_began) &&
}
if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
- if (!ee->can_async_render)
+ if (render2 == -1)
{
- Eina_List *updates = evas_render_updates(ee->evas);
- rend = _render_updates_process(ee, updates);
- evas_render_updates_free(updates);
+ if (getenv("RENDER2")) render2 = 1;
+ else render2 = 0;
}
- else if (evas_render_async(ee->evas))
+ if (render2)
{
- EDBG("ee=%p started asynchronous render.", ee);
- ee->in_async_render = EINA_TRUE;
- rend = 1;
+ if (!ee->can_async_render)
+ {
+ Eina_List *updates = evas_render2_updates(ee->evas);
+ rend = _render_updates_process(ee, updates);
+ evas_render_updates_free(updates);
+ }
+ else
+ {
+ ee->in_async_render = EINA_TRUE;
+ if (evas_render2(ee->evas)) rend = 1;
+ else ee->in_async_render = EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (!ee->can_async_render)
+ {
+ Eina_List *updates = evas_render_updates(ee->evas);
+ rend = _render_updates_process(ee, updates);
+ evas_render_updates_free(updates);
+ }
+ else if (evas_render_async(ee->evas))
+ {
+ EDBG("ee=%p started asynchronous render.", ee);
+ ee->in_async_render = EINA_TRUE;
+ rend = 1;
+ }
+ else if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
}
- else if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
-
return rend;
}