diff options
author | David Walter Seikel | 2013-01-13 17:29:19 +1000 |
---|---|---|
committer | David Walter Seikel | 2013-01-13 17:29:19 +1000 |
commit | 07274513e984f0b5544586c74508ccd16e7dcafa (patch) | |
tree | b32ff2a9136fbc1a4a6a0ed1e4d79cde0f5f16d9 /libraries/evas/src/lib/engines/common/evas_pipe.c | |
parent | Added Irrlicht 1.8, but without all the Windows binaries. (diff) | |
download | SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.zip SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.gz SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.bz2 SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.xz |
Remove EFL, since it's been released now.
Diffstat (limited to 'libraries/evas/src/lib/engines/common/evas_pipe.c')
-rw-r--r-- | libraries/evas/src/lib/engines/common/evas_pipe.c | 1733 |
1 files changed, 0 insertions, 1733 deletions
diff --git a/libraries/evas/src/lib/engines/common/evas_pipe.c b/libraries/evas/src/lib/engines/common/evas_pipe.c deleted file mode 100644 index 66085c8..0000000 --- a/libraries/evas/src/lib/engines/common/evas_pipe.c +++ /dev/null | |||
@@ -1,1733 +0,0 @@ | |||
1 | // THIS IS DEPRECATED. WILL GO EVENTUALLTY. NO NEED TO SUPPORT ANYMORE | ||
2 | |||
3 | #include "evas_common.h" | ||
4 | #include <unistd.h> | ||
5 | |||
6 | #ifdef BUILD_PIPE_RENDER | ||
7 | |||
8 | #ifdef EVAS_FRAME_QUEUING | ||
9 | #define SCALECACHE | ||
10 | static Evas_FrameQ gframeq; // global frameQ | ||
11 | |||
12 | static Evas_Surface * | ||
13 | evas_common_surface_alloc(void *surface, int x, int y, int w, int h) | ||
14 | { | ||
15 | Evas_Surface *e_surface; | ||
16 | |||
17 | e_surface = calloc(1, sizeof(Evas_Surface)); | ||
18 | e_surface->im = surface; | ||
19 | LKL(e_surface->im->cache_entry.ref_fq_add); | ||
20 | e_surface->im->cache_entry.ref_fq[0]++; | ||
21 | LKU(e_surface->im->cache_entry.ref_fq_add); | ||
22 | e_surface->x = x; | ||
23 | e_surface->y = y; | ||
24 | e_surface->w = w; | ||
25 | e_surface->h = h; | ||
26 | |||
27 | return e_surface; | ||
28 | } | ||
29 | |||
30 | static void | ||
31 | evas_common_surface_dealloc(Evas_Surface *surface) | ||
32 | { | ||
33 | Evas_Surface *d_surface; | ||
34 | |||
35 | while (surface) | ||
36 | { | ||
37 | d_surface = surface; | ||
38 | surface = (Evas_Surface *)eina_inlist_remove(EINA_INLIST_GET(surface), EINA_INLIST_GET(d_surface)); | ||
39 | LKL(d_surface->im->cache_entry.ref_fq_del); | ||
40 | d_surface->im->cache_entry.ref_fq[1]++; | ||
41 | LKU(d_surface->im->cache_entry.ref_fq_del); | ||
42 | free(d_surface); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | static void | ||
47 | evas_common_surface_add(Evas_Frame *frame, Evas_Surface *surface) | ||
48 | { | ||
49 | frame->surfaces = (Evas_Surface *)eina_inlist_append(EINA_INLIST_GET(frame->surfaces), EINA_INLIST_GET(surface)); | ||
50 | } | ||
51 | |||
52 | static Evas_Frame * | ||
53 | evas_common_frame_alloc(void) | ||
54 | { | ||
55 | Evas_Frame *frame; | ||
56 | |||
57 | frame = calloc(1, sizeof(Evas_Frame)); | ||
58 | frame->surfaces = NULL; | ||
59 | return frame; | ||
60 | } | ||
61 | |||
62 | static void | ||
63 | evas_common_frame_dealloc(Evas_Frame *frame) | ||
64 | { | ||
65 | evas_common_surface_dealloc(frame->surfaces); | ||
66 | free(frame); | ||
67 | } | ||
68 | |||
69 | static void | ||
70 | evas_common_frame_add(Evas_FrameQ *frameq, Evas_Frame *frame) | ||
71 | { | ||
72 | Evas_Frame *temp_frame; | ||
73 | |||
74 | LKL(frameq->mutex); | ||
75 | while ((int)eina_inlist_count(EINA_INLIST_GET(frameq->frames)) >= frameq->frameq_sz) | ||
76 | { | ||
77 | /* wait a worker thread finish previous frame */ | ||
78 | eina_condition_wait(&(frameq->cond_done)); | ||
79 | } | ||
80 | frameq->frames = (Evas_Frame *) eina_inlist_append(EINA_INLIST_GET(frameq->frames), EINA_INLIST_GET(frame)); | ||
81 | |||
82 | // this frame need not to be scheduled for flushing time | ||
83 | EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), temp_frame) | ||
84 | { | ||
85 | if (!temp_frame->ready) | ||
86 | { | ||
87 | break; | ||
88 | } | ||
89 | } | ||
90 | if (temp_frame && temp_frame == frame) | ||
91 | frame->dont_schedule = 1; | ||
92 | |||
93 | LKU(frameq->mutex); | ||
94 | |||
95 | eina_condition_signal(&(frameq->cond_new)); | ||
96 | } | ||
97 | |||
98 | EAPI Evas_Surface * | ||
99 | evas_common_frameq_new_surface(void *surface, int x, int y, int w, int h) | ||
100 | { | ||
101 | return evas_common_surface_alloc(surface, x, y, w, h); | ||
102 | } | ||
103 | |||
104 | EAPI void | ||
105 | evas_common_frameq_add_surface(Evas_Surface *surface) | ||
106 | { | ||
107 | evas_common_surface_add(gframeq.cur_frame, surface); | ||
108 | } | ||
109 | |||
110 | EAPI void | ||
111 | evas_common_frameq_set_frame_data(void *data, | ||
112 | void (*fn_output_redraws_next_update_push) (void *data, void *surface, int x, int y, int w, int h), | ||
113 | void (*fn_output_flush) (void *data), | ||
114 | void (*fn_output_set_priv)(void *data, void *cur, void *prev)) | ||
115 | { | ||
116 | if (gframeq.cur_frame) | ||
117 | { | ||
118 | gframeq.cur_frame->data = data; | ||
119 | gframeq.cur_frame->output_redraws_next_update_push = fn_output_redraws_next_update_push; | ||
120 | gframeq.cur_frame->output_flush = fn_output_flush; | ||
121 | gframeq.cur_frame->output_set_priv = fn_output_set_priv; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | EAPI void | ||
126 | evas_common_frameq_prepare_frame(void) | ||
127 | { | ||
128 | if (!gframeq.cur_frame ) | ||
129 | { | ||
130 | gframeq.cur_frame = evas_common_frame_alloc(); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | EAPI void | ||
135 | evas_common_frameq_ready_frame(void) | ||
136 | { | ||
137 | if (gframeq.cur_frame) | ||
138 | { | ||
139 | evas_common_frame_add(&gframeq, gframeq.cur_frame); | ||
140 | gframeq.cur_frame = NULL; // create a new frame for the next frame later | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | EAPI void | ||
146 | evas_common_frameq_init(void) | ||
147 | { | ||
148 | gframeq.frames = NULL; | ||
149 | LKI(gframeq.mutex); | ||
150 | eina_condition_new(&(gframeq.cond_new), &(gframeq.mutex)); | ||
151 | eina_condition_new(&(gframeq.cond_ready), &(gframeq.mutex)); | ||
152 | eina_condition_new(&(gframeq.cond_done), &(gframeq.mutex)); | ||
153 | gframeq.initialised = 0; // worker thread are not created yet | ||
154 | gframeq.frameq_sz = 1; // this value ensures the first frame can be enqueued. | ||
155 | } | ||
156 | |||
157 | EAPI void | ||
158 | evas_common_frameq_destroy(void) | ||
159 | { | ||
160 | #if 0 // let them destroyed indirectly with program exit | ||
161 | LKL(gframeq.mutex); | ||
162 | eina_condition_free(&(gframeq.cond_new)); | ||
163 | eina_condition_free(&(gframeq.cond_ready)); | ||
164 | eina_condition_free(&(gframeq.cond_done)); | ||
165 | LKU(gframeq.mutex); | ||
166 | #endif | ||
167 | LKD(gframeq.mutex); | ||
168 | |||
169 | gframeq.frames = NULL; | ||
170 | gframeq.initialised = 0; | ||
171 | } | ||
172 | |||
173 | EAPI void | ||
174 | evas_common_frameq_flush(void) | ||
175 | { | ||
176 | if (! evas_common_frameq_enabled()) | ||
177 | return; | ||
178 | |||
179 | LKL(gframeq.mutex); | ||
180 | while(eina_inlist_count(EINA_INLIST_GET(gframeq.frames)) > 0) | ||
181 | { | ||
182 | /* wait a worker thread finish previous frame */ | ||
183 | eina_condition_wait(&(gframeq.cond_done)); | ||
184 | } | ||
185 | LKU(gframeq.mutex); | ||
186 | } | ||
187 | |||
188 | |||
189 | EAPI void | ||
190 | evas_common_frameq_flush_ready(void) | ||
191 | { | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | EAPI int | ||
196 | evas_common_frameq_get_frameq_sz(void) | ||
197 | { | ||
198 | return gframeq.frameq_sz; | ||
199 | } | ||
200 | |||
201 | EAPI int | ||
202 | evas_common_frameq_enabled(void) | ||
203 | { | ||
204 | return gframeq.initialised; | ||
205 | } | ||
206 | #endif | ||
207 | |||
208 | static RGBA_Pipe *evas_common_pipe_add(RGBA_Pipe *pipe, RGBA_Pipe_Op **op); | ||
209 | static void evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op); | ||
210 | static void evas_common_pipe_op_free(RGBA_Pipe_Op *op); | ||
211 | |||
212 | /* utils */ | ||
213 | static RGBA_Pipe * | ||
214 | evas_common_pipe_add(RGBA_Pipe *rpipe, RGBA_Pipe_Op **op) | ||
215 | { | ||
216 | RGBA_Pipe *p; | ||
217 | int first_pipe = 0; | ||
218 | |||
219 | if (!rpipe) | ||
220 | { | ||
221 | first_pipe = 1; | ||
222 | p = calloc(1, sizeof(RGBA_Pipe)); | ||
223 | if (!p) return NULL; | ||
224 | rpipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(rpipe), EINA_INLIST_GET(p)); | ||
225 | } | ||
226 | p = (RGBA_Pipe *)(EINA_INLIST_GET(rpipe))->last; | ||
227 | if (p->op_num == PIPE_LEN) | ||
228 | { | ||
229 | p = calloc(1, sizeof(RGBA_Pipe)); | ||
230 | if (!p) return NULL; | ||
231 | rpipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(rpipe), EINA_INLIST_GET(p)); | ||
232 | } | ||
233 | p->op_num++; | ||
234 | *op = &(p->op[p->op_num - 1]); | ||
235 | if (first_pipe) | ||
236 | { | ||
237 | /* FIXME: PTHREAD init any thread locks etc */ | ||
238 | } | ||
239 | return rpipe; | ||
240 | } | ||
241 | |||
242 | static void | ||
243 | evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op) | ||
244 | { | ||
245 | memcpy(&(op->context), dc, sizeof(RGBA_Draw_Context)); | ||
246 | if (op->context.cutout.active > 0) | ||
247 | { | ||
248 | op->context.cutout.rects = malloc(sizeof(Cutout_Rect) * op->context.cutout.active); | ||
249 | memcpy(op->context.cutout.rects, dc->cutout.rects, sizeof(Cutout_Rect) * op->context.cutout.active); | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | op->context.cutout.rects = NULL; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | static void | ||
258 | evas_common_pipe_op_free(RGBA_Pipe_Op *op) | ||
259 | { | ||
260 | evas_common_draw_context_apply_clean_cutouts(&op->context.cutout); | ||
261 | } | ||
262 | |||
263 | #ifdef BUILD_PTHREAD | ||
264 | /* main api calls */ | ||
265 | static void * | ||
266 | evas_common_pipe_thread(void *data) | ||
267 | { | ||
268 | Thinfo *thinfo; | ||
269 | |||
270 | // INF("TH [..........."); | ||
271 | thinfo = data; | ||
272 | for (;;) | ||
273 | { | ||
274 | RGBA_Pipe_Thread_Info *info; | ||
275 | RGBA_Pipe *p; | ||
276 | |||
277 | /* wait for start signal */ | ||
278 | // INF(" TH %i START...", thinfo->thread_num); | ||
279 | pthread_barrier_wait(&(thinfo->barrier[0])); | ||
280 | info = thinfo->info; | ||
281 | // if (info) | ||
282 | // { | ||
283 | // thinfo->info = NULL; | ||
284 | // INF(" TH %i GO", thinfo->thread_num); | ||
285 | EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->cache_entry.pipe), p) | ||
286 | { | ||
287 | int i; | ||
288 | |||
289 | for (i = 0; i < p->op_num; i++) | ||
290 | { | ||
291 | if (p->op[i].op_func) | ||
292 | p->op[i].op_func(info->im, &(p->op[i]), info); | ||
293 | } | ||
294 | } | ||
295 | free(info); | ||
296 | // } | ||
297 | // INF(" TH %i DONE", thinfo->thread_num); | ||
298 | /* send finished signal */ | ||
299 | pthread_barrier_wait(&(thinfo->barrier[1])); | ||
300 | } | ||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | #ifdef EVAS_FRAME_QUEUING | ||
305 | static void | ||
306 | evas_common_frameq_release(void *data) | ||
307 | { | ||
308 | Evas_FrameQ *frameq; | ||
309 | Evas_Frameq_Thread_Info *fq_info; | ||
310 | Thinfo *thinfo; | ||
311 | |||
312 | thinfo = data; | ||
313 | fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info); | ||
314 | frameq = fq_info->frameq; | ||
315 | |||
316 | /* This thread may or may not own the mutex. | ||
317 | * But there's no way to determine the ownership of the mutex, so release it anyway | ||
318 | */ | ||
319 | LKU(frameq->mutex); | ||
320 | } | ||
321 | |||
322 | static void * | ||
323 | evas_common_frameq_thread(void *data) | ||
324 | { | ||
325 | Evas_FrameQ *frameq; | ||
326 | Evas_Frame *frame; | ||
327 | Evas_Surface *surface; | ||
328 | RGBA_Pipe *p; | ||
329 | Thinfo *thinfo; | ||
330 | Evas_Frameq_Thread_Info *fq_info; | ||
331 | RGBA_Pipe_Thread_Info p_info; | ||
332 | |||
333 | thinfo = data; | ||
334 | fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info); | ||
335 | frameq = fq_info->frameq; | ||
336 | |||
337 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | ||
338 | pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | ||
339 | /* install thread cancelation cleanup handler */ | ||
340 | pthread_cleanup_push(evas_common_frameq_release, data); | ||
341 | |||
342 | for (;;) | ||
343 | { | ||
344 | frame = NULL; | ||
345 | |||
346 | /* 1. pick a frame to draw */ | ||
347 | LKL(frameq->mutex); | ||
348 | while(!frame) | ||
349 | { | ||
350 | EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), frame) | ||
351 | { | ||
352 | if (!frame->in_process) | ||
353 | { | ||
354 | frame->in_process = 1; | ||
355 | break; | ||
356 | } | ||
357 | } | ||
358 | if (frame) | ||
359 | { | ||
360 | break; | ||
361 | } | ||
362 | pthread_testcancel(); | ||
363 | eina_condition_wait(&(frameq->cond_new)); | ||
364 | } | ||
365 | LKU(frameq->mutex); | ||
366 | |||
367 | /* 2. draw selected frame */ | ||
368 | EINA_INLIST_FOREACH(EINA_INLIST_GET(frame->surfaces), surface) | ||
369 | { | ||
370 | p_info.im = surface->im; | ||
371 | p_info.x = 0; | ||
372 | p_info.y = 0; | ||
373 | p_info.w = surface->im->cache_entry.w; | ||
374 | p_info.h = surface->im->cache_entry.h; | ||
375 | |||
376 | EINA_INLIST_FOREACH(EINA_INLIST_GET(p_info.im->cache_entry.pipe), p) | ||
377 | { | ||
378 | int i; | ||
379 | |||
380 | for (i = 0; i < p->op_num; i++) | ||
381 | { | ||
382 | if (p->op[i].op_func) | ||
383 | { | ||
384 | p->op[i].op_func(p_info.im, &(p->op[i]), &p_info); | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /* push surface out */ | ||
390 | if (! surface->dontpush) | ||
391 | { | ||
392 | frame->output_redraws_next_update_push(frame->data, | ||
393 | surface->im, surface->x, surface->y, surface->w, surface->h); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | // record frame ready time, will be used in post worker thread, evas_common_frameq_thread_post() | ||
398 | gettimeofday(&frame->ready_time, NULL); | ||
399 | |||
400 | LKL(frameq->mutex); | ||
401 | frame->ready = 1; | ||
402 | eina_condition_signal(&(frameq->cond_ready)); | ||
403 | LKU(frameq->mutex); | ||
404 | } | ||
405 | |||
406 | // Remove cleanup handler | ||
407 | pthread_cleanup_pop(0); | ||
408 | return NULL; | ||
409 | } | ||
410 | |||
411 | |||
412 | #define INTERVAL_QSIZE 17 // Actual size is 'INTERVAL_QSIZE - 1' because of not using index | ||
413 | #define SATISFACTION_THRESHOLD 4 // 4 ms --> 250 FPS | ||
414 | #define RESET_RATIO 4 // RESET_RATIO * [Average Ready Gap | get_max_interval()] --> Reset Threshold | ||
415 | #define DOUBLE_RESET_TIME_INTERVAL_THRESHOLD 16000 // make it double in case of less 16ms | ||
416 | #define RESET_ABSOLUTE_INTERVAL 600000 // 600 msec | ||
417 | |||
418 | struct iq_node | ||
419 | { | ||
420 | long long rt; | ||
421 | long long ri; | ||
422 | }; | ||
423 | |||
424 | static struct iq_node _IQ[INTERVAL_QSIZE]; | ||
425 | static int _IQ_head = 0, _IQ_tail = 0; | ||
426 | static int _IQ_length = 0; | ||
427 | static long long min_ready, max_ready; | ||
428 | static long long average_interval; | ||
429 | |||
430 | static int | ||
431 | _IQ_next_index(int i) | ||
432 | { | ||
433 | return (i + 1) % INTERVAL_QSIZE; | ||
434 | } | ||
435 | |||
436 | static int | ||
437 | _IQ_previous_index(int i) | ||
438 | { | ||
439 | if (--i < 0) i += INTERVAL_QSIZE; | ||
440 | return i; | ||
441 | } | ||
442 | |||
443 | static void | ||
444 | _IQ_init(void) | ||
445 | { | ||
446 | _IQ_length = _IQ_head = _IQ_tail = 0; | ||
447 | min_ready = LLONG_MAX, max_ready = LLONG_MIN; | ||
448 | average_interval = 0; | ||
449 | } | ||
450 | |||
451 | static int | ||
452 | _IQ_empty(void) | ||
453 | { | ||
454 | return (_IQ_head == _IQ_tail) ? 1 : 0; | ||
455 | } | ||
456 | |||
457 | static int | ||
458 | _IQ_full(void) | ||
459 | { | ||
460 | return (_IQ_head == ((_IQ_tail + 1) % INTERVAL_QSIZE)) ? 1 : 0; | ||
461 | } | ||
462 | |||
463 | static void | ||
464 | _IQ_insert(long long ready_time, long long last_interval) | ||
465 | { | ||
466 | if (_IQ_full()) return; | ||
467 | |||
468 | if (_IQ_empty()) | ||
469 | { | ||
470 | if (last_interval < 0) | ||
471 | { | ||
472 | last_interval = -last_interval; | ||
473 | } | ||
474 | _IQ[_IQ_tail].rt = ready_time; | ||
475 | _IQ[_IQ_tail].ri = last_interval; | ||
476 | min_ready = ready_time - last_interval; | ||
477 | max_ready = ready_time; | ||
478 | _IQ_tail = _IQ_next_index(_IQ_tail); | ||
479 | _IQ_length++; | ||
480 | } | ||
481 | else | ||
482 | { | ||
483 | if (max_ready < ready_time) | ||
484 | { | ||
485 | _IQ[_IQ_tail].rt = ready_time; | ||
486 | _IQ[_IQ_tail].ri = ready_time - max_ready; | ||
487 | _IQ_tail = _IQ_next_index(_IQ_tail); | ||
488 | _IQ_length++; | ||
489 | max_ready = ready_time; | ||
490 | } | ||
491 | else if (ready_time < min_ready) | ||
492 | { | ||
493 | last_interval = _IQ[_IQ_head].ri; | ||
494 | _IQ[_IQ_head].ri = _IQ[_IQ_head].rt - ready_time; | ||
495 | _IQ_head = _IQ_previous_index(_IQ_head); | ||
496 | _IQ[_IQ_head].rt = ready_time; | ||
497 | _IQ[_IQ_head].ri = last_interval; | ||
498 | min_ready = ready_time; | ||
499 | _IQ_length++; | ||
500 | } | ||
501 | else | ||
502 | { | ||
503 | int i, j, k, l = 0; | ||
504 | for (i = _IQ_head; i != _IQ_tail; i = j) | ||
505 | { | ||
506 | j = _IQ_next_index(i); | ||
507 | if (_IQ[j].rt < ready_time) | ||
508 | { | ||
509 | continue; | ||
510 | } | ||
511 | break; | ||
512 | } | ||
513 | for (k = _IQ_tail; k != j; k = l) | ||
514 | { | ||
515 | l = _IQ_previous_index(k); | ||
516 | _IQ[k] = _IQ[l]; | ||
517 | } | ||
518 | i = _IQ_next_index(j); | ||
519 | _IQ[j].ri -= (_IQ[j].rt - ready_time); | ||
520 | _IQ[j].rt = ready_time; | ||
521 | _IQ[i].ri = _IQ[i].rt - ready_time; | ||
522 | _IQ_tail = _IQ_next_index(_IQ_tail); | ||
523 | _IQ_length++; | ||
524 | } | ||
525 | } | ||
526 | average_interval = (max_ready - min_ready) / _IQ_length; | ||
527 | } | ||
528 | |||
529 | static long long | ||
530 | _IQ_delete(void) | ||
531 | { | ||
532 | struct iq_node oldest; | ||
533 | |||
534 | if (_IQ_empty()) return 0; | ||
535 | oldest = _IQ[_IQ_head]; | ||
536 | _IQ_head = (_IQ_head + 1) % INTERVAL_QSIZE; | ||
537 | if ((--_IQ_length) == 0) | ||
538 | { | ||
539 | _IQ_init(); | ||
540 | } | ||
541 | else | ||
542 | { | ||
543 | min_ready = _IQ[_IQ_head].rt; | ||
544 | average_interval = (max_ready - min_ready) / _IQ_length; | ||
545 | } | ||
546 | |||
547 | return oldest.ri; | ||
548 | } | ||
549 | |||
550 | static long long | ||
551 | get_max_interval(void) | ||
552 | { | ||
553 | int i; | ||
554 | long long max = LLONG_MIN; | ||
555 | |||
556 | for ( i= _IQ_head ; i != _IQ_tail ; i = _IQ_next_index(i)) | ||
557 | { | ||
558 | if (_IQ[i].ri > max) | ||
559 | { | ||
560 | max = _IQ[i].ri; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | return max; | ||
565 | } | ||
566 | |||
567 | static long long | ||
568 | tv_to_long_long(struct timeval *tv) | ||
569 | { | ||
570 | if (!tv) | ||
571 | { | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | return tv->tv_sec * 1000000LL + tv->tv_usec; | ||
576 | } | ||
577 | |||
578 | static long long | ||
579 | evas_common_frameq_schedule_flush_time(int frameq_sz, int thread_no, | ||
580 | long long last_ready_time, long long current_ready_time, | ||
581 | long long last_flush_time, int ready_frames_num, | ||
582 | int dont_schedule) | ||
583 | { | ||
584 | // to get each time and to do others | ||
585 | long long current_time = 0LL; | ||
586 | long long current_ready_interval = 0LL; | ||
587 | long long theshold_time = SATISFACTION_THRESHOLD * 1000LL; // ms -> usec | ||
588 | long long reset_time_interval = 0LL; | ||
589 | long long sleep_time = 0LL; | ||
590 | long long saved_ready_time, saved_ready_interval; | ||
591 | long long time_slept = 0LL; | ||
592 | static long long time_lag = 0; | ||
593 | struct timeval now; | ||
594 | int frameq_full_threshold =0; | ||
595 | int need_reset = 0; | ||
596 | int need_schedule = 0; | ||
597 | |||
598 | frameq_full_threshold = frameq_sz -thread_no; // Qsize - threads# | ||
599 | |||
600 | /* 1.5 defer flush time of current frame if need */ | ||
601 | // in case of the first time, just keep ready time only | ||
602 | if (last_ready_time == 0LL) | ||
603 | { | ||
604 | last_ready_time = current_ready_time; | ||
605 | } | ||
606 | else | ||
607 | { | ||
608 | /* 1.5.1 get current ready time & interval */ | ||
609 | saved_ready_time = current_ready_time; | ||
610 | saved_ready_interval = current_ready_interval = current_ready_time - last_ready_time; | ||
611 | // compensate a case which current ready time is older than previous one, | ||
612 | // doesn't work on the interval queue | ||
613 | if (current_ready_interval < 0) | ||
614 | { | ||
615 | current_ready_time = last_ready_time; | ||
616 | current_ready_interval = 0; | ||
617 | } | ||
618 | |||
619 | /* 1.5.2 get the reset time interval before keeping a new one */ | ||
620 | if (!_IQ_empty()) | ||
621 | { | ||
622 | reset_time_interval = RESET_RATIO * average_interval; | ||
623 | if (average_interval < DOUBLE_RESET_TIME_INTERVAL_THRESHOLD) | ||
624 | { | ||
625 | reset_time_interval *= 2; | ||
626 | } | ||
627 | } | ||
628 | |||
629 | /* 1.5.3 reset - if too late, discard all saved interval and start from here */ | ||
630 | if (current_ready_interval > RESET_ABSOLUTE_INTERVAL) | ||
631 | { | ||
632 | need_reset = 1; | ||
633 | } | ||
634 | else if (_IQ_length >= thread_no * 2 && current_ready_interval > reset_time_interval) | ||
635 | { | ||
636 | need_reset = 1; | ||
637 | } | ||
638 | else if (_IQ_length >= thread_no && _IQ_length < thread_no * 2 | ||
639 | && current_ready_interval > get_max_interval() * RESET_RATIO) | ||
640 | { | ||
641 | need_reset = 1; | ||
642 | } | ||
643 | |||
644 | if (need_reset) | ||
645 | { | ||
646 | _IQ_init(); | ||
647 | } | ||
648 | else | ||
649 | { | ||
650 | /* 1.5.4 enqueue - keep a new interval for next average interval */ | ||
651 | if (_IQ_full()) | ||
652 | { | ||
653 | _IQ_delete(); | ||
654 | } | ||
655 | _IQ_insert(saved_ready_time, saved_ready_interval); | ||
656 | |||
657 | /* 1.5.5 schedule - if faster than average interval, figure out sleep time to meet it */ | ||
658 | if (!dont_schedule) | ||
659 | { | ||
660 | need_schedule = 0; | ||
661 | sleep_time = 0; | ||
662 | if (_IQ_length >= thread_no * 2 && average_interval > theshold_time) | ||
663 | { | ||
664 | need_schedule = 1; | ||
665 | } | ||
666 | // compensate the case that postworker blocks the workers from getting a new fresh frame | ||
667 | // It's actually occurred when during the wait time of postworker, the frame queue is full | ||
668 | // Consequently check the number of currently ready frames and apply some time drop to average time according to the number | ||
669 | if (ready_frames_num >= frameq_full_threshold) | ||
670 | { | ||
671 | need_schedule = 0; | ||
672 | } | ||
673 | if (need_schedule) | ||
674 | { | ||
675 | gettimeofday(&now, NULL); | ||
676 | current_time = tv_to_long_long(&now); | ||
677 | time_lag += (current_time - last_flush_time); | ||
678 | sleep_time = (average_interval < time_lag) ? 0 : (average_interval - time_lag); | ||
679 | } | ||
680 | } | ||
681 | |||
682 | /* 1.5.6 sleep - actually sleep and get over-slept time (time_lag) for next frame */ | ||
683 | if (sleep_time > 0) | ||
684 | { | ||
685 | sleep_time = sleep_time * 9 / 10; | ||
686 | usleep((unsigned int)sleep_time); | ||
687 | gettimeofday(&now, NULL); | ||
688 | time_slept = tv_to_long_long(&now) - current_time; | ||
689 | time_lag = time_slept - sleep_time; | ||
690 | } | ||
691 | else | ||
692 | { | ||
693 | time_lag = 0; | ||
694 | } | ||
695 | } | ||
696 | last_ready_time = current_ready_time; | ||
697 | } | ||
698 | |||
699 | return last_ready_time; | ||
700 | } | ||
701 | |||
702 | static void * | ||
703 | evas_common_frameq_thread_post(void *data) | ||
704 | { | ||
705 | Evas_FrameQ *frameq; | ||
706 | Evas_Frame *frame; | ||
707 | Evas_Surface *surface; | ||
708 | Thinfo *thinfo; | ||
709 | Evas_Frameq_Thread_Info *fq_info; | ||
710 | Eina_List *pending_writes = NULL; | ||
711 | Eina_List *prev_pending_writes = NULL; | ||
712 | |||
713 | long long last_ready_time = 0LL; | ||
714 | long long current_ready_time; | ||
715 | Evas_Frame *temp_frame = NULL; | ||
716 | int ready_frames_num; | ||
717 | long long last_flush_time = 0LL; | ||
718 | struct timeval now; | ||
719 | int dont_schedule = 0; | ||
720 | |||
721 | thinfo = data; | ||
722 | fq_info = (Evas_Frameq_Thread_Info *)(thinfo->fq_info); | ||
723 | frameq = fq_info->frameq; | ||
724 | |||
725 | pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | ||
726 | pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); | ||
727 | /* install thread cancelation cleanup handler */ | ||
728 | pthread_cleanup_push(evas_common_frameq_release, data); | ||
729 | |||
730 | _IQ_init(); | ||
731 | |||
732 | for (;;) | ||
733 | { | ||
734 | /* 1. wait the first frame being done */ | ||
735 | LKL(frameq->mutex); | ||
736 | while(!frameq->frames || !frameq->frames->ready) | ||
737 | { | ||
738 | eina_condition_wait(&(frameq->cond_ready)); | ||
739 | } | ||
740 | frame = frameq->frames; | ||
741 | |||
742 | /* 1.5. prepare to schedule flush time */ | ||
743 | current_ready_time = tv_to_long_long(&frame->ready_time); | ||
744 | ready_frames_num = 0; | ||
745 | EINA_INLIST_FOREACH(EINA_INLIST_GET(frameq->frames), temp_frame) | ||
746 | { | ||
747 | if (temp_frame->ready == 1) | ||
748 | { | ||
749 | ready_frames_num++; | ||
750 | } | ||
751 | } | ||
752 | dont_schedule = (frame->dont_schedule)?1:0; | ||
753 | LKU(frameq->mutex); | ||
754 | |||
755 | /* 2. generate pending_writes */ | ||
756 | EINA_INLIST_FOREACH(EINA_INLIST_GET(frame->surfaces), surface) | ||
757 | { | ||
758 | evas_common_pipe_flush(surface->im); | ||
759 | if (! surface->dontpush) | ||
760 | { | ||
761 | pending_writes = eina_list_append(pending_writes, surface->im); | ||
762 | } | ||
763 | } | ||
764 | |||
765 | /* 2.5. schedule flush time */ | ||
766 | last_ready_time = evas_common_frameq_schedule_flush_time( | ||
767 | frameq->frameq_sz, frameq->thread_num, | ||
768 | last_ready_time, current_ready_time, | ||
769 | last_flush_time, ready_frames_num, dont_schedule); | ||
770 | |||
771 | /* 3. flush redraws */ | ||
772 | frame->output_set_priv(frame->data, pending_writes, prev_pending_writes); | ||
773 | frame->output_flush(frame->data); | ||
774 | gettimeofday(&now, NULL); | ||
775 | // keep as the last flush time | ||
776 | last_flush_time = now.tv_sec * 1000000LL + now.tv_usec; | ||
777 | |||
778 | prev_pending_writes = pending_writes; | ||
779 | pending_writes = NULL; | ||
780 | |||
781 | /* 4. remove this frame from the frame queue */ | ||
782 | LKL(frameq->mutex); | ||
783 | frameq->frames = | ||
784 | (Evas_Frame *)eina_inlist_remove(EINA_INLIST_GET(frameq->frames), | ||
785 | EINA_INLIST_GET(frame)); | ||
786 | |||
787 | LKU(frameq->mutex); | ||
788 | eina_condition_broadcast(&frameq->cond_done); | ||
789 | evas_common_frame_dealloc(frame); | ||
790 | } | ||
791 | |||
792 | // Remove cleanup handler | ||
793 | pthread_cleanup_pop(0); | ||
794 | return NULL; | ||
795 | } | ||
796 | |||
797 | #endif /* EVAS_FRAME_QUEUING */ | ||
798 | #endif | ||
799 | |||
800 | #ifdef BUILD_PTHREAD | ||
801 | static int thread_num = 0; | ||
802 | static Thinfo thinfo[TH_MAX]; | ||
803 | static pthread_barrier_t thbarrier[2]; | ||
804 | #endif | ||
805 | |||
806 | static void | ||
807 | evas_common_pipe_begin(RGBA_Image *im) | ||
808 | { | ||
809 | #ifdef BUILD_PTHREAD | ||
810 | int i, y, h; | ||
811 | |||
812 | #ifdef EVAS_FRAME_QUEUING | ||
813 | return; | ||
814 | #endif | ||
815 | |||
816 | if (!im->cache_entry.pipe) return; | ||
817 | if (thread_num == 1) return; | ||
818 | y = 0; | ||
819 | h = im->cache_entry.h / thread_num; | ||
820 | if (h < 1) h = 1; | ||
821 | for (i = 0; i < thread_num; i++) | ||
822 | { | ||
823 | RGBA_Pipe_Thread_Info *info; | ||
824 | |||
825 | // if (y >= im->cache_entry.h) break; | ||
826 | info = calloc(1, sizeof(RGBA_Pipe_Thread_Info)); | ||
827 | info->im = im; | ||
828 | #ifdef EVAS_SLI | ||
829 | info->x = 0; | ||
830 | info->w = im->cache_entry.w; | ||
831 | info->y = i; | ||
832 | info->h = thread_num; | ||
833 | #else | ||
834 | info->x = 0; | ||
835 | info->y = y; | ||
836 | info->w = im->cache_entry.w; | ||
837 | if (i == (thread_num - 1)) | ||
838 | { | ||
839 | info->h = im->cache_entry.h - y; | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | info->h = h; | ||
844 | } | ||
845 | y += info->h; | ||
846 | #endif | ||
847 | thinfo[i].info = info; | ||
848 | } | ||
849 | /* tell worker threads to start */ | ||
850 | pthread_barrier_wait(&(thbarrier[0])); | ||
851 | #endif | ||
852 | } | ||
853 | |||
854 | #ifdef EVAS_FRAME_QUEUING | ||
855 | EAPI void | ||
856 | evas_common_frameq_begin(void) | ||
857 | { | ||
858 | #ifdef BUILD_PTHREAD | ||
859 | int i; | ||
860 | Evas_Frameq_Thread_Info *fp_info; | ||
861 | pthread_attr_t attr; | ||
862 | cpu_set_t cpu; | ||
863 | |||
864 | if (!gframeq.initialised) | ||
865 | { | ||
866 | int cpunum, set_cpu_affinity = 0; | ||
867 | |||
868 | cpunum = eina_cpu_count(); | ||
869 | gframeq.thread_num = cpunum; | ||
870 | gframeq.frameq_sz = cpunum * FRAMEQ_SZ_PER_THREAD; | ||
871 | |||
872 | eina_threads_init(); | ||
873 | |||
874 | for (i = 0; i < gframeq.thread_num; i++) | ||
875 | { | ||
876 | |||
877 | fp_info = calloc(1, sizeof(Evas_Frameq_Thread_Info)); | ||
878 | fp_info->frameq = &gframeq; | ||
879 | |||
880 | gframeq.thinfo[i].thread_num = i; | ||
881 | gframeq.thinfo[i].fq_info = fp_info; | ||
882 | |||
883 | pthread_attr_init(&attr); | ||
884 | if (set_cpu_affinity) | ||
885 | { | ||
886 | CPU_ZERO(&cpu); | ||
887 | CPU_SET((i+1) % cpunum, &cpu); | ||
888 | pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu); | ||
889 | } | ||
890 | |||
891 | pthread_create(&(gframeq.thinfo[i].thread_id), &attr, | ||
892 | evas_common_frameq_thread, &(gframeq.thinfo[i])); | ||
893 | |||
894 | pthread_attr_destroy(&attr); | ||
895 | pthread_detach(gframeq.thinfo[i].thread_id); | ||
896 | } | ||
897 | |||
898 | { | ||
899 | fp_info = calloc(1, sizeof(Evas_Frameq_Thread_Info)); | ||
900 | fp_info->frameq = &gframeq; | ||
901 | |||
902 | gframeq.thinfo[i].thread_num = i; | ||
903 | gframeq.thinfo[i].fq_info = fp_info; | ||
904 | |||
905 | pthread_attr_init(&attr); | ||
906 | if (set_cpu_affinity) | ||
907 | { | ||
908 | CPU_ZERO(&cpu); | ||
909 | CPU_SET((i+1) % cpunum, &cpu); | ||
910 | pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu); | ||
911 | } | ||
912 | |||
913 | pthread_create(&(gframeq.thinfo[i].thread_id), &attr, | ||
914 | evas_common_frameq_thread_post, &(gframeq.thinfo[i])); | ||
915 | pthread_attr_destroy(&attr); | ||
916 | pthread_detach(gframeq.thinfo[i].thread_id); | ||
917 | } | ||
918 | gframeq.initialised = 1; // now worker threads are created. | ||
919 | |||
920 | INF("initialised"); | ||
921 | DBG("%d cpus, set_cpu_affinity=%d, frameq_sz=%d", | ||
922 | cpunum, set_cpu_affinity, gframeq.frameq_sz); | ||
923 | } | ||
924 | #endif /* BUILD_PTHREAD */ | ||
925 | } | ||
926 | |||
927 | EAPI void | ||
928 | evas_common_frameq_finish(void) | ||
929 | { | ||
930 | int i; | ||
931 | |||
932 | /* 1. cancel all worker threads */ | ||
933 | for (i = 0; i < gframeq.thread_num; i++) | ||
934 | { | ||
935 | pthread_cancel(gframeq.thinfo[i].thread_id); | ||
936 | } | ||
937 | // cancel post-worker thread | ||
938 | pthread_cancel(gframeq.thinfo[i].thread_id); | ||
939 | |||
940 | /* 2. send signal to worker threads so that they enter to the thread cancelation cleanup handler */ | ||
941 | for (i = 0; i < gframeq.thread_num; i++) | ||
942 | { | ||
943 | eina_condition_signal(&(gframeq.cond_new)); | ||
944 | } | ||
945 | // send signal to post-worker thread | ||
946 | eina_condition_signal(&(gframeq.cond_ready)); | ||
947 | |||
948 | /* all the workers were created and detached before | ||
949 | * so don't need to join them here. | ||
950 | */ | ||
951 | |||
952 | } | ||
953 | |||
954 | #endif /* EVAS_FRAME_QUEUING */ | ||
955 | |||
956 | EAPI void | ||
957 | evas_common_pipe_flush(RGBA_Image *im) | ||
958 | { | ||
959 | if (!im->cache_entry.pipe) return; | ||
960 | #ifndef EVAS_FRAME_QUEUING | ||
961 | #ifdef BUILD_PTHREAD | ||
962 | if (thread_num > 1) | ||
963 | { | ||
964 | /* sync worker threads */ | ||
965 | pthread_barrier_wait(&(thbarrier[1])); | ||
966 | } | ||
967 | else | ||
968 | #endif | ||
969 | { | ||
970 | RGBA_Pipe *p; | ||
971 | int i; | ||
972 | |||
973 | /* process pipe - 1 thead */ | ||
974 | for (p = im->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next) | ||
975 | { | ||
976 | for (i = 0; i < p->op_num; i++) | ||
977 | { | ||
978 | if (p->op[i].op_func) | ||
979 | { | ||
980 | p->op[i].op_func(im, &(p->op[i]), NULL); | ||
981 | } | ||
982 | } | ||
983 | } | ||
984 | } | ||
985 | #endif /* !EVAS_FRAME_QUEUING */ | ||
986 | evas_common_cpu_end_opt(); | ||
987 | evas_common_pipe_free(im); | ||
988 | } | ||
989 | |||
990 | EAPI void | ||
991 | evas_common_pipe_free(RGBA_Image *im) | ||
992 | { | ||
993 | |||
994 | RGBA_Pipe *p; | ||
995 | int i; | ||
996 | |||
997 | if (!im->cache_entry.pipe) return; | ||
998 | /* FIXME: PTHREAD join all threads here (if not finished) */ | ||
999 | |||
1000 | /* free pipe */ | ||
1001 | while (im->cache_entry.pipe) | ||
1002 | { | ||
1003 | p = im->cache_entry.pipe; | ||
1004 | for (i = 0; i < p->op_num; i++) | ||
1005 | { | ||
1006 | if (p->op[i].free_func) | ||
1007 | { | ||
1008 | p->op[i].free_func(&(p->op[i])); | ||
1009 | } | ||
1010 | } | ||
1011 | im->cache_entry.pipe = (RGBA_Pipe *)eina_inlist_remove(EINA_INLIST_GET(im->cache_entry.pipe), EINA_INLIST_GET(p)); | ||
1012 | free(p); | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | |||
1017 | |||
1018 | /* draw ops */ | ||
1019 | /**************** RECT ******************/ | ||
1020 | static void | ||
1021 | evas_common_pipe_rectangle_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info) | ||
1022 | { | ||
1023 | if (info) | ||
1024 | { | ||
1025 | RGBA_Draw_Context context; | ||
1026 | |||
1027 | memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context)); | ||
1028 | #ifdef EVAS_SLI | ||
1029 | evas_common_draw_context_set_sli(&(context), info->y, info->h); | ||
1030 | #else | ||
1031 | evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h); | ||
1032 | #endif | ||
1033 | evas_common_rectangle_draw(dst, &(context), | ||
1034 | op->op.rect.x, op->op.rect.y, | ||
1035 | op->op.rect.w, op->op.rect.h); | ||
1036 | } | ||
1037 | else | ||
1038 | { | ||
1039 | evas_common_rectangle_draw(dst, &(op->context), | ||
1040 | op->op.rect.x, op->op.rect.y, | ||
1041 | op->op.rect.w, op->op.rect.h); | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | EAPI void | ||
1046 | evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, int w, int h) | ||
1047 | { | ||
1048 | RGBA_Pipe_Op *op; | ||
1049 | |||
1050 | if ((w < 1) || (h < 1)) return; | ||
1051 | dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op); | ||
1052 | if (!dst->cache_entry.pipe) return; | ||
1053 | op->op.rect.x = x; | ||
1054 | op->op.rect.y = y; | ||
1055 | op->op.rect.w = w; | ||
1056 | op->op.rect.h = h; | ||
1057 | op->op_func = evas_common_pipe_rectangle_draw_do; | ||
1058 | op->free_func = evas_common_pipe_op_free; | ||
1059 | evas_common_pipe_draw_context_copy(dc, op); | ||
1060 | } | ||
1061 | |||
1062 | /**************** LINE ******************/ | ||
1063 | static void | ||
1064 | evas_common_pipe_line_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info) | ||
1065 | { | ||
1066 | if (info) | ||
1067 | { | ||
1068 | RGBA_Draw_Context context; | ||
1069 | |||
1070 | memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context)); | ||
1071 | #ifdef EVAS_SLI | ||
1072 | evas_common_draw_context_set_sli(&(context), info->y, info->h); | ||
1073 | #else | ||
1074 | evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h); | ||
1075 | #endif | ||
1076 | evas_common_line_draw(dst, &(context), | ||
1077 | op->op.line.x0, op->op.line.y0, | ||
1078 | op->op.line.x1, op->op.line.y1); | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | evas_common_line_draw(dst, &(op->context), | ||
1083 | op->op.line.x0, op->op.line.y0, | ||
1084 | op->op.line.x1, op->op.line.y1); | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | EAPI void | ||
1089 | evas_common_pipe_line_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, | ||
1090 | int x0, int y0, int x1, int y1) | ||
1091 | { | ||
1092 | RGBA_Pipe_Op *op; | ||
1093 | |||
1094 | dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op); | ||
1095 | if (!dst->cache_entry.pipe) return; | ||
1096 | op->op.line.x0 = x0; | ||
1097 | op->op.line.y0 = y0; | ||
1098 | op->op.line.x1 = x1; | ||
1099 | op->op.line.y1 = y1; | ||
1100 | op->op_func = evas_common_pipe_line_draw_do; | ||
1101 | op->free_func = evas_common_pipe_op_free; | ||
1102 | evas_common_pipe_draw_context_copy(dc, op); | ||
1103 | } | ||
1104 | |||
1105 | /**************** POLY ******************/ | ||
1106 | static void | ||
1107 | evas_common_pipe_op_poly_free(RGBA_Pipe_Op *op) | ||
1108 | { | ||
1109 | RGBA_Polygon_Point *p; | ||
1110 | |||
1111 | while (op->op.poly.points) | ||
1112 | { | ||
1113 | p = op->op.poly.points; | ||
1114 | op->op.poly.points = (RGBA_Polygon_Point *)eina_inlist_remove(EINA_INLIST_GET(op->op.poly.points), | ||
1115 | EINA_INLIST_GET(p)); | ||
1116 | free(p); | ||
1117 | } | ||
1118 | evas_common_pipe_op_free(op); | ||
1119 | } | ||
1120 | |||
1121 | static void | ||
1122 | evas_common_pipe_poly_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info) | ||
1123 | { | ||
1124 | if (info) | ||
1125 | { | ||
1126 | RGBA_Draw_Context context; | ||
1127 | |||
1128 | memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context)); | ||
1129 | #ifdef EVAS_SLI | ||
1130 | evas_common_draw_context_set_sli(&(context), info->y, info->h); | ||
1131 | #else | ||
1132 | evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h); | ||
1133 | #endif | ||
1134 | evas_common_polygon_draw(dst, &(context), | ||
1135 | op->op.poly.points, 0, 0); | ||
1136 | } | ||
1137 | else | ||
1138 | { | ||
1139 | evas_common_polygon_draw(dst, &(op->context), | ||
1140 | op->op.poly.points, 0, 0); | ||
1141 | } | ||
1142 | } | ||
1143 | |||
1144 | EAPI void | ||
1145 | evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, | ||
1146 | RGBA_Polygon_Point *points, int x, int y) | ||
1147 | { | ||
1148 | RGBA_Pipe_Op *op; | ||
1149 | RGBA_Polygon_Point *pts = NULL, *p, *pp; | ||
1150 | |||
1151 | if (!points) return; | ||
1152 | dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op); | ||
1153 | if (!dst->cache_entry.pipe) return; | ||
1154 | /* FIXME: copy points - maybe we should refcount? */ | ||
1155 | for (p = points; p; p = (RGBA_Polygon_Point *)(EINA_INLIST_GET(p))->next) | ||
1156 | { | ||
1157 | pp = calloc(1, sizeof(RGBA_Polygon_Point)); | ||
1158 | if (pp) | ||
1159 | { | ||
1160 | pp->x = p->x + x; | ||
1161 | pp->y = p->y + y; | ||
1162 | pts = (RGBA_Polygon_Point *)eina_inlist_append(EINA_INLIST_GET(pts), EINA_INLIST_GET(pp)); | ||
1163 | } | ||
1164 | } | ||
1165 | op->op.poly.points = pts; | ||
1166 | op->op_func = evas_common_pipe_poly_draw_do; | ||
1167 | op->free_func = evas_common_pipe_op_poly_free; | ||
1168 | evas_common_pipe_draw_context_copy(dc, op); | ||
1169 | } | ||
1170 | |||
1171 | /**************** TEXT ******************/ | ||
1172 | static void | ||
1173 | evas_common_pipe_op_text_free(RGBA_Pipe_Op *op) | ||
1174 | { | ||
1175 | #ifdef EVAS_FRAME_QUEUING | ||
1176 | LKL(op->op.text.font->ref_fq_del); | ||
1177 | op->op.text.font->ref_fq[1]++; | ||
1178 | LKU(op->op.text.font->ref_fq_del); | ||
1179 | eina_condition_signal(&(op->op.text.font->cond_fq_del)); | ||
1180 | #else | ||
1181 | evas_common_font_free(op->op.text.font); | ||
1182 | #endif | ||
1183 | evas_common_text_props_content_unref(&(op->op.text.intl_props)); | ||
1184 | evas_common_pipe_op_free(op); | ||
1185 | } | ||
1186 | |||
1187 | #ifdef EVAS_FRAME_QUEUING | ||
1188 | /* flush all op using @fn */ | ||
1189 | EAPI void | ||
1190 | evas_common_pipe_op_text_flush(RGBA_Font *fn) | ||
1191 | { | ||
1192 | if (! evas_common_frameq_enabled()) | ||
1193 | return; | ||
1194 | |||
1195 | LKL(fn->ref_fq_add); | ||
1196 | LKL(fn->ref_fq_del); | ||
1197 | |||
1198 | while (fn->ref_fq[0] != fn->ref_fq[1]) | ||
1199 | eina_condition_wait(&(fn->cond_fq_del)); | ||
1200 | |||
1201 | LKU(fn->ref_fq_del); | ||
1202 | LKU(fn->ref_fq_add); | ||
1203 | } | ||
1204 | #endif | ||
1205 | |||
1206 | static void | ||
1207 | evas_common_pipe_text_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info) | ||
1208 | { | ||
1209 | if (info) | ||
1210 | { | ||
1211 | RGBA_Draw_Context context; | ||
1212 | |||
1213 | memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context)); | ||
1214 | #ifdef EVAS_SLI | ||
1215 | evas_common_draw_context_set_sli(&(context), info->y, info->h); | ||
1216 | #else | ||
1217 | evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h); | ||
1218 | #endif | ||
1219 | evas_common_font_draw(dst, &(context), | ||
1220 | op->op.text.font, op->op.text.x, op->op.text.y, | ||
1221 | &op->op.text.intl_props); | ||
1222 | } | ||
1223 | else | ||
1224 | { | ||
1225 | evas_common_font_draw(dst, &(op->context), | ||
1226 | op->op.text.font, op->op.text.x, op->op.text.y, | ||
1227 | &op->op.text.intl_props); | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | EAPI void | ||
1232 | evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, | ||
1233 | RGBA_Font *fn, int x, int y, const Evas_Text_Props *intl_props) | ||
1234 | { | ||
1235 | RGBA_Pipe_Op *op; | ||
1236 | |||
1237 | if (!fn) return; | ||
1238 | dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op); | ||
1239 | if (!dst->cache_entry.pipe) return; | ||
1240 | op->op.text.x = x; | ||
1241 | op->op.text.y = y; | ||
1242 | evas_common_text_props_content_copy_and_ref(&(op->op.text.intl_props), | ||
1243 | intl_props); | ||
1244 | #ifdef EVAS_FRAME_QUEUING | ||
1245 | LKL(fn->ref_fq_add); | ||
1246 | fn->ref_fq[0]++; | ||
1247 | LKU(fn->ref_fq_add); | ||
1248 | #else | ||
1249 | fn->references++; | ||
1250 | #endif | ||
1251 | op->op.text.font = fn; | ||
1252 | op->op_func = evas_common_pipe_text_draw_do; | ||
1253 | op->free_func = evas_common_pipe_op_text_free; | ||
1254 | evas_common_pipe_draw_context_copy(dc, op); | ||
1255 | } | ||
1256 | |||
1257 | /**************** IMAGE *****************/ | ||
1258 | static void | ||
1259 | evas_common_pipe_op_image_free(RGBA_Pipe_Op *op) | ||
1260 | { | ||
1261 | #ifdef EVAS_FRAME_QUEUING | ||
1262 | LKL(op->op.image.src->cache_entry.ref_fq_del); | ||
1263 | op->op.image.src->cache_entry.ref_fq[1]++; | ||
1264 | LKU(op->op.image.src->cache_entry.ref_fq_del); | ||
1265 | eina_condition_signal(&(op->op.image.src->cache_entry.cond_fq_del)); | ||
1266 | #else | ||
1267 | op->op.image.src->ref--; | ||
1268 | if (op->op.image.src->ref == 0) | ||
1269 | { | ||
1270 | evas_cache_image_drop(&op->op.image.src->cache_entry); | ||
1271 | } | ||
1272 | #endif | ||
1273 | evas_common_pipe_op_free(op); | ||
1274 | } | ||
1275 | |||
1276 | #ifdef EVAS_FRAME_QUEUING | ||
1277 | EAPI void | ||
1278 | evas_common_pipe_op_image_flush(RGBA_Image *im) | ||
1279 | { | ||
1280 | if (! evas_common_frameq_enabled()) | ||
1281 | return; | ||
1282 | |||
1283 | LKL(im->cache_entry.ref_fq_add); | ||
1284 | LKL(im->cache_entry.ref_fq_del); | ||
1285 | |||
1286 | while (im->cache_entry.ref_fq[0] != im->cache_entry.ref_fq[1]) | ||
1287 | eina_condition_wait(&(im->cache_entry.cond_fq_del)); | ||
1288 | |||
1289 | LKU(im->cache_entry.ref_fq_del); | ||
1290 | LKU(im->cache_entry.ref_fq_add); | ||
1291 | } | ||
1292 | #endif | ||
1293 | |||
1294 | static void | ||
1295 | evas_common_pipe_image_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info) | ||
1296 | { | ||
1297 | if (info) | ||
1298 | { | ||
1299 | RGBA_Draw_Context context; | ||
1300 | |||
1301 | memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context)); | ||
1302 | #ifdef EVAS_SLI | ||
1303 | evas_common_draw_context_set_sli(&(context), info->y, info->h); | ||
1304 | #else | ||
1305 | evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h); | ||
1306 | #endif | ||
1307 | |||
1308 | #ifdef SCALECACHE | ||
1309 | evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src), | ||
1310 | dst, &(context), | ||
1311 | op->op.image.smooth, | ||
1312 | op->op.image.sx, | ||
1313 | op->op.image.sy, | ||
1314 | op->op.image.sw, | ||
1315 | op->op.image.sh, | ||
1316 | op->op.image.dx, | ||
1317 | op->op.image.dy, | ||
1318 | op->op.image.dw, | ||
1319 | op->op.image.dh); | ||
1320 | #else | ||
1321 | if (op->op.image.smooth) | ||
1322 | { | ||
1323 | evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src, | ||
1324 | dst, &(context), | ||
1325 | op->op.image.sx, | ||
1326 | op->op.image.sy, | ||
1327 | op->op.image.sw, | ||
1328 | op->op.image.sh, | ||
1329 | op->op.image.dx, | ||
1330 | op->op.image.dy, | ||
1331 | op->op.image.dw, | ||
1332 | op->op.image.dh); | ||
1333 | } | ||
1334 | else | ||
1335 | { | ||
1336 | evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src, | ||
1337 | dst, &(context), | ||
1338 | op->op.image.sx, | ||
1339 | op->op.image.sy, | ||
1340 | op->op.image.sw, | ||
1341 | op->op.image.sh, | ||
1342 | op->op.image.dx, | ||
1343 | op->op.image.dy, | ||
1344 | op->op.image.dw, | ||
1345 | op->op.image.dh); | ||
1346 | } | ||
1347 | #endif | ||
1348 | } | ||
1349 | else | ||
1350 | { | ||
1351 | #ifdef SCALECACHE | ||
1352 | evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src), | ||
1353 | dst, &(op->context), | ||
1354 | op->op.image.smooth, | ||
1355 | op->op.image.sx, | ||
1356 | op->op.image.sy, | ||
1357 | op->op.image.sw, | ||
1358 | op->op.image.sh, | ||
1359 | op->op.image.dx, | ||
1360 | op->op.image.dy, | ||
1361 | op->op.image.dw, | ||
1362 | op->op.image.dh); | ||
1363 | #else | ||
1364 | if (op->op.image.smooth) | ||
1365 | { | ||
1366 | evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src, | ||
1367 | dst, &(op->context), | ||
1368 | op->op.image.sx, | ||
1369 | op->op.image.sy, | ||
1370 | op->op.image.sw, | ||
1371 | op->op.image.sh, | ||
1372 | op->op.image.dx, | ||
1373 | op->op.image.dy, | ||
1374 | op->op.image.dw, | ||
1375 | op->op.image.dh); | ||
1376 | } | ||
1377 | else | ||
1378 | { | ||
1379 | evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src, | ||
1380 | dst, &(op->context), | ||
1381 | op->op.image.sx, | ||
1382 | op->op.image.sy, | ||
1383 | op->op.image.sw, | ||
1384 | op->op.image.sh, | ||
1385 | op->op.image.dx, | ||
1386 | op->op.image.dy, | ||
1387 | op->op.image.dw, | ||
1388 | op->op.image.dh); | ||
1389 | } | ||
1390 | #endif | ||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | EAPI void | ||
1395 | evas_common_pipe_image_draw(RGBA_Image *src, RGBA_Image *dst, | ||
1396 | RGBA_Draw_Context *dc, int smooth, | ||
1397 | int src_region_x, int src_region_y, | ||
1398 | int src_region_w, int src_region_h, | ||
1399 | int dst_region_x, int dst_region_y, | ||
1400 | int dst_region_w, int dst_region_h) | ||
1401 | { | ||
1402 | RGBA_Pipe_Op *op; | ||
1403 | |||
1404 | if (!src) return; | ||
1405 | // evas_common_pipe_flush(src); | ||
1406 | dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op); | ||
1407 | if (!dst->cache_entry.pipe) return; | ||
1408 | op->op.image.smooth = smooth; | ||
1409 | op->op.image.sx = src_region_x; | ||
1410 | op->op.image.sy = src_region_y; | ||
1411 | op->op.image.sw = src_region_w; | ||
1412 | op->op.image.sh = src_region_h; | ||
1413 | op->op.image.dx = dst_region_x; | ||
1414 | op->op.image.dy = dst_region_y; | ||
1415 | op->op.image.dw = dst_region_w; | ||
1416 | op->op.image.dh = dst_region_h; | ||
1417 | #ifdef EVAS_FRAME_QUEUING | ||
1418 | LKL(src->cache_entry.ref_fq_add); | ||
1419 | src->cache_entry.ref_fq[0]++; | ||
1420 | LKU(src->cache_entry.ref_fq_add); | ||
1421 | #else | ||
1422 | src->ref++; | ||
1423 | #endif | ||
1424 | op->op.image.src = src; | ||
1425 | op->op_func = evas_common_pipe_image_draw_do; | ||
1426 | op->free_func = evas_common_pipe_op_image_free; | ||
1427 | evas_common_pipe_draw_context_copy(dc, op); | ||
1428 | |||
1429 | #ifdef EVAS_FRAME_QUEUING | ||
1430 | /* laod every src image here. | ||
1431 | * frameq utilize all cpu cores already by worker threads | ||
1432 | * so another threads and barrier waiting can't be of any benefit. | ||
1433 | * therefore, not instantiate loader threads. | ||
1434 | */ | ||
1435 | if (src->cache_entry.space == EVAS_COLORSPACE_ARGB8888) | ||
1436 | evas_cache_image_load_data(&src->cache_entry); | ||
1437 | evas_common_image_colorspace_normalize(src); | ||
1438 | #else | ||
1439 | evas_common_pipe_image_load(src); | ||
1440 | #endif | ||
1441 | } | ||
1442 | |||
1443 | static void | ||
1444 | evas_common_pipe_op_map_free(RGBA_Pipe_Op *op) | ||
1445 | { | ||
1446 | #ifdef EVAS_FRAME_QUEUING | ||
1447 | LKL(op->op.image.src->cache_entry.ref_fq_del); | ||
1448 | op->op.image.src->cache_entry.ref_fq[1]++; | ||
1449 | LKU(op->op.image.src->cache_entry.ref_fq_del); | ||
1450 | #else | ||
1451 | op->op.map.src->ref--; | ||
1452 | if (op->op.map.src->ref == 0) | ||
1453 | evas_cache_image_drop(&op->op.map.src->cache_entry); | ||
1454 | #endif | ||
1455 | free(op->op.map.p); | ||
1456 | evas_common_pipe_op_free(op); | ||
1457 | } | ||
1458 | |||
1459 | static void | ||
1460 | evas_common_pipe_map_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info) | ||
1461 | { | ||
1462 | if (info) | ||
1463 | { | ||
1464 | RGBA_Draw_Context context; | ||
1465 | |||
1466 | memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context)); | ||
1467 | #ifdef EVAS_SLI | ||
1468 | evas_common_draw_context_set_sli(&(context), info->y, info->h); | ||
1469 | #else | ||
1470 | evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h); | ||
1471 | #endif | ||
1472 | |||
1473 | evas_common_map_rgba(op->op.map.src, dst, | ||
1474 | &context, op->op.map.npoints, op->op.map.p, | ||
1475 | op->op.map.smooth, op->op.map.level); | ||
1476 | } | ||
1477 | else | ||
1478 | { | ||
1479 | evas_common_map_rgba(op->op.map.src, dst, | ||
1480 | &(op->context), op->op.map.npoints, op->op.map.p, | ||
1481 | op->op.map.smooth, op->op.map.level); | ||
1482 | } | ||
1483 | } | ||
1484 | |||
1485 | EAPI void | ||
1486 | evas_common_pipe_map_draw(RGBA_Image *src, RGBA_Image *dst, | ||
1487 | RGBA_Draw_Context *dc, int npoints, RGBA_Map_Point *p, | ||
1488 | int smooth, int level) | ||
1489 | { | ||
1490 | RGBA_Pipe_Op *op; | ||
1491 | RGBA_Map_Point *pts_copy; | ||
1492 | int i; | ||
1493 | |||
1494 | if (!src) return; | ||
1495 | pts_copy = malloc(sizeof (RGBA_Map_Point) * 4); | ||
1496 | if (!pts_copy) return; | ||
1497 | dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op); | ||
1498 | if (!dst->cache_entry.pipe) | ||
1499 | { | ||
1500 | free(pts_copy); | ||
1501 | return; | ||
1502 | } | ||
1503 | |||
1504 | for (i = 0; i < 4; ++i) | ||
1505 | pts_copy[i] = p[i]; | ||
1506 | |||
1507 | op->op.map.npoints = npoints; | ||
1508 | op->op.map.smooth = smooth; | ||
1509 | op->op.map.level = level; | ||
1510 | #ifdef EVAS_FRAME_QUEUING | ||
1511 | LKL(src->cache_entry.ref_fq_add); | ||
1512 | src->cache_entry.ref_fq[0]++; | ||
1513 | LKU(src->cache_entry.ref_fq_add); | ||
1514 | #else | ||
1515 | src->ref++; | ||
1516 | #endif | ||
1517 | op->op.map.src = src; | ||
1518 | op->op.map.p = pts_copy; | ||
1519 | op->op_func = evas_common_pipe_map_draw_do; | ||
1520 | op->free_func = evas_common_pipe_op_map_free; | ||
1521 | evas_common_pipe_draw_context_copy(dc, op); | ||
1522 | |||
1523 | #ifdef EVAS_FRAME_QUEUING | ||
1524 | /* laod every src image here. | ||
1525 | * frameq utilize all cpu cores already by worker threads | ||
1526 | * so another threads and barrier waiting can't be of any benefit. | ||
1527 | * therefore, not instantiate loader threads. | ||
1528 | */ | ||
1529 | if (src->cache_entry.space == EVAS_COLORSPACE_ARGB8888) | ||
1530 | evas_cache_image_load_data(&src->cache_entry); | ||
1531 | evas_common_image_colorspace_normalize(src); | ||
1532 | #else | ||
1533 | evas_common_pipe_image_load(src); | ||
1534 | #endif | ||
1535 | } | ||
1536 | |||
1537 | static void | ||
1538 | evas_common_pipe_map_render(RGBA_Image *root) | ||
1539 | { | ||
1540 | RGBA_Pipe *p; | ||
1541 | int i; | ||
1542 | |||
1543 | /* Map imply that we need to process them recursively first. */ | ||
1544 | for (p = root->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next) | ||
1545 | { | ||
1546 | for (i = 0; i < p->op_num; i++) | ||
1547 | { | ||
1548 | if (p->op[i].op_func == evas_common_pipe_map_draw_do) | ||
1549 | { | ||
1550 | if (p->op[i].op.map.src->cache_entry.pipe) | ||
1551 | evas_common_pipe_map_render(p->op[i].op.map.src); | ||
1552 | } | ||
1553 | else if (p->op[i].op_func == evas_common_pipe_image_draw_do) | ||
1554 | { | ||
1555 | if (p->op[i].op.image.src->cache_entry.pipe) | ||
1556 | evas_common_pipe_map_render(p->op[i].op.image.src); | ||
1557 | } | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | evas_common_pipe_begin(root); | ||
1562 | evas_common_pipe_flush(root); | ||
1563 | } | ||
1564 | |||
1565 | #ifdef BUILD_PTHREAD | ||
1566 | static Eina_List *task = NULL; | ||
1567 | static Thinfo task_thinfo[TH_MAX]; | ||
1568 | static pthread_barrier_t task_thbarrier[2]; | ||
1569 | static LK(task_mutext); | ||
1570 | #endif | ||
1571 | |||
1572 | #ifdef BUILD_PTHREAD | ||
1573 | static void* | ||
1574 | evas_common_pipe_load(void *data) | ||
1575 | { | ||
1576 | Thinfo *tinfo; | ||
1577 | |||
1578 | tinfo = data; | ||
1579 | for (;;) | ||
1580 | { | ||
1581 | /* wait for start signal */ | ||
1582 | pthread_barrier_wait(&(tinfo->barrier[0])); | ||
1583 | |||
1584 | while (task) | ||
1585 | { | ||
1586 | RGBA_Image *im = NULL; | ||
1587 | |||
1588 | LKL(task_mutext); | ||
1589 | im = eina_list_data_get(task); | ||
1590 | task = eina_list_remove_list(task, task); | ||
1591 | LKU(task_mutext); | ||
1592 | |||
1593 | if (im) | ||
1594 | { | ||
1595 | if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888) | ||
1596 | evas_cache_image_load_data(&im->cache_entry); | ||
1597 | evas_common_image_colorspace_normalize(im); | ||
1598 | |||
1599 | im->flags &= ~RGBA_IMAGE_TODO_LOAD; | ||
1600 | } | ||
1601 | } | ||
1602 | |||
1603 | /* send finished signal */ | ||
1604 | pthread_barrier_wait(&(tinfo->barrier[1])); | ||
1605 | } | ||
1606 | |||
1607 | return NULL; | ||
1608 | } | ||
1609 | #endif | ||
1610 | |||
1611 | static volatile int bval = 0; | ||
1612 | |||
1613 | static void | ||
1614 | evas_common_pipe_image_load_do(void) | ||
1615 | { | ||
1616 | #ifdef BUILD_PTHREAD | ||
1617 | /* Notify worker thread. */ | ||
1618 | pthread_barrier_wait(&(task_thbarrier[0])); | ||
1619 | |||
1620 | /* sync worker threads */ | ||
1621 | pthread_barrier_wait(&(task_thbarrier[1])); | ||
1622 | #endif | ||
1623 | } | ||
1624 | |||
1625 | static Eina_Bool | ||
1626 | evas_common_pipe_init(void) | ||
1627 | { | ||
1628 | #ifdef BUILD_PTHREAD | ||
1629 | if (thread_num == 0) | ||
1630 | { | ||
1631 | int cpunum; | ||
1632 | int i; | ||
1633 | |||
1634 | cpunum = eina_cpu_count(); | ||
1635 | thread_num = cpunum; | ||
1636 | // on single cpu we still want this initted.. otherwise we block forever | ||
1637 | // waiting onm pthread barriers for async rendering on a single core! | ||
1638 | // if (thread_num == 1) return EINA_FALSE; | ||
1639 | |||
1640 | eina_threads_init(); | ||
1641 | |||
1642 | LKI(task_mutext); | ||
1643 | |||
1644 | pthread_barrier_init(&(thbarrier[0]), NULL, thread_num + 1); | ||
1645 | pthread_barrier_init(&(thbarrier[1]), NULL, thread_num + 1); | ||
1646 | for (i = 0; i < thread_num; i++) | ||
1647 | { | ||
1648 | pthread_attr_t attr; | ||
1649 | cpu_set_t cpu; | ||
1650 | |||
1651 | pthread_attr_init(&attr); | ||
1652 | CPU_ZERO(&cpu); | ||
1653 | CPU_SET(i % cpunum, &cpu); | ||
1654 | pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu); | ||
1655 | thinfo[i].thread_num = i; | ||
1656 | thinfo[i].info = NULL; | ||
1657 | thinfo[i].barrier = thbarrier; | ||
1658 | /* setup initial locks */ | ||
1659 | pthread_create(&(thinfo[i].thread_id), &attr, | ||
1660 | evas_common_pipe_thread, &(thinfo[i])); | ||
1661 | pthread_attr_destroy(&attr); | ||
1662 | } | ||
1663 | |||
1664 | pthread_barrier_init(&(task_thbarrier[0]), NULL, thread_num + 1); | ||
1665 | pthread_barrier_init(&(task_thbarrier[1]), NULL, thread_num + 1); | ||
1666 | for (i = 0; i < thread_num; i++) | ||
1667 | { | ||
1668 | pthread_attr_t attr; | ||
1669 | cpu_set_t cpu; | ||
1670 | |||
1671 | pthread_attr_init(&attr); | ||
1672 | CPU_ZERO(&cpu); | ||
1673 | CPU_SET(i % cpunum, &cpu); | ||
1674 | pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu); | ||
1675 | task_thinfo[i].thread_num = i; | ||
1676 | task_thinfo[i].info = NULL; | ||
1677 | task_thinfo[i].barrier = task_thbarrier; | ||
1678 | /* setup initial locks */ | ||
1679 | pthread_create(&(task_thinfo[i].thread_id), &attr, | ||
1680 | evas_common_pipe_load, &(task_thinfo[i])); | ||
1681 | pthread_attr_destroy(&attr); | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | if (thread_num == 1) return EINA_FALSE; | ||
1686 | return EINA_TRUE; | ||
1687 | #endif | ||
1688 | return EINA_FALSE; | ||
1689 | } | ||
1690 | |||
1691 | EAPI void | ||
1692 | evas_common_pipe_image_load(RGBA_Image *im) | ||
1693 | { | ||
1694 | if (im->flags & RGBA_IMAGE_TODO_LOAD) | ||
1695 | return ; | ||
1696 | |||
1697 | if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888 | ||
1698 | && !evas_cache_image_is_loaded(&(im->cache_entry))) | ||
1699 | goto add_task; | ||
1700 | |||
1701 | if ((!im->cs.data) || ((!im->cs.dirty) && (!(im->flags & RGBA_IMAGE_IS_DIRTY)))) | ||
1702 | goto add_task; | ||
1703 | |||
1704 | return ; | ||
1705 | |||
1706 | add_task: | ||
1707 | task = eina_list_append(task, im); | ||
1708 | im->flags |= RGBA_IMAGE_TODO_LOAD; | ||
1709 | } | ||
1710 | |||
1711 | EAPI void | ||
1712 | evas_common_pipe_map_begin(RGBA_Image *root) | ||
1713 | { | ||
1714 | if (!evas_common_pipe_init()) | ||
1715 | { | ||
1716 | RGBA_Image *im; | ||
1717 | |||
1718 | EINA_LIST_FREE(task, im) | ||
1719 | { | ||
1720 | if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888) | ||
1721 | evas_cache_image_load_data(&im->cache_entry); | ||
1722 | evas_common_image_colorspace_normalize(im); | ||
1723 | |||
1724 | im->flags &= ~RGBA_IMAGE_TODO_LOAD; | ||
1725 | } | ||
1726 | } | ||
1727 | |||
1728 | evas_common_pipe_image_load_do(); | ||
1729 | |||
1730 | evas_common_pipe_map_render(root); | ||
1731 | } | ||
1732 | |||
1733 | #endif | ||