evas: don't clip the clipper.
[framework/uifw/evas.git] / src / lib / engines / common / evas_pipe.c
1 #include "evas_common.h"
2 #include <unistd.h>
3
4 #ifdef BUILD_PIPE_RENDER
5 static RGBA_Pipe *evas_common_pipe_add(RGBA_Pipe *pipe, RGBA_Pipe_Op **op);
6 static void evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op);
7 static void evas_common_pipe_op_free(RGBA_Pipe_Op *op);
8
9 /* utils */
10 static RGBA_Pipe *
11 evas_common_pipe_add(RGBA_Pipe *rpipe, RGBA_Pipe_Op **op)
12 {
13    RGBA_Pipe *p;
14    int first_pipe = 0;
15
16    if (!rpipe)
17      {
18         first_pipe = 1;
19         p = calloc(1, sizeof(RGBA_Pipe));
20         if (!p) return NULL;
21         rpipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(rpipe), EINA_INLIST_GET(p));
22      }
23    p = (RGBA_Pipe *)(EINA_INLIST_GET(rpipe))->last;
24    if (p->op_num == PIPE_LEN)
25      {
26         p = calloc(1, sizeof(RGBA_Pipe));
27         if (!p) return NULL;
28         rpipe = (RGBA_Pipe *)eina_inlist_append(EINA_INLIST_GET(rpipe), EINA_INLIST_GET(p));
29      }
30    p->op_num++;
31    *op = &(p->op[p->op_num - 1]);
32    if (first_pipe)
33      {
34         /* FIXME: PTHREAD init any thread locks etc */
35      }
36    return rpipe;
37 }
38
39 static void
40 evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op)
41 {
42    memcpy(&(op->context), dc, sizeof(RGBA_Draw_Context));
43    if (op->context.cutout.active > 0)
44      {
45         op->context.cutout.rects = malloc(sizeof(Cutout_Rect) * op->context.cutout.active);
46         memcpy(op->context.cutout.rects, dc->cutout.rects, sizeof(Cutout_Rect) * op->context.cutout.active);
47      }
48    else
49      {
50         op->context.cutout.rects = NULL;
51      }
52 }
53
54 static void
55 evas_common_pipe_op_free(RGBA_Pipe_Op *op)
56 {
57    evas_common_draw_context_apply_clean_cutouts(&op->context.cutout);
58 }
59
60 #ifdef BUILD_PTHREAD
61 /* main api calls */
62 static void *
63 evas_common_pipe_thread(void *data)
64 {
65    Thinfo *thinfo;
66
67 // INF("TH [...........");
68    thinfo = data;
69    for (;;)
70      {
71         const RGBA_Pipe_Thread_Info *info;
72         RGBA_Pipe *p;
73
74         /* wait for start signal */
75 // INF(" TH %i START...", thinfo->thread_num);
76         pthread_barrier_wait(&(thinfo->barrier[0]));
77
78         EINA_INLIST_FOREACH(thinfo->tasks, info)
79           {
80              EINA_INLIST_FOREACH(EINA_INLIST_GET(thinfo->im->cache_entry.pipe), p)
81                {
82                   int i;
83
84                   for (i = 0; i < p->op_num; i++)
85                     {
86                        if (p->op[i].op_func && p->op[i].render)
87                          p->op[i].op_func(thinfo->im, &(p->op[i]), info);
88                     }
89                }
90           }
91
92         thinfo->tasks = NULL;
93
94         pthread_barrier_wait(&(thinfo->barrier[1]));
95      }
96    return NULL;
97 }
98 #endif
99
100 #ifdef BUILD_PTHREAD
101 static Eina_List *im_task = NULL;
102 static Eina_List *text_task = NULL;
103 static Thinfo task_thinfo[TH_MAX];
104 static pthread_barrier_t task_thbarrier[2];
105 static LK(im_task_mutex);
106 static LK(text_task_mutex);
107
108 static int               thread_num = 0;
109 static Thinfo            thinfo[TH_MAX];
110 static pthread_barrier_t thbarrier[2];
111
112 static RGBA_Pipe_Thread_Info *buf = NULL;
113 static unsigned int           buf_size = 0;
114
115 static Cutout_Rects *
116 evas_pipe_cutout_rects_pop(Thinfo *info)
117 {
118    Cutout_Rects *r;
119
120    r = eina_array_pop(&info->cutout_trash);
121    if (!r) r = evas_common_draw_context_cutouts_new();
122    return r;
123 }
124
125 static void
126 evas_pipe_cutout_rects_push(Thinfo *info, Cutout_Rects *r)
127 {
128    /* evas_common_draw_context_apply_clean_cutouts(r); */
129    evas_common_draw_context_cutouts_free(r);
130    eina_array_push(&info->cutout_trash, r);
131 }
132
133 static void
134 evas_pipe_cutout_rects_rotate(Cutout_Rects *r)
135 {
136    static int current = 0;
137
138    if (current >= thread_num) current = 0;
139    evas_pipe_cutout_rects_push(&task_thinfo[current], r);
140    current++;
141 }
142
143 static void
144 evas_pipe_prepare_push(RGBA_Pipe_Op *op)
145 {
146    static int current = 0;
147
148    if (current >= thread_num) current = 0;
149    eina_array_push(&task_thinfo[current].rects_task, op);
150    current++;
151 }
152
153 #endif
154
155 static void
156 evas_common_pipe_begin(RGBA_Image *im)
157 {
158 #define SZ 128
159 #ifdef BUILD_PTHREAD
160    unsigned int x, y, cpu;
161    RGBA_Pipe_Thread_Info *info;
162    unsigned int estimatex, estimatey;
163    unsigned int needed_size;
164
165    if (!im->cache_entry.pipe) return;
166    if (thread_num == 1) return;
167
168    if (im->cache_entry.w * im->cache_entry.h / thread_num < SZ * SZ)
169      {
170         estimatex = im->cache_entry.w;
171         estimatey = im->cache_entry.h / thread_num;
172         if (estimatey == 0) estimatey = 1;
173      }
174    else
175      {
176         estimatex = SZ;
177         estimatey = SZ;
178      }
179
180    needed_size = ((im->cache_entry.w / estimatex) + 1 ) * ((im->cache_entry.h /  estimatey) + 1);
181    if (buf_size < needed_size)
182      {
183         buf = realloc(buf, sizeof (RGBA_Pipe_Thread_Info) * needed_size);
184         buf_size = needed_size;
185      }
186
187    info = buf;
188    cpu = 0;
189    for (y = 0; y < im->cache_entry.h; y += estimatey)
190      for (x = 0; x < im->cache_entry.w; x += estimatex)
191        {
192           EINA_RECTANGLE_SET(&info->area, x, y,
193                              (x + estimatex > im->cache_entry.w) ? im->cache_entry.w - x : estimatex,
194                              (y + estimatey > im->cache_entry.h) ? im->cache_entry.h - y : estimatey);
195
196           thinfo[cpu].im = im;
197           thinfo[cpu].tasks = eina_inlist_prepend((void*) thinfo[cpu].tasks, EINA_INLIST_GET(info));
198           cpu++;
199           if (cpu >= (unsigned int) thread_num) cpu = 0;
200
201           info++;
202        }
203
204    /* tell worker threads to start */
205    pthread_barrier_wait(&(thbarrier[0]));
206 #endif
207 }
208
209 EAPI void
210 evas_common_pipe_flush(RGBA_Image *im)
211 {
212    if (!im->cache_entry.pipe) return;
213 #ifdef BUILD_PTHREAD
214    if (thread_num > 1)
215      {
216        /* sync worker threads */
217        pthread_barrier_wait(&(thbarrier[1]));
218      }
219    else
220 #endif
221      {
222         RGBA_Pipe_Thread_Info info;
223         RGBA_Pipe *p;
224         int i;
225
226         EINA_RECTANGLE_SET(&info.area, 0, 0, im->cache_entry.w, im->cache_entry.h);
227
228         /* process pipe - 1 thead */
229         for (p = im->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
230           {
231              for (i = 0; i < p->op_num; i++)
232                {
233                   if (p->op[i].render && p->op[i].op_func)
234                     {
235                        p->op[i].op_func(im, &(p->op[i]), &info);
236                     }
237                }
238           }
239      }
240
241    evas_common_cpu_end_opt();
242    evas_common_pipe_free(im);
243 }
244
245 EAPI void
246 evas_common_pipe_free(RGBA_Image *im)
247 {
248
249    RGBA_Pipe *p;
250    int i;
251
252    if (!im->cache_entry.pipe) return;
253    /* FIXME: PTHREAD join all threads here (if not finished) */
254
255    /* free pipe */
256    while (im->cache_entry.pipe)
257      {
258         p = im->cache_entry.pipe;
259         for (i = 0; i < p->op_num; i++)
260           {
261              if (p->op[i].free_func)
262                {
263                   p->op[i].free_func(&(p->op[i]));
264                }
265              if (p->op[i].rects) evas_pipe_cutout_rects_rotate(p->op[i].rects);
266           }
267         im->cache_entry.pipe = (RGBA_Pipe *)eina_inlist_remove(EINA_INLIST_GET(im->cache_entry.pipe), EINA_INLIST_GET(p));
268         free(p);
269      }
270 }
271
272
273
274 /* draw ops */
275 /**************** RECT ******************/
276 static void
277 evas_common_pipe_rectangle_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
278 {
279    RGBA_Draw_Context context;
280
281    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
282    evas_common_rectangle_draw_do(op->rects, &info->area, dst, &(context),
283                                  op->op.rect.x, op->op.rect.y,
284                                  op->op.rect.w, op->op.rect.h);
285 }
286
287 static Eina_Bool
288 evas_common_pipe_rectangle_prepare(void *data, RGBA_Image *dst, RGBA_Pipe_Op *op)
289 {
290    Cutout_Rects *recycle;
291    Thinfo *info = data;
292    Eina_Bool r;
293
294    recycle = evas_pipe_cutout_rects_pop(info);
295    r = evas_common_rectangle_draw_prepare(recycle, dst, &(op->context),
296                                           op->op.rect.x, op->op.rect.y,
297                                           op->op.rect.w, op->op.rect.h);
298    if (recycle->active) op->rects = recycle;
299    else evas_pipe_cutout_rects_push(info, recycle);
300
301    return r;
302 }
303
304 EAPI void
305 evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, int w, int h)
306 {
307    RGBA_Pipe_Op *op;
308
309    if ((w < 1) || (h < 1)) return;
310    dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
311    if (!dst->cache_entry.pipe) return;
312    op->op.rect.x = x;
313    op->op.rect.y = y;
314    op->op.rect.w = w;
315    op->op.rect.h = h;
316    op->op_func = evas_common_pipe_rectangle_draw_do;
317    op->free_func = evas_common_pipe_op_free;
318    op->prepare_func = evas_common_pipe_rectangle_prepare;
319    evas_pipe_prepare_push(op);
320    evas_common_pipe_draw_context_copy(dc, op);
321 }
322
323 /**************** LINE ******************/
324 static void
325 evas_common_pipe_line_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
326 {
327    RGBA_Draw_Context context;
328
329    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
330    evas_common_draw_context_clip_clip(&(context), info->area.x, info->area.y, info->area.w, info->area.h);
331    evas_common_line_draw(dst, &(context),
332                          op->op.line.x0, op->op.line.y0,
333                          op->op.line.x1, op->op.line.y1);
334 }
335
336 EAPI void
337 evas_common_pipe_line_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
338                            int x0, int y0, int x1, int y1)
339 {
340    RGBA_Pipe_Op *op;
341
342    dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
343    if (!dst->cache_entry.pipe) return;
344    op->op.line.x0 = x0;
345    op->op.line.y0 = y0;
346    op->op.line.x1 = x1;
347    op->op.line.y1 = y1;
348    op->op_func = evas_common_pipe_line_draw_do;
349    op->free_func = evas_common_pipe_op_free;
350    op->prepare_func = NULL;
351    op->render = EINA_TRUE;
352    evas_common_pipe_draw_context_copy(dc, op);
353 }
354
355 /**************** POLY ******************/
356 static void
357 evas_common_pipe_op_poly_free(RGBA_Pipe_Op *op)
358 {
359 #if 0
360    RGBA_Polygon_Point *p;
361
362    while (op->op.poly.points)
363      {
364         p = op->op.poly.points;
365         op->op.poly.points = (RGBA_Polygon_Point *)eina_inlist_remove(EINA_INLIST_GET(op->op.poly.points),
366                                                       EINA_INLIST_GET(p));
367         free(p);
368      }
369 #endif
370    evas_common_pipe_op_free(op);
371 }
372
373 static void
374 evas_common_pipe_poly_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
375 {
376    RGBA_Draw_Context context;
377
378    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
379    evas_common_draw_context_clip_clip(&(context), info->area.x, info->area.y, info->area.w, info->area.h);
380    evas_common_polygon_draw(dst, &(context),
381                             op->op.poly.points, op->op.poly.x, op->op.poly.y);
382 }
383
384 EAPI void
385 evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
386                            RGBA_Polygon_Point *points, int x, int y)
387 {
388    RGBA_Pipe_Op *op;
389    /* RGBA_Polygon_Point *pts = NULL, *p, *pp; */
390
391    if (!points) return;
392    dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
393    if (!dst->cache_entry.pipe) return;
394    /* FIXME: copy points - maybe we should refcount? */
395 #if 0
396    for (p = points; p; p = (RGBA_Polygon_Point *)(EINA_INLIST_GET(p))->next)
397      {
398         pp = calloc(1, sizeof(RGBA_Polygon_Point));
399         if (pp)
400           {
401              pp->x = p->x + x;
402              pp->y = p->y + y;
403              pts = (RGBA_Polygon_Point *)eina_inlist_append(EINA_INLIST_GET(pts), EINA_INLIST_GET(pp));
404           }
405      }
406 #endif
407    op->op.poly.x = x;
408    op->op.poly.y = y;
409    op->op.poly.points = points/* pts */;
410    op->op_func = evas_common_pipe_poly_draw_do;
411    op->free_func = evas_common_pipe_op_poly_free;
412    op->render = EINA_TRUE;
413    op->prepare_func = NULL; /* FIXME: If we really want to improve it, we should prepare span for it here */
414    evas_common_pipe_draw_context_copy(dc, op);
415 }
416
417 /**************** TEXT ******************/
418 static void
419 evas_common_pipe_op_text_free(RGBA_Pipe_Op *op)
420 {
421    evas_common_text_props_content_unref(op->op.text.intl_props);
422    evas_common_pipe_op_free(op);
423 }
424
425 static void
426 evas_common_pipe_text_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
427 {
428    RGBA_Draw_Context context;
429
430    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
431    evas_common_font_draw_do(op->rects, &info->area, op->op.text.func, dst, &(context), op->op.text.x, op->op.text.y, op->op.text.intl_props);
432 }
433
434 static Eina_Bool
435 evas_common_pipe_text_draw_prepare(void *data, RGBA_Image *dst, RGBA_Pipe_Op *op)
436 {
437    Cutout_Rects *recycle;
438    Thinfo *info = data;
439    Eina_Bool r;
440
441    recycle = evas_pipe_cutout_rects_pop(info);
442    r = evas_common_font_draw_prepare_cutout(recycle, dst, &(op->context),
443                                             &(op->op.text.func));
444    if (recycle->active) op->rects = recycle;
445    else evas_pipe_cutout_rects_push(info, recycle);
446
447    return r;
448 }
449
450 EAPI void
451 evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
452                            int x, int y, Evas_Text_Props *intl_props)
453 {
454    RGBA_Pipe_Op *op;
455
456    dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
457    if (!dst->cache_entry.pipe) return;
458    op->op.text.x = x;
459    op->op.text.y = y;
460    op->op.text.intl_props = intl_props;
461    evas_common_text_props_content_ref(intl_props);
462    op->op_func = evas_common_pipe_text_draw_do;
463    op->free_func = evas_common_pipe_op_text_free;
464    op->prepare_func = evas_common_pipe_text_draw_prepare;
465    evas_pipe_prepare_push(op);
466    evas_common_pipe_draw_context_copy(dc, op);
467    evas_common_pipe_text_prepare(intl_props);
468 }
469
470 /**************** IMAGE *****************/
471 static void
472 evas_common_pipe_op_image_free(RGBA_Pipe_Op *op)
473 {
474    op->op.image.src->ref--;
475    if (op->op.image.src->ref == 0)
476      {
477         evas_cache_image_drop(&op->op.image.src->cache_entry);
478      }
479    evas_common_pipe_op_free(op);
480 }
481
482 static Eina_Bool
483 evas_common_pipe_op_image_prepare(void *data, RGBA_Image *dst, RGBA_Pipe_Op *op)
484 {
485    Cutout_Rects *recycle;
486    Thinfo *info = data;
487    Eina_Bool r;
488
489    recycle = evas_pipe_cutout_rects_pop(info);
490    r = evas_common_scale_rgba_in_to_out_clip_prepare(recycle,
491                                                      op->op.image.src, dst,
492                                                      &(op->context),
493                                                      op->op.image.dx, op->op.image.dy,
494                                                      op->op.image.dw, op->op.image.dh);
495    if (recycle->active) op->rects = recycle;
496    else evas_pipe_cutout_rects_push(info, recycle);
497
498    return r;
499 }
500
501 static void
502 evas_common_pipe_image_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
503 {
504    RGBA_Draw_Context context;
505
506    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
507
508 #ifdef SCALECACHE
509    /* FIXME: Make the scalecache path use the prepared Cutout ? */
510    evas_common_draw_context_clip_clip(&(context), info->area.x, info->area.y, info->area.w, info->area.h);
511    evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src),
512                                         dst, &(context),
513                                         op->op.image.smooth,
514                                         op->op.image.sx,
515                                         op->op.image.sy,
516                                         op->op.image.sw,
517                                         op->op.image.sh,
518                                         op->op.image.dx,
519                                         op->op.image.dy,
520                                         op->op.image.dw,
521                                         op->op.image.dh);
522 #else
523    if (op->op.image.smooth)
524      {
525         evas_common_scale_rgba_in_to_out_clip_smooth_do(op->rects, &info->area,
526                                                         op->op.image.src,
527                                                         dst, &(context),
528                                                         op->op.image.sx,
529                                                         op->op.image.sy,
530                                                         op->op.image.sw,
531                                                         op->op.image.sh,
532                                                         op->op.image.dx,
533                                                         op->op.image.dy,
534                                                         op->op.image.dw,
535                                                         op->op.image.dh);
536      }
537    else
538      {
539         evas_common_scale_rgba_in_to_out_clip_sample_do(op->rects, &info->area,
540                                                         op->op.image.src,
541                                                         dst, &(context),
542                                                         op->op.image.sx,
543                                                         op->op.image.sy,
544                                                         op->op.image.sw,
545                                                         op->op.image.sh,
546                                                         op->op.image.dx,
547                                                         op->op.image.dy,
548                                                         op->op.image.dw,
549                                                         op->op.image.dh);
550      }
551 #endif
552 }
553
554 EAPI void
555 evas_common_pipe_image_draw(RGBA_Image *src, RGBA_Image *dst,
556                            RGBA_Draw_Context *dc, int smooth,
557                            int src_region_x, int src_region_y,
558                            int src_region_w, int src_region_h,
559                            int dst_region_x, int dst_region_y,
560                            int dst_region_w, int dst_region_h)
561 {
562    RGBA_Pipe_Op *op;
563
564    if (!src) return;
565 //   evas_common_pipe_flush(src);
566    dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
567    if (!dst->cache_entry.pipe) return;
568    op->op.image.smooth = smooth;
569    op->op.image.sx = src_region_x;
570    op->op.image.sy = src_region_y;
571    op->op.image.sw = src_region_w;
572    op->op.image.sh = src_region_h;
573    op->op.image.dx = dst_region_x;
574    op->op.image.dy = dst_region_y;
575    op->op.image.dw = dst_region_w;
576    op->op.image.dh = dst_region_h;
577    src->ref++;
578    op->op.image.src = src;
579    op->op_func = evas_common_pipe_image_draw_do;
580    op->free_func = evas_common_pipe_op_image_free;
581    op->prepare_func = evas_common_pipe_op_image_prepare;
582    evas_pipe_prepare_push(op);
583    evas_common_pipe_draw_context_copy(dc, op);
584
585    evas_common_pipe_image_load(src);
586 }
587
588 static void
589 evas_common_pipe_op_map_free(RGBA_Pipe_Op *op)
590 {
591    op->op.map.src->ref--;
592    if (op->op.map.src->ref == 0)
593      evas_cache_image_drop(&op->op.map.src->cache_entry);
594    /* free(op->op.map.p); */
595    evas_common_pipe_op_free(op);
596 }
597
598 static void
599 evas_common_pipe_map_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
600 {
601    RGBA_Draw_Context context;
602
603    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
604    evas_common_map_rgba_do(&info->area, op->op.map.src, dst,
605                            &context, op->op.map.m,
606                            op->op.map.smooth, op->op.map.level);
607 }
608
609 static Eina_Bool
610 evas_common_pipe_map_draw_prepare(void *data, RGBA_Image *dst, RGBA_Pipe_Op *op)
611 {
612    RGBA_Draw_Context context;
613    Thinfo *info = data; 
614    Eina_Bool r; 
615
616    memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
617    r = evas_common_map_rgba_prepare(op->op.map.src, dst,
618                                     &context, op->op.map.m);
619
620    return r;
621 }
622
623 EAPI void
624 evas_common_pipe_map_draw(RGBA_Image *src, RGBA_Image *dst,
625                           RGBA_Draw_Context *dc, RGBA_Map *m,
626                           int smooth, int level)
627 {
628    RGBA_Pipe_Op *op;
629    /* RGBA_Map_Point *pts_copy; */
630    int i;
631
632    if (!src) return;
633    /* pts_copy = malloc(sizeof (RGBA_Map_Point) * 4); */
634    /* if (!pts_copy) return; */
635    dst->cache_entry.pipe = evas_common_pipe_add(dst->cache_entry.pipe, &op);
636    if (!dst->cache_entry.pipe) 
637      {
638        /* free(pts_copy); */
639        return; 
640      }
641
642    /* for (i = 0; i < 4; ++i) */
643    /*   pts_copy[i] = p[i]; */
644
645    op->op.map.smooth = smooth;
646    op->op.map.level = level;
647    src->ref++;
648    op->op.map.src = src;
649    op->op.map.m = m;
650    op->op_func = evas_common_pipe_map_draw_do;
651    op->free_func = evas_common_pipe_op_map_free;
652    op->prepare_func = evas_common_pipe_map_draw_prepare;
653    evas_pipe_prepare_push(op);
654    evas_common_pipe_draw_context_copy(dc, op);
655
656    evas_common_pipe_image_load(src);
657 }
658
659 static void
660 evas_common_pipe_map_render(RGBA_Image *root)
661 {
662   RGBA_Pipe *p;
663   int i;
664
665   /* Map imply that we need to process them recursively first. */
666   for (p = root->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
667     {
668       for (i = 0; i < p->op_num; i++)
669         {
670           if (p->op[i].op_func == evas_common_pipe_map_draw_do)
671             {
672               if (p->op[i].op.map.src->cache_entry.pipe)
673                 evas_common_pipe_map_render(p->op[i].op.map.src);
674             }
675           else if (p->op[i].op_func == evas_common_pipe_image_draw_do)
676             {
677               if (p->op[i].op.image.src->cache_entry.pipe)
678                 evas_common_pipe_map_render(p->op[i].op.image.src);
679             }
680         }
681     }
682
683   evas_common_pipe_begin(root);
684   evas_common_pipe_flush(root);
685 }
686
687 #ifdef BUILD_PTHREAD
688 static void*
689 evas_common_pipe_load(void *data)
690 {
691   Thinfo *tinfo;
692
693   tinfo = data;
694   for (;;)
695     {
696       RGBA_Pipe_Op *op;
697       Eina_Array_Iterator it;
698       unsigned int i;
699       /* wait for start signal */
700       pthread_barrier_wait(&(tinfo->barrier[0]));
701
702       while (im_task)
703         {
704           RGBA_Image *im = NULL;
705
706           LKL(im_task_mutex);
707           im = eina_list_data_get(im_task);
708           im_task = eina_list_remove_list(im_task, im_task);
709           LKU(im_task_mutex);
710
711           if (im)
712             {
713               if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
714                 evas_cache_image_load_data(&im->cache_entry);
715               evas_common_image_colorspace_normalize(im);
716
717               im->flags &= ~RGBA_IMAGE_TODO_LOAD;
718             }
719         }
720
721       while (text_task)
722         {
723            Evas_Text_Props *text_props;
724            RGBA_Font_Int *fi;
725
726            LKL(text_task_mutex);
727            fi = eina_list_data_get(text_task);
728            text_task = eina_list_remove_list(text_task, text_task);
729            LKU(text_task_mutex);
730
731            if (fi)
732              {
733                 LKL(fi->ft_mutex);
734                 EINA_LIST_FREE(fi->task, text_props)
735                   {
736                      evas_common_font_draw_prepare(text_props);
737                      text_props->changed = EINA_FALSE;
738                      text_props->prepare = EINA_FALSE;
739                   }
740                 LKU(fi->ft_mutex);
741              }
742         }
743
744       EINA_ARRAY_ITER_NEXT(&tinfo->rects_task, i, op, it)
745         op->render = op->prepare_func(tinfo, tinfo->im, op);
746       eina_array_clean(&tinfo->rects_task);
747
748       /* send finished signal */
749       pthread_barrier_wait(&(tinfo->barrier[1]));
750     }
751
752   return NULL;
753 }
754 #endif
755
756 static volatile int bval = 0;
757
758 static void
759 evas_common_pipe_load_do(RGBA_Image *im)
760 {
761 #ifdef BUILD_PTHREAD
762    int i;
763
764    for (i = 0; i < thread_num; i++)
765      task_thinfo[i].im = im;
766
767    /* Notify worker thread. */
768    pthread_barrier_wait(&(task_thbarrier[0]));
769
770    /* sync worker threads */
771    pthread_barrier_wait(&(task_thbarrier[1]));
772 #endif
773 }
774
775 EAPI void
776 evas_common_pipe_image_load(RGBA_Image *im)
777 {
778   if (im->flags & RGBA_IMAGE_TODO_LOAD)
779     return ;
780
781   if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888
782       && !evas_cache_image_is_loaded(&(im->cache_entry)))
783     goto add_task;
784
785   if (!((!im->cs.data) || ((!im->cs.dirty) && (!(im->flags & RGBA_IMAGE_IS_DIRTY)))))
786     goto add_task;
787
788   return ;
789
790  add_task:
791   LKL(im_task_mutex);
792   im_task = eina_list_append(im_task, im);
793   LKU(im_task_mutex);
794   im->flags |= RGBA_IMAGE_TODO_LOAD;
795 }
796
797 EAPI void
798 evas_common_pipe_text_prepare(Evas_Text_Props *text_props)
799 {
800    RGBA_Font_Int *fi;
801
802    fi = text_props->font_instance;
803    if (!fi) return ;
804
805    if (!text_props->changed && text_props->generation == fi->generation && text_props->glyphs)
806      return ;
807
808    LKL(fi->ft_mutex);
809
810    if (!fi->task)
811      {
812        LKL(text_task_mutex);
813        text_task = eina_list_append(text_task, fi);
814        LKU(text_task_mutex);
815      }
816
817    if (text_props->prepare) goto end;
818    text_props->prepare = EINA_TRUE;
819    fi->task = eina_list_append(fi->task, text_props);
820
821  end:
822    LKU(fi->ft_mutex);
823 }
824
825 EAPI void
826 evas_common_pipe_map_begin(RGBA_Image *root)
827 {
828   if (!evas_common_pipe_init())
829     {
830       RGBA_Image *im;
831
832       EINA_LIST_FREE(im_task, im)
833         {
834           if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
835             evas_cache_image_load_data(&im->cache_entry);
836           evas_common_image_colorspace_normalize(im);
837
838           im->flags &= ~RGBA_IMAGE_TODO_LOAD;
839         }
840     }
841
842   evas_common_pipe_load_do(root);
843
844   evas_common_pipe_map_render(root);
845 }
846 #endif
847
848 EAPI Eina_Bool
849 evas_common_pipe_init(void)
850 {
851 #ifdef BUILD_PIPE_RENDER
852    if (thread_num == 0)
853      {
854         int cpunum;
855         int i;
856
857         cpunum = eina_cpu_count();
858         thread_num = cpunum;
859 // on  single cpu we still want this initted.. otherwise we block forever
860 // waiting onm pthread barriers for async rendering on a single core!
861 //      if (thread_num == 1) return EINA_FALSE;
862
863         eina_threads_init();
864
865         LKI(im_task_mutex);
866         LKI(text_task_mutex);
867
868         pthread_barrier_init(&(thbarrier[0]), NULL, thread_num + 1);
869         pthread_barrier_init(&(thbarrier[1]), NULL, thread_num + 1);
870         for (i = 0; i < thread_num; i++)
871           {
872              pthread_attr_t attr;
873              cpu_set_t cpu;
874
875              pthread_attr_init(&attr);
876              CPU_ZERO(&cpu);
877              CPU_SET(i % cpunum, &cpu);
878              pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
879              thinfo[i].thread_num = i;
880              thinfo[i].tasks = NULL;
881              thinfo[i].barrier = thbarrier;
882              /* setup initial locks */
883              pthread_create(&(thinfo[i].thread_id), &attr,
884                             evas_common_pipe_thread, &(thinfo[i]));
885              pthread_attr_destroy(&attr);
886           }
887
888         pthread_barrier_init(&(task_thbarrier[0]), NULL, thread_num + 1);
889         pthread_barrier_init(&(task_thbarrier[1]), NULL, thread_num + 1);
890         for (i = 0; i < thread_num; i++)
891           {
892              pthread_attr_t attr;
893              cpu_set_t cpu;
894
895              pthread_attr_init(&attr);
896              CPU_ZERO(&cpu);
897              CPU_SET(i % cpunum, &cpu);
898              pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
899              task_thinfo[i].thread_num = i;
900              task_thinfo[i].tasks = NULL;
901              task_thinfo[i].barrier = task_thbarrier;
902              eina_array_step_set(&task_thinfo[i].cutout_trash, sizeof (Eina_Array), 8);
903              eina_array_step_set(&task_thinfo[i].rects_task, sizeof (Eina_Array), 8);
904              /* setup initial locks */
905              pthread_create(&(task_thinfo[i].thread_id), &attr,
906                             evas_common_pipe_load, &(task_thinfo[i]));
907              pthread_attr_destroy(&attr);
908           }
909      }
910
911    if (thread_num == 1) return EINA_FALSE;
912    return EINA_TRUE;
913 #endif
914    return EINA_FALSE;
915 }