Hi Raster, I see where you're heading... let's see the outcome. :-) I have a question below inline.
On Fri, Dec 20, 2013 at 8:44 AM, Carsten Haitzler <[email protected]> wrote: > > raster pushed a commit to branch master. > > http://git.enlightenment.org/core/efl.git/commit/?id=cb841b56af11bbf787b36b3aaf6c6e69f1e1490f > > commit cb841b56af11bbf787b36b3aaf6c6e69f1e1490f > Author: Carsten Haitzler (Rasterman) <[email protected]> > Date: Fri Dec 20 19:45:17 2013 +0900 > > evas render2 - more work on basics > --- > src/lib/evas/canvas/evas_render.c | 15 +- > src/lib/evas/canvas/evas_render2.c | 459 > +++++++++++++++++++++---------------- > 2 files changed, 263 insertions(+), 211 deletions(-) > > diff --git a/src/lib/evas/canvas/evas_render.c > b/src/lib/evas/canvas/evas_render.c > index 6dab39c..a6b5768 100644 > --- a/src/lib/evas/canvas/evas_render.c > +++ b/src/lib/evas/canvas/evas_render.c > @@ -10,15 +10,12 @@ > #include <sys/time.h> > #endif > > -Eina_Bool > -_evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, > - Eina_Bool do_draw, Eina_Bool do_async); > -void > -_evas_render2_idle_flush(Eo *eo_e); > -void > -_evas_render2_dump(Eo *eo_e); > -void > -_evas_render2_wait(Eo *eo_e); > +// symbols of funcs from evas_render2 which is a next-gen replacement of > +// the current evas render code. see evas_render2.c for more. > +Eina_Bool _evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, Eina_Bool > do_draw, Eina_Bool do_async); > +void _evas_render2_idle_flush(Eo *eo_e); > +void _evas_render2_dump(Eo *eo_e); > +void _evas_render2_wait(Eo *eo_e); > > > /* debug rendering > diff --git a/src/lib/evas/canvas/evas_render2.c > b/src/lib/evas/canvas/evas_render2.c > index ce95b02..f853473 100644 > --- a/src/lib/evas/canvas/evas_render2.c > +++ b/src/lib/evas/canvas/evas_render2.c > @@ -40,49 +40,193 @@ void _evas_render2_idle_flush(Eo *eo_e); > void _evas_render2_dump(Eo *eo_e); > void _evas_render2_wait(Eo *eo_e); > > -static void _evas_render2_end(Eo *eo_e); > - > static void _evas_render2_cow_gc(Eina_Cow *cow, int max); > static void _evas_render2_cow_all_gc(int max); > static void _evas_render2_all_sync(void); > static void _evas_render2_wakeup_cb(void *target, Evas_Callback_Type type, > void *event_info); > 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_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_reset(Evas_Public_Data *e); > +static void _evas_render2_stage_object_cleanup(Evas_Public_Data *e); > +static void _evas_render2_th_render(void *data); > +static void _evas_render2_end(Eo *eo_e); > > // global data (for rendering only) > > ////////////////////////////////////////////////////////////////////////////// > static Eina_List *_rendering = NULL; > > +// actual helper/internal functions > > ////////////////////////////////////////////////////////////////////////////// > +static void > +_evas_render2_cow_gc(Eina_Cow *cow, int max) > +{ > + // gc a single cow type up to max iter or if max <= 0, all of them > + int i = 0; > > -/////////////////////////////////////////////////////////////////////// > -// BEGIN RENDERING (in mainloop) > -/////////////////////////////////////////////////////////////////////// > -Eina_Bool > -_evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, > - Eina_Bool do_draw, Eina_Bool do_async) > + while (eina_cow_gc(cow)) > + { > + if (max < 1) continue; > + i++; > + if (i > max) break; > + } > +} > + > +static void > +_evas_render2_cow_all_gc(int max) > { > - Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); > - Eina_Rectangle *r; > - Eina_List *l; > + // gc all known cow types > + _evas_render2_cow_gc(evas_object_proxy_cow, max); > + _evas_render2_cow_gc(evas_object_map_cow, max); > + _evas_render2_cow_gc(evas_object_image_pixels_cow, max); > + _evas_render2_cow_gc(evas_object_image_load_opts_cow, max); > + _evas_render2_cow_gc(evas_object_image_state_cow, max); > +} > + > +static void > +_evas_render2_all_sync(void) > +{ > + // wait for ALL canvases to stop rendering > + Eo *eo_e; > > - // 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 > - if (e->rendering && do_async) return EINA_FALSE; > - // check viewport size is same as output - not allowed to differ > - if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h)) > - ERR("viewport size != output size!"); > + if (!_rendering) return; > + eo_e = eina_list_data_get(eina_list_last(_rendering)); > + _evas_render2_wait(eo_e); > +} > > - // call canvas callbacks saying we are in the pre-render state > - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL); > - // we have to calculate smare objects before render so do that here > - evas_call_smarts_calculate(eo_e); > +static void > +_evas_render2_wakeup_cb(void *target, Evas_Callback_Type type EINA_UNUSED, > void *event_info EINA_UNUSED) > +{ > + // in mainloop run the rendering end handler > + Eo *eo_e = target; > + > + _evas_render2_end(eo_e); > +} > + > +static void > +_evas_render2_wakeup_send(void *data) > +{ > + // pass an event to the mainloop async event handler in evas so mainloop > + // runs wakeup_cb and not in any thread > + evas_async_events_put(data, 0, NULL, _evas_render2_wakeup_cb); > +} > + > +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, eo_event_freeze_get(&freeze_num)); > + for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_thaw()); > + evas_event_callback_call(eo_e, type, event_info); > + for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_freeze()); > +} > > +static void > +_evas_render2_updates_clean(Evas_Public_Data *e) > +{ > + Update *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); > + } > +} > + > +static void > +_evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates) > +{ > + Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); > + > // XXX: > - // XXX: process all objects figuring out update regions > + // XXX: actually update screen from mainloop here if needed - eg software > + // XXX: engine needs to xshmputimage here - engine func does this > // XXX: > + > + // if we did do rendering flush output to target and call callbacks > + if (e->render.updates) > + { > + _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, > NULL); > + 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); > + } > + // clear our previous rendering stuff from the engine > + e->engine.func->output_redraws_clear(e->engine.data.output); > + // stop tracking canvas as being async rendered > + _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); > + } > + else > + _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL); > + // if we don't want to keep updates after this > + if (!make_updates) _evas_render2_updates_clean(e); > + // clean out modules we don't need anymore > + 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) > +{ > + Eina_Rectangle *r; > + Eina_List *l; > + > + // XXX: should time this > // if the output size changed, add a full redraw > if ((e->output.changed) || (e->framespace.changed)) > { > @@ -104,87 +248,111 @@ _evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, > EINA_LIST_FOREACH(e->obscures, l, r) > e->engine.func->output_redraws_rect_del(e->engine.data.output, > r->x, r->y, r->w, r->h); > - > - // we are actually asked to draw not just go through the motions for gc > - if (do_draw) > - { > - // XXX: > - // XXX: RENDER HERE! > - if (do_async) > - { > - // XXX: send off render commands > - } > - else > - { > - // XXX: do render that is sent of above right here > - } > - // XXX: > +} > > - // if we are async... > - if (do_async) > - { > - // ref the canvas so it stays while threads wortk > - eo_ref(eo_e); > - // track hanvas in list of things going in the background > - e->rendering = EINA_TRUE; > - _rendering = eina_list_append(_rendering, eo_e); > - // flush the thread queue > - evas_thread_queue_flush > - ((Evas_Thread_Command_Cb)_evas_render2_wakeup_send, eo_e); > - } > - // if not async but we had actual update regions drawn > - else if (e->render.updates) > - { > - // call output flush and callbacks around it > - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, > - NULL); > - e->engine.func->output_flush(e->engine.data.output, > - EVAS_RENDER_MODE_SYNC); > - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, > - NULL); > - } > - } > +static void > +_evas_render2_stage_main_render_prepare(Evas_Public_Data *e) > +{ > + // XXX: > + // XXX: do any preparation work here that is needed for the render > + // XXX: threads to do their work, but can't be done in a thread. this > + // XXX: also includes doing the pose render and clear of change flag > + // XXX: > + printf("_evas_render2_stage_main_render_prepare %p\n", e); > +} > > - // reset flags sinc rendering is processed now > +static void > +_evas_render2_stage_render_do(Evas_Public_Data *e) > +{ > + // XXX: > + // XXX: actually render now (either in thread or in mainloop) > + // XXX: > + printf("_evas_render2_stage_render_do %p\n", e); > +} > + > +static void > +_evas_render2_stage_reset(Evas_Public_Data *e) > +{ > + // cleanup canvas state after a render > e->changed = EINA_FALSE; > e->viewport.changed = EINA_FALSE; > e->output.changed = EINA_FALSE; > e->framespace.changed = EINA_FALSE; > e->invalidate = EINA_FALSE; > +} > > +static void > +_evas_render2_stage_object_cleanup(Evas_Public_Data *e) > +{ > + // cleanup objects no longer needed now they have been scanned > // XXX: > // XXX: delete objects no longer needed here > // XXX: > + printf("_evas_render2_stage_object_cleanup %p\n", e); > +} > > - // if we are not going to be async then do post render here > - if (!do_async) > +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); > +} > + > +// major functions (called from evas_render.c) > +////////////////////////////////////////////////////////////////////////////// > + > +/////////////////////////////////////////////////////////////////////// > +// BEGIN RENDERING (in mainloop) > +/////////////////////////////////////////////////////////////////////// > +Eina_Bool > +_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_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 > + if (e->rendering && do_async) return EINA_FALSE; > + // check viewport size is same as output - not allowed to differ > + if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h)) > + ERR("viewport size != output size!"); > + // call canvas callbacks saying we are in the pre-render state > + _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL); > + // we have to calculate smare objects before render so do that here > + evas_call_smarts_calculate(eo_e); > + // begin out actual rendering bits > + _evas_render2_stage_generate_object_updates(e); > + _evas_render2_stage_explicit_updates(e); > + // we are actually asked to draw not just go through the motions for gc > + if (do_draw) > { > - // clear our previous rendering stuff from the engine > - e->engine.func->output_redraws_clear(e->engine.data.output); > - // call the post render callback with info if appropriate > - if (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); > - } > - else > - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL); > - // clean out modules we don't need anymore > - evas_module_clean(); > - // clean out updates and tmp surfaces we were holding/tracking > - if (!make_updates) > + // now go through any preparation that needs doing in the mainloop > + _evas_render2_stage_main_render_prepare(e); > + // send off rendering to primary thread renderer > + if (do_async) > { > - Update *u; > - > - EINA_LIST_FREE(e->render.updates, u) > - { > - //evas_cache_image_drop(u->surface); > - free(u); > - } > + // ref the canvas so it stays while threads wortk > + eo_ref(eo_e); > + // track hanvas in list of things going in the background > + e->rendering = EINA_TRUE; > + _rendering = eina_list_append(_rendering, eo_e); > + // queue the render thread command > + evas_thread_cmd_enqueue(_evas_render2_th_render, e); > + // flush the thread queue and call wakeup_send in the thread > + 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); > } > + // reset flags since rendering is processed now > + _evas_render2_stage_reset(e); > + // clean/delete/gc objects here > + _evas_render2_stage_object_cleanup(e); Don't we need to do these last 2 calls only if !do_async? And if do_async then in your wake up function in the mainloop you reset flags and cleanup objects? -- Ulisses > + // 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_draw) _evas_render2_updates_clean(e); > return EINA_TRUE; > } > > @@ -197,50 +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_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); > - Eina_Bool have_updates = EINA_FALSE; > - Update *u; > - > - // XXX: > - // XXX: actually update screen from mainloop here if needed - eg software > - // engine needs to xshmputimage here > - // XXX: > - > - // clean out updates and tmp surfaces we were holding/tracking > - if (e->render.updates) > - { > - have_updates = EINA_TRUE; > - EINA_LIST_FREE(e->render.updates, u) > - { > - //evas_cache_image_drop(u->surface); > - free(u); > - } > - } > - // if we did do rendering flush output to target and call callbacks > - if (have_updates) > - { > - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, > NULL); > - 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); > - } > - // clear our previous rendering stuff from the engine > - e->engine.func->output_redraws_clear(e->engine.data.output); > - // stop tracking canvas as being async rendered > - _rendering = eina_list_remove(_rendering, eo_e); > - e->rendering = EINA_FALSE; > - // call the post render callback with info if appropriate > - if (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); > - } > - else > - _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL); > - // clean out modules we don't need anymore > - evas_module_clean(); > + _evas_render2_stage_last(eo_e, EINA_TRUE); > // release canvas object ref > eo_unref(eo_e); > } > @@ -302,73 +427,3 @@ _evas_render2_wait(Eo *eo_e) > Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); > while (e->rendering) evas_async_events_process_blocking(); > } > - > - > - > - > -// helpers > -////////////////////////////////////////////////////////////////////////////// > - > -static void > -_evas_render2_cow_gc(Eina_Cow *cow, int max) > -{ > - // gc a single cow type up to max iter or if max <= 0, all of them > - int i = 0; > - > - while (eina_cow_gc(cow)) > - { > - if (max < 1) continue; > - i++; > - if (i > max) break; > - } > -} > - > -static void > -_evas_render2_cow_all_gc(int max) > -{ > - // gc all known cow types > - _evas_render2_cow_gc(evas_object_proxy_cow, max); > - _evas_render2_cow_gc(evas_object_map_cow, max); > - _evas_render2_cow_gc(evas_object_image_pixels_cow, max); > - _evas_render2_cow_gc(evas_object_image_load_opts_cow, max); > - _evas_render2_cow_gc(evas_object_image_state_cow, max); > -} > - > -static void > -_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); > -} > - > -static void > -_evas_render2_wakeup_cb(void *target, Evas_Callback_Type type EINA_UNUSED, > void *event_info EINA_UNUSED) > -{ > - // in mainloop run the rendering end handler > - Eo *eo_e = target; > - > - _evas_render2_end(eo_e); > -} > - > -static void > -_evas_render2_wakeup_send(void *data) > -{ > - // pass an event to the mainloop async event handler in evas so mainloop > - // runs wakeup_cb and not in any thread > - evas_async_events_put(data, 0, NULL, _evas_render2_wakeup_cb); > -} > - > -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, eo_event_freeze_get(&freeze_num)); > - for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_thaw()); > - evas_event_callback_call(eo_e, type, event_info); > - for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_freeze()); > -} > > -- > > ------------------------------------------------------------------------------ Rapidly troubleshoot problems before they affect your business. Most IT organizations don't have a clear picture of how application performance affects their revenue. With AppDynamics, you get 100% visibility into your Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk _______________________________________________ enlightenment-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/enlightenment-devel
