The current async render is sending each render command to the thread, and here it seems you want a thread to do the whole render. That wasn't very clear, let's try again.
Are you planning on messing with the object's render functions so they can be called from a thread? As opposed as what we have now, where they are called from the main loop, they in turn call the engine functions and these will check the do_async flag to decide if they draw in place or if they send a command to the render thread. On Fri, Dec 20, 2013 at 11:46 AM, Ulisses Furquim <[email protected]> wrote: > 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 ------------------------------------------------------------------------------ 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
