summaryrefslogtreecommitdiff
path: root/src/lib/evas/canvas/evas_render2.c
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2013-12-20 19:45:17 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2013-12-20 19:45:44 +0900
commitcb841b56af11bbf787b36b3aaf6c6e69f1e1490f (patch)
tree78a35a0e97d766f402fdf2f757660ebb56dc0c04 /src/lib/evas/canvas/evas_render2.c
parent1a5b7d383d6ec05d1499fcbbddae496c77d87e1f (diff)
evas render2 - more work on basics
Diffstat (limited to '')
-rw-r--r--src/lib/evas/canvas/evas_render2.c459
1 files changed, 257 insertions, 202 deletions
diff --git a/src/lib/evas/canvas/evas_render2.c b/src/lib/evas/canvas/evas_render2.c
index ce95b02008..f853473a56 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);
40void _evas_render2_dump(Eo *eo_e); 40void _evas_render2_dump(Eo *eo_e);
41void _evas_render2_wait(Eo *eo_e); 41void _evas_render2_wait(Eo *eo_e);
42 42
43static void _evas_render2_end(Eo *eo_e);
44
45static void _evas_render2_cow_gc(Eina_Cow *cow, int max); 43static void _evas_render2_cow_gc(Eina_Cow *cow, int max);
46static void _evas_render2_cow_all_gc(int max); 44static void _evas_render2_cow_all_gc(int max);
47static void _evas_render2_all_sync(void); 45static void _evas_render2_all_sync(void);
48static void _evas_render2_wakeup_cb(void *target, Evas_Callback_Type type, void *event_info); 46static void _evas_render2_wakeup_cb(void *target, Evas_Callback_Type type, void *event_info);
49static void _evas_render2_wakeup_send(void *data); 47static void _evas_render2_wakeup_send(void *data);
50static void _evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info); 48static void _evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info);
49static void _evas_render2_updates_clean(Evas_Public_Data *e);
50static void _evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates);
51static void _evas_render2_stage_generate_object_updates(Evas_Public_Data *e);
52static void _evas_render2_stage_explicit_updates(Evas_Public_Data *e);
53static void _evas_render2_stage_main_render_prepare(Evas_Public_Data *e);
54static void _evas_render2_stage_render_do(Evas_Public_Data *e);
55static void _evas_render2_stage_reset(Evas_Public_Data *e);
56static void _evas_render2_stage_object_cleanup(Evas_Public_Data *e);
57static void _evas_render2_th_render(void *data);
58static void _evas_render2_end(Eo *eo_e);
51 59
52// global data (for rendering only) 60// global data (for rendering only)
53////////////////////////////////////////////////////////////////////////////// 61//////////////////////////////////////////////////////////////////////////////
54static Eina_List *_rendering = NULL; 62static Eina_List *_rendering = NULL;
55 63
64// actual helper/internal functions
56////////////////////////////////////////////////////////////////////////////// 65//////////////////////////////////////////////////////////////////////////////
66static void
67_evas_render2_cow_gc(Eina_Cow *cow, int max)
68{
69 // gc a single cow type up to max iter or if max <= 0, all of them
70 int i = 0;
57 71
58/////////////////////////////////////////////////////////////////////// 72 while (eina_cow_gc(cow))
59// BEGIN RENDERING (in mainloop) 73 {
60/////////////////////////////////////////////////////////////////////// 74 if (max < 1) continue;
61Eina_Bool 75 i++;
62_evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, 76 if (i > max) break;
63 Eina_Bool do_draw, Eina_Bool do_async) 77 }
78}
79
80static void
81_evas_render2_cow_all_gc(int max)
64{ 82{
65 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); 83 // gc all known cow types
66 Eina_Rectangle *r; 84 _evas_render2_cow_gc(evas_object_proxy_cow, max);
67 Eina_List *l; 85 _evas_render2_cow_gc(evas_object_map_cow, max);
86 _evas_render2_cow_gc(evas_object_image_pixels_cow, max);
87 _evas_render2_cow_gc(evas_object_image_load_opts_cow, max);
88 _evas_render2_cow_gc(evas_object_image_state_cow, max);
89}
90
91static void
92_evas_render2_all_sync(void)
93{
94 // wait for ALL canvases to stop rendering
95 Eo *eo_e;
68 96
69 // if nothing changed at all since last render - skip this frame 97 if (!_rendering) return;
70 if (!e->changed) return EINA_FALSE; 98 eo_e = eina_list_data_get(eina_list_last(_rendering));
71 // we are still rendering while being asked to render - skip this frame 99 _evas_render2_wait(eo_e);
72 if (e->rendering && do_async) return EINA_FALSE; 100}
73 // check viewport size is same as output - not allowed to differ
74 if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
75 ERR("viewport size != output size!");
76 101
77 // call canvas callbacks saying we are in the pre-render state 102static void
78 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL); 103_evas_render2_wakeup_cb(void *target, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
79 // we have to calculate smare objects before render so do that here 104{
80 evas_call_smarts_calculate(eo_e); 105 // in mainloop run the rendering end handler
106 Eo *eo_e = target;
107
108 _evas_render2_end(eo_e);
109}
110
111static void
112_evas_render2_wakeup_send(void *data)
113{
114 // pass an event to the mainloop async event handler in evas so mainloop
115 // runs wakeup_cb and not in any thread
116 evas_async_events_put(data, 0, NULL, _evas_render2_wakeup_cb);
117}
118
119static void
120_evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info)
121{
122 int freeze_num = 0, i;
123
124 eo_do(eo_e, eo_event_freeze_get(&freeze_num));
125 for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_thaw());
126 evas_event_callback_call(eo_e, type, event_info);
127 for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_freeze());
128}
81 129
130static void
131_evas_render2_updates_clean(Evas_Public_Data *e)
132{
133 Update *u;
134
135 // clean out updates and tmp surfaces we were holding/tracking
136 EINA_LIST_FREE(e->render.updates, u)
137 {
138 //evas_cache_image_drop(u->surface);
139 free(u);
140 }
141}
142
143static void
144_evas_render2_stage_last(Eo *eo_e, Eina_Bool make_updates)
145{
146 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
147
82 // XXX: 148 // XXX:
83 // XXX: process all objects figuring out update regions 149 // XXX: actually update screen from mainloop here if needed - eg software
150 // XXX: engine needs to xshmputimage here - engine func does this
84 // XXX: 151 // XXX:
152
153 // if we did do rendering flush output to target and call callbacks
154 if (e->render.updates)
155 {
156 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
157 e->engine.func->output_flush(e->engine.data.output,
158 EVAS_RENDER_MODE_ASYNC_END);
159 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
160 }
161 // clear our previous rendering stuff from the engine
162 e->engine.func->output_redraws_clear(e->engine.data.output);
163 // stop tracking canvas as being async rendered
164 _rendering = eina_list_remove(_rendering, eo_e);
165 e->rendering = EINA_FALSE;
166 // call the post render callback with info if appropriate
167 if ((1) || (e->render.updates))
168 {
169 Evas_Event_Render_Post post;
170
171 post.updated_area = e->render.updates;
172 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
173 }
174 else
175 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL);
176 // if we don't want to keep updates after this
177 if (!make_updates) _evas_render2_updates_clean(e);
178 // clean out modules we don't need anymore
179 evas_module_clean();
180}
181
182static void
183_evas_render2_object_basic_process(Evas_Public_Data *e,
184 Evas_Object_Protected_Data *obj)
185{
186 printf("_evas_render2_object_basic_process %p %p\n", e, obj);
187}
188
189static void
190_evas_render2_object_process(Evas_Public_Data *e,
191 Evas_Object_Protected_Data *obj)
192{
193 // process object OR walk through child objects if smart and process those
194 Evas_Object_Protected_Data *obj2;
195
196 // XXX: this needs to become parallel, BUT we need new object methods to
197 // call to make that possible as the current ones work on a single global
198 // engine handle and single orderted redraw queue.
199 if (obj->smart.smart)
200 {
201 EINA_INLIST_FOREACH
202 (evas_object_smart_members_get_direct(obj->object), obj2)
203 _evas_render2_object_process(e, obj2);
204 }
205 else _evas_render2_object_basic_process(e, obj);
206}
207
208static void
209_evas_render2_stage_generate_object_updates(Evas_Public_Data *e)
210{
211 Evas_Layer *lay;
212
213 // XXX: should time this
214 EINA_INLIST_FOREACH(e->layers, lay)
215 {
216 Evas_Object_Protected_Data *obj;
85 217
218 EINA_INLIST_FOREACH(lay->objects, obj)
219 _evas_render2_object_process(e, obj);
220 }
221}
222
223static void
224_evas_render2_stage_explicit_updates(Evas_Public_Data *e)
225{
226 Eina_Rectangle *r;
227 Eina_List *l;
228
229 // XXX: should time this
86 // if the output size changed, add a full redraw 230 // if the output size changed, add a full redraw
87 if ((e->output.changed) || (e->framespace.changed)) 231 if ((e->output.changed) || (e->framespace.changed))
88 { 232 {
@@ -104,87 +248,111 @@ _evas_render2_begin(Eo *eo_e, Eina_Bool make_updates,
104 EINA_LIST_FOREACH(e->obscures, l, r) 248 EINA_LIST_FOREACH(e->obscures, l, r)
105 e->engine.func->output_redraws_rect_del(e->engine.data.output, 249 e->engine.func->output_redraws_rect_del(e->engine.data.output,
106 r->x, r->y, r->w, r->h); 250 r->x, r->y, r->w, r->h);
107 251}
108 // we are actually asked to draw not just go through the motions for gc
109 if (do_draw)
110 {
111 // XXX:
112 // XXX: RENDER HERE!
113 if (do_async)
114 {
115 // XXX: send off render commands
116 }
117 else
118 {
119 // XXX: do render that is sent of above right here
120 }
121 // XXX:
122 252
123 // if we are async... 253static void
124 if (do_async) 254_evas_render2_stage_main_render_prepare(Evas_Public_Data *e)
125 { 255{
126 // ref the canvas so it stays while threads wortk 256 // XXX:
127 eo_ref(eo_e); 257 // XXX: do any preparation work here that is needed for the render
128 // track hanvas in list of things going in the background 258 // XXX: threads to do their work, but can't be done in a thread. this
129 e->rendering = EINA_TRUE; 259 // XXX: also includes doing the pose render and clear of change flag
130 _rendering = eina_list_append(_rendering, eo_e); 260 // XXX:
131 // flush the thread queue 261 printf("_evas_render2_stage_main_render_prepare %p\n", e);
132 evas_thread_queue_flush 262}
133 ((Evas_Thread_Command_Cb)_evas_render2_wakeup_send, eo_e);
134 }
135 // if not async but we had actual update regions drawn
136 else if (e->render.updates)
137 {
138 // call output flush and callbacks around it
139 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE,
140 NULL);
141 e->engine.func->output_flush(e->engine.data.output,
142 EVAS_RENDER_MODE_SYNC);
143 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST,
144 NULL);
145 }
146 }
147 263
148 // reset flags sinc rendering is processed now 264static void
265_evas_render2_stage_render_do(Evas_Public_Data *e)
266{
267 // XXX:
268 // XXX: actually render now (either in thread or in mainloop)
269 // XXX:
270 printf("_evas_render2_stage_render_do %p\n", e);
271}
272
273static void
274_evas_render2_stage_reset(Evas_Public_Data *e)
275{
276 // cleanup canvas state after a render
149 e->changed = EINA_FALSE; 277 e->changed = EINA_FALSE;
150 e->viewport.changed = EINA_FALSE; 278 e->viewport.changed = EINA_FALSE;
151 e->output.changed = EINA_FALSE; 279 e->output.changed = EINA_FALSE;
152 e->framespace.changed = EINA_FALSE; 280 e->framespace.changed = EINA_FALSE;
153 e->invalidate = EINA_FALSE; 281 e->invalidate = EINA_FALSE;
282}
154 283
284static void
285_evas_render2_stage_object_cleanup(Evas_Public_Data *e)
286{
287 // cleanup objects no longer needed now they have been scanned
155 // XXX: 288 // XXX:
156 // XXX: delete objects no longer needed here 289 // XXX: delete objects no longer needed here
157 // XXX: 290 // XXX:
291 printf("_evas_render2_stage_object_cleanup %p\n", e);
292}
158 293
159 // if we are not going to be async then do post render here 294static void
160 if (!do_async) 295_evas_render2_th_render(void *data)
296{
297 Evas_Public_Data *e = data;
298 printf("th rend %p\n", e);
299 _evas_render2_stage_render_do(e);
300}
301
302// major functions (called from evas_render.c)
303//////////////////////////////////////////////////////////////////////////////
304
305///////////////////////////////////////////////////////////////////////
306// BEGIN RENDERING (in mainloop)
307///////////////////////////////////////////////////////////////////////
308Eina_Bool
309_evas_render2_begin(Eo *eo_e, Eina_Bool make_updates,
310 Eina_Bool do_draw, Eina_Bool do_async)
311{
312 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
313
314 // if nothing changed at all since last render - skip this frame
315 if (!e->changed) return EINA_FALSE;
316 // we are still rendering while being asked to render - skip this frame
317 if (e->rendering && do_async) return EINA_FALSE;
318 // check viewport size is same as output - not allowed to differ
319 if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
320 ERR("viewport size != output size!");
321 // call canvas callbacks saying we are in the pre-render state
322 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL);
323 // we have to calculate smare objects before render so do that here
324 evas_call_smarts_calculate(eo_e);
325 // begin out actual rendering bits
326 _evas_render2_stage_generate_object_updates(e);
327 _evas_render2_stage_explicit_updates(e);
328 // we are actually asked to draw not just go through the motions for gc
329 if (do_draw)
161 { 330 {
162 // clear our previous rendering stuff from the engine 331 // now go through any preparation that needs doing in the mainloop
163 e->engine.func->output_redraws_clear(e->engine.data.output); 332 _evas_render2_stage_main_render_prepare(e);
164 // call the post render callback with info if appropriate 333 // send off rendering to primary thread renderer
165 if (e->render.updates) 334 if (do_async)
166 {
167 Evas_Event_Render_Post post;
168
169 post.updated_area = e->render.updates;
170 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
171 }
172 else
173 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL);
174 // clean out modules we don't need anymore
175 evas_module_clean();
176 // clean out updates and tmp surfaces we were holding/tracking
177 if (!make_updates)
178 { 335 {
179 Update *u; 336 // ref the canvas so it stays while threads wortk
180 337 eo_ref(eo_e);
181 EINA_LIST_FREE(e->render.updates, u) 338 // track hanvas in list of things going in the background
182 { 339 e->rendering = EINA_TRUE;
183 //evas_cache_image_drop(u->surface); 340 _rendering = eina_list_append(_rendering, eo_e);
184 free(u); 341 // queue the render thread command
185 } 342 evas_thread_cmd_enqueue(_evas_render2_th_render, e);
343 // flush the thread queue and call wakeup_send in the thread
344 evas_thread_queue_flush(_evas_render2_wakeup_send, eo_e);
186 } 345 }
346 // or if not async, do rendering inline now
347 else _evas_render2_stage_render_do(e);
187 } 348 }
349 // reset flags since rendering is processed now
350 _evas_render2_stage_reset(e);
351 // clean/delete/gc objects here
352 _evas_render2_stage_object_cleanup(e);
353 // if we are not going to be async then do last render stage here
354 if (!do_async) _evas_render2_stage_last(eo_e, make_updates);
355 if (!do_draw) _evas_render2_updates_clean(e);
188 return EINA_TRUE; 356 return EINA_TRUE;
189} 357}
190 358
@@ -197,50 +365,7 @@ _evas_render2_end(Eo *eo_e)
197 // this is actually called if rendering was async and is done. this is 365 // this is actually called if rendering was async and is done. this is
198 // run in the mainloop where rendering began and may handle any cleanup 366 // run in the mainloop where rendering began and may handle any cleanup
199 // or pixel upload if needed here 367 // or pixel upload if needed here
200 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); 368 _evas_render2_stage_last(eo_e, EINA_TRUE);
201 Eina_Bool have_updates = EINA_FALSE;
202 Update *u;
203
204 // XXX:
205 // XXX: actually update screen from mainloop here if needed - eg software
206 // engine needs to xshmputimage here
207 // XXX:
208
209 // clean out updates and tmp surfaces we were holding/tracking
210 if (e->render.updates)
211 {
212 have_updates = EINA_TRUE;
213 EINA_LIST_FREE(e->render.updates, u)
214 {
215 //evas_cache_image_drop(u->surface);
216 free(u);
217 }
218 }
219 // if we did do rendering flush output to target and call callbacks
220 if (have_updates)
221 {
222 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
223 e->engine.func->output_flush(e->engine.data.output,
224 EVAS_RENDER_MODE_ASYNC_END);
225 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
226 }
227 // clear our previous rendering stuff from the engine
228 e->engine.func->output_redraws_clear(e->engine.data.output);
229 // stop tracking canvas as being async rendered
230 _rendering = eina_list_remove(_rendering, eo_e);
231 e->rendering = EINA_FALSE;
232 // call the post render callback with info if appropriate
233 if (e->render.updates)
234 {
235 Evas_Event_Render_Post post;
236
237 post.updated_area = e->render.updates;
238 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
239 }
240 else
241 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, NULL);
242 // clean out modules we don't need anymore
243 evas_module_clean();
244 // release canvas object ref 369 // release canvas object ref
245 eo_unref(eo_e); 370 eo_unref(eo_e);
246} 371}
@@ -302,73 +427,3 @@ _evas_render2_wait(Eo *eo_e)
302 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS); 427 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
303 while (e->rendering) evas_async_events_process_blocking(); 428 while (e->rendering) evas_async_events_process_blocking();
304} 429}
305
306
307
308
309// helpers
310//////////////////////////////////////////////////////////////////////////////
311
312static void
313_evas_render2_cow_gc(Eina_Cow *cow, int max)
314{
315 // gc a single cow type up to max iter or if max <= 0, all of them
316 int i = 0;
317
318 while (eina_cow_gc(cow))
319 {
320 if (max < 1) continue;
321 i++;
322 if (i > max) break;
323 }
324}
325
326static void
327_evas_render2_cow_all_gc(int max)
328{
329 // gc all known cow types
330 _evas_render2_cow_gc(evas_object_proxy_cow, max);
331 _evas_render2_cow_gc(evas_object_map_cow, max);
332 _evas_render2_cow_gc(evas_object_image_pixels_cow, max);
333 _evas_render2_cow_gc(evas_object_image_load_opts_cow, max);
334 _evas_render2_cow_gc(evas_object_image_state_cow, max);
335}
336
337static void
338_evas_render2_all_sync(void)
339{
340 // wait for ALL canvases to stop rendering
341 Eo *eo_e;
342
343 if (!_rendering) return;
344 eo_e = eina_list_data_get(eina_list_last(_rendering));
345 _evas_render2_wait(eo_e);
346}
347
348static void
349_evas_render2_wakeup_cb(void *target, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
350{
351 // in mainloop run the rendering end handler
352 Eo *eo_e = target;
353
354 _evas_render2_end(eo_e);
355}
356
357static void
358_evas_render2_wakeup_send(void *data)
359{
360 // pass an event to the mainloop async event handler in evas so mainloop
361 // runs wakeup_cb and not in any thread
362 evas_async_events_put(data, 0, NULL, _evas_render2_wakeup_cb);
363}
364
365static void
366_evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info)
367{
368 int freeze_num = 0, i;
369
370 eo_do(eo_e, eo_event_freeze_get(&freeze_num));
371 for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_thaw());
372 evas_event_callback_call(eo_e, type, event_info);
373 for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_freeze());
374}