diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 8094b7d494..3372143db3 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -240,6 +240,8 @@ lib/evas/canvas/evas_font_dir.c \ lib/evas/canvas/evas_rectangle.c \ lib/evas/canvas/evas_render.c \ lib/evas/canvas/evas_render2.c \ +lib/evas/canvas/evas_render2.h \ +lib/evas/canvas/evas_render2_updates.c \ lib/evas/canvas/evas_smart.c \ lib/evas/canvas/evas_stack.c \ lib/evas/canvas/evas_async_events.c \ diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index e8975c8395..8c710bc9c6 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -224,6 +224,7 @@ evas_object_change(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj) obj->changed_move = EINA_FALSE; } + if (obj->smart.smart) printf("change smart %p %i\n", obj, obj->changed); if (obj->changed) return; evas_render_object_recalc(eo_obj); diff --git a/src/lib/evas/canvas/evas_render2.c b/src/lib/evas/canvas/evas_render2.c index 7957b97abc..714ec52de3 100644 --- a/src/lib/evas/canvas/evas_render2.c +++ b/src/lib/evas/canvas/evas_render2.c @@ -1,14 +1,4 @@ -#include "evas_common_private.h" -#include "evas_private.h" -#include -#include -#ifdef EVAS_CSERVE2 -#include "evas_cs2_private.h" -#endif - -#ifdef EVAS_RENDER_DEBUG_TIMING -#include -#endif +#include "evas_render2.h" ////////////////////////////////////////////////////////////////////////////// // this is the start of a rewrite of the evas rendering infra. first port of @@ -25,11 +15,11 @@ // data types ////////////////////////////////////////////////////////////////////////////// -typedef struct Update Update; +typedef struct _Update Update; struct _Update { - Eina_Rectangle area; + Eina_Rectangle *area; void *surface; }; @@ -47,11 +37,10 @@ static void _evas_render2_wakeup_cb(void *target, Evas_Callback_Type type, void static void _evas_render2_wakeup_send(void *data); static void _evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info); static void _evas_render2_updates_clean(Evas_Public_Data *e); -static void _evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates); -static void _evas_render2_stage_generate_object_updates(Evas_Public_Data *e); +static void _evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates, Eina_Bool do_async); static void _evas_render2_stage_explicit_updates(Evas_Public_Data *e); static void _evas_render2_stage_main_render_prepare(Evas_Public_Data *e); -static void _evas_render2_stage_render_do(Evas_Public_Data *e); +static void _evas_render2_stage_render_do(Evas_Public_Data *e, Eina_Bool do_async); static void _evas_render2_stage_reset(Evas_Public_Data *e); static void _evas_render2_stage_object_cleanup(Evas_Public_Data *e); static void _evas_render2_th_render(void *data); @@ -93,7 +82,7 @@ _evas_render2_all_sync(void) { // wait for ALL canvases to stop rendering Eo *eo_e; - + if (!_rendering) return; eo_e = eina_list_data_get(eina_list_last(_rendering)); _evas_render2_wait(eo_e); @@ -120,7 +109,7 @@ static void _evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info) { int freeze_num = 0, i; - + eo_do(eo_e, freeze_num = eo_event_freeze_count_get()); for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_thaw()); evas_event_callback_call(eo_e, type, event_info); @@ -130,21 +119,19 @@ _evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info) static void _evas_render2_updates_clean(Evas_Public_Data *e) { - Update *u; + void *u; // clean out updates and tmp surfaces we were holding/tracking - EINA_LIST_FREE(e->render.updates, u) - { - //evas_cache_image_drop(u->surface); - free(u); - } + EINA_LIST_FREE(e->render.updates, u) eina_rectangle_free(u); } static void -_evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates) +_evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates, Eina_Bool do_async) { Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CANVAS_CLASS); - + Eina_List *ret_updates = NULL; + Evas_Event_Render_Post post; + // XXX: // XXX: actually update screen from mainloop here if needed - eg software // XXX: engine needs to xshmputimage here - engine func does this @@ -153,7 +140,22 @@ _evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates) // if we did do rendering flush output to target and call callbacks if (e->render.updates) { + Update *ru; + _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL); + 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, + EVAS_RENDER_MODE_ASYNC_END); + ret_updates = eina_list_append(ret_updates, ru->area); + evas_cache_image_drop(ru->surface); + free(ru); + } + if (do_async) post.updated_area = ret_updates; + else e->render.updates = ret_updates; e->engine.func->output_flush(e->engine.data.output, EVAS_RENDER_MODE_ASYNC_END); _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL); @@ -164,13 +166,8 @@ _evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates) _rendering = eina_list_remove(_rendering, eo_e); e->rendering = EINA_FALSE; // call the post render callback with info if appropriate - if ((1) || (e->render.updates)) - { - Evas_Event_Render_Post post; - - post.updated_area = e->render.updates; - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post); - } + if (do_async) + _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post); else _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL); // if we don't want to keep updates after this @@ -179,47 +176,6 @@ _evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates) evas_module_clean(); } -static void -_evas_render2_object_basic_process(Evas_Public_Data *e, - Evas_Object_Protected_Data *obj) -{ - printf("_evas_render2_object_basic_process %p %p\n", e, obj); -} - -static void -_evas_render2_object_process(Evas_Public_Data *e, - Evas_Object_Protected_Data *obj) -{ - // process object OR walk through child objects if smart and process those - Evas_Object_Protected_Data *obj2; - - // XXX: this needs to become parallel, BUT we need new object methods to - // call to make that possible as the current ones work on a single global - // engine handle and single orderted redraw queue. - if (obj->smart.smart) - { - EINA_INLIST_FOREACH - (evas_object_smart_members_get_direct(obj->object), obj2) - _evas_render2_object_process(e, obj2); - } - else _evas_render2_object_basic_process(e, obj); -} - -static void -_evas_render2_stage_generate_object_updates(Evas_Public_Data *e) -{ - Evas_Layer *lay; - - // XXX: should time this - EINA_INLIST_FOREACH(e->layers, lay) - { - Evas_Object_Protected_Data *obj; - - EINA_INLIST_FOREACH(lay->objects, obj) - _evas_render2_object_process(e, obj); - } -} - static void _evas_render2_stage_explicit_updates(Evas_Public_Data *e) { @@ -262,12 +218,48 @@ _evas_render2_stage_main_render_prepare(Evas_Public_Data *e) } static void -_evas_render2_stage_render_do(Evas_Public_Data *e) +_evas_render2_stage_render_do(Evas_Public_Data *e, Eina_Bool do_async EINA_UNUSED) { - // XXX: + void *surface; + int ux, uy, uw, uh; + int cx, cy, cw, ch; +// Evas_Render_Mode render_mode = EVAS_RENDER_MODE_UNDEF; + +// if (!do_async) render_mode = EVAS_RENDER_MODE_SYNC; +// else render_mode = EVAS_RENDER_MODE_ASYNC_INIT;// XXX: // XXX: actually render now (either in thread or in mainloop) // XXX: printf("_evas_render2_stage_render_do %p\n", e); + while ((surface = + e->engine.func->output_redraws_next_update_get + (e->engine.data.output, + &ux, &uy, &uw, &uh, + &cx, &cy, &cw, &ch))) + { + Update *ru = NULL; + void *ctx; + + ctx = e->engine.func->context_new(e->engine.data.output); + e->engine.func->context_color_set + (e->engine.data.output, ctx, + rand() & 0xff, rand() & 0xff, rand() & 0xff, 0xff); + printf("%i %i %i %i\n", cx, cy, cw, ch); + e->engine.func->rectangle_draw(e->engine.data.output, + ctx, surface, + cx, cy, cw, ch, + EINA_FALSE); + e->engine.func->context_free(e->engine.data.output, ctx); + 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); +// e->engine.func->output_redraws_next_update_push(e->engine.data.output, +// surface, +// ux, uy, uw, uh, +// render_mode); + } + e->engine.func->output_redraws_clear(e->engine.data.output); } static void @@ -295,8 +287,8 @@ static void _evas_render2_th_render(void *data) { Evas_Public_Data *e = data; - printf("th rend %p\n", e); - _evas_render2_stage_render_do(e); + printf("th rend %p ......................................\n", e); + _evas_render2_stage_render_do(e, EINA_TRUE); } // major functions (called from evas_render.c) @@ -310,7 +302,7 @@ _evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, Eina_Bool do_draw, Eina_Bool do_async) { Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CANVAS_CLASS); - + // 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 frame @@ -344,15 +336,23 @@ _evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, evas_thread_queue_flush(_evas_render2_wakeup_send, eo_e); } // or if not async, do rendering inline now - else _evas_render2_stage_render_do(e); + else _evas_render2_stage_render_do(e, EINA_FALSE); } // reset flags since rendering is processed now _evas_render2_stage_reset(e); // clean/delete/gc objects here _evas_render2_stage_object_cleanup(e); // if we are not going to be async then do last render stage here - if (!do_async) _evas_render2_stage_last(eo_e, make_updates); + if (!do_async) _evas_render2_stage_last(eo_e, make_updates, EINA_FALSE); if (!do_draw) _evas_render2_updates_clean(e); + + e->changed = EINA_FALSE; + e->viewport.changed = EINA_FALSE; + e->output.changed = EINA_FALSE; + e->framespace.changed = EINA_FALSE; + e->invalidate = EINA_FALSE; + + evas_module_clean(); return EINA_TRUE; } @@ -365,7 +365,7 @@ _evas_render2_end(Eo *eo_e) // this is actually called if rendering was async and is done. this is // run in the mainloop where rendering began and may handle any cleanup // or pixel upload if needed here - _evas_render2_stage_last(eo_e, EINA_TRUE); + _evas_render2_stage_last(eo_e, EINA_TRUE, EINA_TRUE); // release canvas object ref eo_unref(eo_e); } diff --git a/src/lib/evas/canvas/evas_render2.h b/src/lib/evas/canvas/evas_render2.h new file mode 100644 index 0000000000..2eb77e7dc7 --- /dev/null +++ b/src/lib/evas/canvas/evas_render2.h @@ -0,0 +1,43 @@ +#ifndef EVAS_RENDER2_H +#define EVAS_RENDER2_H +#include "evas_common_private.h" +#include "evas_private.h" +#include +#include +#ifdef EVAS_CSERVE2 +#include "evas_cs2_private.h" +#endif + +#ifdef EVAS_RENDER_DEBUG_TIMING +#include +#endif + +/* render stuff here */ +void _evas_render2_stage_generate_object_updates(Evas_Public_Data *e); + +#ifndef _WIN32 +static inline double +get_time(void) +{ + struct timeval timev; + gettimeofday(&timev, NULL); + return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000); +} +#else +static inline double +get_time(void) +{ + return (double)GetTickCount()/1000.0; +} +#endif + +static inline void +out_time(double t) +{ + double b; + + b = (t * 100.0) / (1.0 / 60.0); + printf("%1.8fs (%1.2f%% 60fps budget)\n", t, b); +} + +#endif diff --git a/src/lib/evas/canvas/evas_render2_updates.c b/src/lib/evas/canvas/evas_render2_updates.c new file mode 100644 index 0000000000..50f69b6f1f --- /dev/null +++ b/src/lib/evas/canvas/evas_render2_updates.c @@ -0,0 +1,77 @@ +#include "evas_render2.h" + +static void +_obj_basic_process(Evas_Public_Data *e, + Evas_Object_Protected_Data *obj, int l) +{ + Evas_Object *eo_obj = obj->object; + + obj->rect_del = EINA_FALSE; + obj->render_pre = EINA_FALSE; + if (obj->delete_me == 2) return; + else if (obj->delete_me != 0) obj->delete_me++; + evas_object_clip_recalc(obj); + obj->is_active = 1; + obj->func->render_pre(eo_obj, obj, obj->private_data); + obj->pre_render_done = EINA_TRUE; + int i; for (i = 0; i < l; i++) printf(" "); + printf("BASIC %p %p\n", e, obj); + obj->func->render_post(eo_obj, obj, obj->private_data); + obj->restack = EINA_FALSE; + obj->pre_render_done = EINA_FALSE; + evas_object_change_reset(eo_obj); +} + +static void +_obj_process(Evas_Public_Data *e, + Evas_Object_Protected_Data *obj, int l) +{ + // process object OR walk through child objects if smart and process those + Evas_Object_Protected_Data *obj2; + Evas_Object *eo_obj = obj->object; + + if (obj->smart.smart) + { + if (!evas_object_smart_changed_get(eo_obj)) return; + obj->rect_del = EINA_FALSE; + obj->render_pre = EINA_FALSE; + if (obj->delete_me == 2) return; + else if (obj->delete_me != 0) obj->delete_me++; + evas_object_clip_recalc(obj); + obj->is_active = 1; + obj->func->render_pre(eo_obj, obj, obj->private_data); + obj->pre_render_done = EINA_TRUE; + int i; for (i = 0; i < l; i++) printf(" "); + printf("SMART %p %p\n", e, obj); + + EINA_INLIST_FOREACH + (evas_object_smart_members_get_direct(obj->object), obj2) + _obj_process(e, obj2, l + 1); + + obj->func->render_post(eo_obj, obj, obj->private_data); + obj->restack = EINA_FALSE; + obj->pre_render_done = EINA_FALSE; + evas_object_change_reset(eo_obj); + } + else + { + if (!obj->changed) return; + _obj_basic_process(e, obj, l); + } +} + +void +_evas_render2_stage_generate_object_updates(Evas_Public_Data *e) +{ + Evas_Layer *lay; + Evas_Object_Protected_Data *obj; + double t; + + t = get_time(); + EINA_INLIST_FOREACH(e->layers, lay) + { + EINA_INLIST_FOREACH(lay->objects, obj) _obj_process(e, obj, 0); + } + t = get_time() - t; + printf("T: update generation: "); out_time(t); +}