summaryrefslogtreecommitdiff
path: root/src/lib/evas/canvas/evas_render2.c
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2013-12-19 22:49:16 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2013-12-19 22:49:43 +0900
commiteed4526003ad63c2a0bb8b9d574cdcd35c680a06 (patch)
tree6ac9f9f84fa35d65f9d9ce4fa43f6a78945599cc /src/lib/evas/canvas/evas_render2.c
parent8937708e4363b16c8b26f9a8d7526d162ac94547 (diff)
first steps to rewriting evas render... a long path.
Diffstat (limited to '')
-rw-r--r--src/lib/evas/canvas/evas_render2.c374
1 files changed, 374 insertions, 0 deletions
diff --git a/src/lib/evas/canvas/evas_render2.c b/src/lib/evas/canvas/evas_render2.c
new file mode 100644
index 0000000000..1e56ccc803
--- /dev/null
+++ b/src/lib/evas/canvas/evas_render2.c
@@ -0,0 +1,374 @@
1#include "evas_common_private.h"
2#include "evas_private.h"
3#include <math.h>
4#include <assert.h>
5#ifdef EVAS_CSERVE2
6#include "evas_cs2_private.h"
7#endif
8
9#ifdef EVAS_RENDER_DEBUG_TIMING
10#include <sys/time.h>
11#endif
12
13//////////////////////////////////////////////////////////////////////////////
14// this is the start of a rewrite of the evas rendering infra. first port of
15// call is to just make it work and still support async rendering with no
16// optimizations at all. once it WORKS properly start adding back
17// optimizations one at a time very carefully until it is equivalent to where
18// evas render was before, THEN... we can consider switching it on by default
19// but until then it's off unless you set:
20//
21// export EVAS_RENDER2=1
22//
23// at runtime.
24//////////////////////////////////////////////////////////////////////////////
25
26// data types
27//////////////////////////////////////////////////////////////////////////////
28typedef struct Update Update;
29
30struct _Update
31{
32 Eina_Rectangle area;
33 void *surface;
34};
35
36// funcs
37//////////////////////////////////////////////////////////////////////////////
38Eina_Bool _evas_render2_begin(Eo *eo_e, Eina_Bool make_updates, Eina_Bool do_draw, Eina_Bool do_async);
39void _evas_render2_idle_flush(Eo *eo_e);
40void _evas_render2_dump(Eo *eo_e);
41void _evas_render2_wait(Eo *eo_e);
42
43static void _evas_render2_end(Eo *eo_e);
44
45static void _evas_render2_cow_gc(Eina_Cow *cow, int max);
46static void _evas_render2_cow_all_gc(int max);
47static void _evas_render2_all_sync(void);
48static void _evas_render2_wakeup_cb(void *target, Evas_Callback_Type type, void *event_info);
49static void _evas_render2_wakeup_send(void *data);
50static void _evas_render2_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info);
51
52// global data (for rendering only)
53//////////////////////////////////////////////////////////////////////////////
54static Eina_List *_rendering = NULL;
55
56//////////////////////////////////////////////////////////////////////////////
57
58///////////////////////////////////////////////////////////////////////
59// BEGIN RENDERING (in mainloop)
60///////////////////////////////////////////////////////////////////////
61Eina_Bool
62_evas_render2_begin(Eo *eo_e, Eina_Bool make_updates,
63 Eina_Bool do_draw, Eina_Bool do_async)
64{
65 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
66 Eina_Rectangle *r;
67 Eina_List *l;
68
69 // if nothing changed at all since last render - skip this frame
70 if (!e->changed) return EINA_FALSE;
71 // we are still rendering while being asked to render - skip this frame
72 if (e->rendering && do_async) return EINA_FALSE;
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
77 // call canvas callbacks saying we are in the pre-render state
78 _evas_render2_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL);
79 // we have to calculate smare objects before render so do that here
80 evas_call_smarts_calculate(eo_e);
81
82 // if the output size changed, add a full redraw
83 if ((e->output.changed) || (e->framespace.changed))
84 {
85 e->engine.func->output_resize(e->engine.data.output,
86 e->output.w, e->output.h);
87 e->engine.func->output_redraws_rect_add(e->engine.data.output, 0, 0,
88 e->output.w, e->output.h);
89 }
90 // if there are explicit update regions - add them
91 EINA_LIST_FREE(e->damages, r)
92 {
93 // if we didnt just do a full redraw if output changed
94 if ((!e->output.changed) && (!e->framespace.changed))
95 e->engine.func->output_redraws_rect_add(e->engine.data.output,
96 r->x, r->y, r->w, r->h);
97 eina_rectangle_free(r);
98 }
99 // remove obscures from rendering - we keep them around
100 EINA_LIST_FOREACH(e->obscures, l, r)
101 e->engine.func->output_redraws_rect_del(e->engine.data.output,
102 r->x, r->y, r->w, r->h);
103
104 // we are actually asked to draw not just go through the motions for gc
105 if (do_draw)
106 {
107 // XXX:
108 // XXX: process all objects figuring out update regions
109 // XXX:
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
123 // if we are async...
124 if (do_async)
125 {
126 // ref the canvas so it stays while threads wortk
127 eo_ref(eo_e);
128 // track hanvas in list of things going in the background
129 e->rendering = EINA_TRUE;
130 _rendering = eina_list_append(_rendering, eo_e);
131 // flush the thread queue
132 evas_thread_queue_flush
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
148 // reset flags sinc rendering is processed now
149 e->changed = EINA_FALSE;
150 e->viewport.changed = EINA_FALSE;
151 e->output.changed = EINA_FALSE;
152 e->framespace.changed = EINA_FALSE;
153 e->invalidate = EINA_FALSE;
154
155 // XXX:
156 // XXX: delete objects no longer needed here
157 // XXX:
158
159 // if we are not going to be async then do post render here
160 if (!do_async)
161 {
162 // clear our previous rendering stuff from the engine
163 e->engine.func->output_redraws_clear(e->engine.data.output);
164 // call the post render callback with info if appropriate
165 if (e->render.updates)
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 {
179 Update *u;
180
181 EINA_LIST_FREE(e->render.updates, u)
182 {
183 //evas_cache_image_drop(u->surface);
184 free(u);
185 }
186 }
187 }
188 return EINA_TRUE;
189}
190
191///////////////////////////////////////////////////////////////////////
192// END RENDERING (in mainloop)
193///////////////////////////////////////////////////////////////////////
194static void
195_evas_render2_end(Eo *eo_e)
196{
197 // 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
199 // or pixel upload if needed here
200 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
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
245 eo_unref(eo_e);
246}
247
248///////////////////////////////////////////////////////////////////////
249// IDLE FLUSH (in mainloop)
250///////////////////////////////////////////////////////////////////////
251void
252_evas_render2_idle_flush(Eo *eo_e)
253{
254 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
255
256 // wait for rendering to finish so we don't mess up shared resources
257 _evas_render2_wait(eo_e);
258 // clean fonts
259 evas_fonts_zero_pressure(eo_e);
260 // call engine idle flush call
261 if ((e->engine.func) && (e->engine.func->output_idle_flush) &&
262 (e->engine.data.output))
263 e->engine.func->output_idle_flush(e->engine.data.output);
264 // mark as invalidated
265 e->invalidate = EINA_TRUE;
266 // garbage collect up to 500 cow segments from our cow types
267 // not e that we should probably expose a call to do this outside of evas
268 // so ecore evas can call it in an idler
269 _evas_render2_cow_all_gc(500);
270}
271
272///////////////////////////////////////////////////////////////////////
273// DUMP DATA (in mainloop)
274///////////////////////////////////////////////////////////////////////
275void
276_evas_render2_dump(Eo *eo_e)
277{
278 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
279
280 // freeze core cache system async work
281 evas_cache_async_freeze();
282 // wait for all canvases to render as they may share data we are dumping
283 _evas_render2_all_sync();
284 // go through idle flush first
285 _evas_render2_idle_flush(eo_e);
286 // also now tell engine to dump too
287 if ((e->engine.func) && (e->engine.func->output_dump) &&
288 (e->engine.data.output))
289 e->engine.func->output_dump(e->engine.data.output);
290 // clean up all cow sections no matter how many
291 _evas_render2_cow_all_gc(0);
292 // unfreeze core cache system
293 evas_cache_async_thaw();
294}
295
296///////////////////////////////////////////////////////////////////////
297// WAIT ON CANVAS RENDER (if async, in mainloop)
298///////////////////////////////////////////////////////////////////////
299void
300_evas_render2_wait(Eo *eo_e)
301{
302 Evas_Public_Data *e = eo_data_scope_get(eo_e, EVAS_CLASS);
303 while (e->rendering) evas_async_events_process_blocking();
304}
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}