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))
{
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);
+ // 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;
}
// 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);
}
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());
-}