move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_pipe.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include "evas_common.h"
6
7 static RGBA_Pipe *evas_common_pipe_add(RGBA_Pipe *pipe, RGBA_Pipe_Op **op);
8 static void evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op);
9 static void evas_common_pipe_op_free(RGBA_Pipe_Op *op);
10
11 /* utils */
12 static RGBA_Pipe *
13 evas_common_pipe_add(RGBA_Pipe *pipe, RGBA_Pipe_Op **op)
14 {
15    RGBA_Pipe *p;
16    int first_pipe = 0;
17
18    if (!pipe)
19      {
20         first_pipe = 1;
21         p = calloc(1, sizeof(RGBA_Pipe));
22         if (!p) return NULL;
23         pipe = evas_object_list_append(pipe, p);
24      }
25    p = (RGBA_Pipe *)((Evas_Object_List *)pipe)->last;
26    if (p->op_num == PIPE_LEN)
27      {
28         p = calloc(1, sizeof(RGBA_Pipe));
29         if (!p) return NULL;
30         pipe = evas_object_list_append(pipe, p);
31      }
32    p->op_num++;
33    *op = &(p->op[p->op_num - 1]);
34    if (first_pipe)
35      {
36         /* FIXME: PTHREAD init any thread locks etc */
37      }
38    return pipe;
39 }
40
41 static void
42 evas_common_pipe_draw_context_copy(RGBA_Draw_Context *dc, RGBA_Pipe_Op *op)
43 {
44    memcpy(&(op->context), dc, sizeof(RGBA_Draw_Context));
45    if (op->context.cutout.active > 0)
46      {
47         op->context.cutout.rects = malloc(sizeof(Cutout_Rect) * op->context.cutout.active);
48         memcpy(op->context.cutout.rects, dc->cutout.rects, sizeof(Cutout_Rect) * op->context.cutout.active);
49      }
50    else
51      op->context.cutout.rects = NULL;
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 /* main api calls */
61 #ifdef BUILD_PTHREAD
62 typedef struct _Thinfo
63 {
64    int                    thread_num;
65    pthread_t              thread_id;
66    pthread_barrier_t     *barrier;
67    RGBA_Pipe_Thread_Info *info;
68 } Thinfo;
69
70 static void *
71 evas_common_pipe_thread(void *data)
72 {
73    Thinfo *thinfo;
74
75 //   printf("TH [...........\n");
76    thinfo = data;
77    for (;;)
78      {
79         RGBA_Pipe_Thread_Info *info;
80         RGBA_Pipe *p;
81
82         /* wait for start signal */
83 //      printf(" TH %i START...\n", thinfo->thread_num);
84         pthread_barrier_wait(&(thinfo->barrier[0]));
85         info = thinfo->info;
86 //      if (info)
87 //        {
88 //           thinfo->info = NULL;
89 //           printf(" TH %i GO\n", thinfo->thread_num);
90              for (p = info->im->pipe; p; p = (RGBA_Pipe *)((Evas_Object_List *)p)->next)
91                {
92                   int i;
93
94                   for (i = 0; i < p->op_num; i++)
95                     {
96                        if (p->op[i].op_func)
97                          p->op[i].op_func(info->im, &(p->op[i]), info);
98                     }
99                }
100              free(info);
101 //        }
102 //      printf(" TH %i DONE\n", thinfo->thread_num);
103         /* send finished signal */
104         pthread_barrier_wait(&(thinfo->barrier[1]));
105      }
106    return NULL;
107 }
108 #endif
109
110 #ifdef BUILD_PTHREAD
111 static int               thread_num = 0;
112 static Thinfo            thinfo[TH_MAX];
113 static pthread_barrier_t thbarrier[2];
114 #endif
115
116 EAPI void
117 evas_common_pipe_begin(RGBA_Image *im)
118 {
119 #ifdef BUILD_PTHREAD
120    int i, y, h;
121
122    if (!im->pipe) return;
123    if (thread_num == 1) return;
124    if (thread_num == 0)
125      {
126         int cpunum;
127
128         cpunum = evas_common_cpu_count();
129         thread_num = cpunum;
130         if (thread_num == 1) return;
131         pthread_barrier_init(&(thbarrier[0]), NULL, thread_num + 1);
132         pthread_barrier_init(&(thbarrier[1]), NULL, thread_num + 1);
133         for (i = 0; i < thread_num; i++)
134           {
135              pthread_attr_t attr;
136              cpu_set_t cpu;
137
138              pthread_attr_init(&attr);
139              CPU_ZERO(&cpu);
140              CPU_SET(i % cpunum, &cpu);
141              pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
142              thinfo[i].thread_num = i;
143              thinfo[i].info = NULL;
144              thinfo[i].barrier = thbarrier;
145              /* setup initial locks */
146              pthread_create(&(thinfo[i].thread_id), &attr,
147                             evas_common_pipe_thread, &(thinfo[i]));
148              pthread_attr_destroy(&attr);
149           }
150      }
151    y = 0;
152    h = im->cache_entry.h / thread_num;
153    if (h < 1) h = 1;
154    for (i = 0; i < thread_num; i++)
155      {
156         RGBA_Pipe_Thread_Info *info;
157
158 //           if (y >= im->cache_entry.h) break;
159         info = calloc(1, sizeof(RGBA_Pipe_Thread_Info));
160         info->im = im;
161 #ifdef EVAS_SLI
162         info->x = 0;
163         info->w = im->cache_entry.w;
164         info->y = i;
165         info->h = thread_num;
166 #else
167         info->x = 0;
168         info->y = y;
169         info->w = im->cache_entry.w;
170         if (i == (thread_num - 1))
171           info->h = im->cache_entry.h - y;
172         else
173           info->h = h;
174         y += info->h;
175 #endif
176         thinfo[i].info = info;
177      }
178    /* tell worker threads to start */
179    pthread_barrier_wait(&(thbarrier[0]));
180 #endif
181 }
182
183 EAPI void
184 evas_common_pipe_flush(RGBA_Image *im)
185 {
186
187    RGBA_Pipe *p;
188    int i;
189
190    if (!im->pipe) return;
191 #ifdef BUILD_PTHREAD
192    if (thread_num > 1)
193      {
194         /* sync worker threads */
195         pthread_barrier_wait(&(thbarrier[1]));
196      }
197    else
198 #endif
199      {
200         /* process pipe - 1 thead */
201         for (p = im->pipe; p; p = (RGBA_Pipe *)((Evas_Object_List *)p)->next)
202           {
203              for (i = 0; i < p->op_num; i++)
204                {
205                   if (p->op[i].op_func)
206                     p->op[i].op_func(im, &(p->op[i]), NULL);
207                }
208           }
209      }
210    evas_common_cpu_end_opt();
211    evas_common_pipe_free(im);
212 }
213
214 EAPI void
215 evas_common_pipe_free(RGBA_Image *im)
216 {
217
218    RGBA_Pipe *p;
219    int i;
220
221    if (!im->pipe) return;
222    /* FIXME: PTHREAD join all threads here (if not finished) */
223
224    /* free pipe */
225    while (im->pipe)
226      {
227         p = im->pipe;
228         for (i = 0; i < p->op_num; i++)
229           {
230              if (p->op[i].free_func)
231                p->op[i].free_func(&(p->op[i]));
232           }
233         im->pipe = evas_object_list_remove(im->pipe, p);
234         free(p);
235      }
236 }
237
238
239
240 /* draw ops */
241 /**************** RECT ******************/
242 static void
243 evas_common_pipe_rectangle_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
244 {
245    if (info)
246      {
247         RGBA_Draw_Context context;
248
249         memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
250 #ifdef EVAS_SLI
251         evas_common_draw_context_set_sli(&(context), info->y, info->h);
252 #else
253         evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
254 #endif
255         evas_common_rectangle_draw(dst, &(context),
256                                    op->op.rect.x, op->op.rect.y,
257                                    op->op.rect.w, op->op.rect.h);
258      }
259    else
260      evas_common_rectangle_draw(dst, &(op->context),
261                                 op->op.rect.x, op->op.rect.y,
262                                 op->op.rect.w, op->op.rect.h);
263 }
264
265 EAPI void
266 evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
267                                 int x, int y, int w, int h)
268 {
269    RGBA_Pipe_Op *op;
270
271    if ((w < 1) || (h < 1)) return;
272    dst->pipe = evas_common_pipe_add(dst->pipe, &op);
273    if (!dst->pipe) return;
274    op->op.rect.x = x;
275    op->op.rect.y = y;
276    op->op.rect.w = w;
277    op->op.rect.h = h;
278    op->op_func = evas_common_pipe_rectangle_draw_do;
279    op->free_func = evas_common_pipe_op_free;
280    evas_common_pipe_draw_context_copy(dc, op);
281 }
282
283 /**************** LINE ******************/
284 static void
285 evas_common_pipe_line_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
286 {
287    if (info)
288      {
289         RGBA_Draw_Context context;
290
291         memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
292 #ifdef EVAS_SLI
293         evas_common_draw_context_set_sli(&(context), info->y, info->h);
294 #else
295         evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
296 #endif
297         evas_common_line_draw(dst, &(context),
298                               op->op.line.x0, op->op.line.y0,
299                               op->op.line.x1, op->op.line.y1);
300      }
301    else
302      evas_common_line_draw(dst, &(op->context),
303                            op->op.line.x0, op->op.line.y0,
304                            op->op.line.x1, op->op.line.y1);
305 }
306
307 EAPI void
308 evas_common_pipe_line_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
309                            int x0, int y0, int x1, int y1)
310 {
311    RGBA_Pipe_Op *op;
312
313    dst->pipe = evas_common_pipe_add(dst->pipe, &op);
314    if (!dst->pipe) return;
315    op->op.line.x0 = x0;
316    op->op.line.y0 = y0;
317    op->op.line.x1 = x1;
318    op->op.line.y1 = y1;
319    op->op_func = evas_common_pipe_line_draw_do;
320    op->free_func = evas_common_pipe_op_free;
321    evas_common_pipe_draw_context_copy(dc, op);
322 }
323
324 /**************** POLY ******************/
325 static void
326 evas_common_pipe_op_poly_free(RGBA_Pipe_Op *op)
327 {
328    RGBA_Polygon_Point *p;
329
330    while (op->op.poly.points)
331      {
332         p = op->op.poly.points;
333         op->op.poly.points = evas_object_list_remove(op->op.poly.points, p);
334         free(p);
335      }
336    evas_common_pipe_op_free(op);
337 }
338
339 static void
340 evas_common_pipe_poly_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
341 {
342    if (info)
343      {
344         RGBA_Draw_Context context;
345
346         memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
347 #ifdef EVAS_SLI
348         evas_common_draw_context_set_sli(&(context), info->y, info->h);
349 #else
350         evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
351 #endif
352         evas_common_polygon_draw(dst, &(context),
353                                  op->op.poly.points);
354      }
355    else
356      evas_common_polygon_draw(dst, &(op->context),
357                               op->op.poly.points);
358 }
359
360 EAPI void
361 evas_common_pipe_poly_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
362                            RGBA_Polygon_Point *points)
363 {
364    RGBA_Pipe_Op *op;
365    RGBA_Polygon_Point *pts = NULL, *p, *pp;
366
367    if (!points) return;
368    dst->pipe = evas_common_pipe_add(dst->pipe, &op);
369    if (!dst->pipe) return;
370    /* FIXME: copy points - maybe we should refcount? */
371    for (p = points; p; p = (RGBA_Polygon_Point *)((Evas_Object_List *)p)->next)
372      {
373         pp = calloc(1, sizeof(RGBA_Polygon_Point));
374         if (pp)
375           {
376              pp->x = p->x;
377              pp->y = p->y;
378              pts = evas_object_list_append(pts, pp);
379           }
380      }
381    op->op.poly.points = pts;
382    op->op_func = evas_common_pipe_poly_draw_do;
383    op->free_func = evas_common_pipe_op_poly_free;
384    evas_common_pipe_draw_context_copy(dc, op);
385 }
386
387 /**************** GRAD ******************/
388 static void
389 evas_common_pipe_op_grad_free(RGBA_Pipe_Op *op)
390 {
391    evas_common_gradient_free(op->op.grad.grad);
392    evas_common_pipe_op_free(op);
393 }
394
395 static void
396 evas_common_pipe_grad_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
397 {
398    if (info)
399      {
400         RGBA_Draw_Context context;
401
402         memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
403 #ifdef EVAS_SLI
404         evas_common_draw_context_set_sli(&(context), info->y, info->h);
405 #else
406         evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
407 #endif
408         evas_common_gradient_draw(dst, &(context),
409                                   op->op.grad.x, op->op.grad.y,
410                                   op->op.grad.w, op->op.grad.h,
411                                   op->op.grad.grad);
412      }
413    else
414      evas_common_gradient_draw(dst, &(op->context),
415                                op->op.grad.x, op->op.grad.y,
416                                op->op.grad.w, op->op.grad.h,
417                                op->op.grad.grad);
418 }
419
420 EAPI void
421 evas_common_pipe_grad_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
422                            int x, int y, int w, int h, RGBA_Gradient *gr)
423 {
424    RGBA_Pipe_Op *op;
425
426    if (!gr) return;
427    dst->pipe = evas_common_pipe_add(dst->pipe, &op);
428    if (!dst->pipe) return;
429    op->op.grad.x = x;
430    op->op.grad.y = y;
431    op->op.grad.w = w;
432    op->op.grad.h = h;
433    gr->references++;
434    op->op.grad.grad = gr;
435    op->op_func = evas_common_pipe_grad_draw_do;
436    op->free_func = evas_common_pipe_op_grad_free;
437    evas_common_pipe_draw_context_copy(dc, op);
438 }
439
440 /**************** TEXT ******************/
441 static void
442 evas_common_pipe_op_text_free(RGBA_Pipe_Op *op)
443 {
444    evas_common_font_free(op->op.text.font);
445    free(op->op.text.text);
446    evas_common_pipe_op_free(op);
447 }
448
449 static void
450 evas_common_pipe_text_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
451 {
452    if (info)
453      {
454         RGBA_Draw_Context context;
455
456         memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
457 #ifdef EVAS_SLI
458         evas_common_draw_context_set_sli(&(context), info->y, info->h);
459 #else
460         evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
461 #endif
462         evas_common_font_draw(dst, &(context),
463                               op->op.text.font, op->op.text.x, op->op.text.y,
464                               op->op.text.text);
465      }
466    else
467      evas_common_font_draw(dst, &(op->context),
468                            op->op.text.font, op->op.text.x, op->op.text.y,
469                            op->op.text.text);
470 }
471
472 EAPI void
473 evas_common_pipe_text_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
474                            RGBA_Font *fn, int x, int y, const char *text)
475 {
476    RGBA_Pipe_Op *op;
477
478    if ((!fn) || (!text)) return;
479    dst->pipe = evas_common_pipe_add(dst->pipe, &op);
480    if (!dst->pipe) return;
481    op->op.text.x = x;
482    op->op.text.y = y;
483    op->op.text.text = strdup(text);
484    fn->references++;
485    op->op.text.font = fn;
486    op->op_func = evas_common_pipe_text_draw_do;
487    op->free_func = evas_common_pipe_op_text_free;
488    evas_common_pipe_draw_context_copy(dc, op);
489 }
490
491 /**************** IMAGE *****************/
492 static void
493 evas_common_pipe_op_image_free(RGBA_Pipe_Op *op)
494 {
495    op->op.image.src->ref--;
496    if (op->op.image.src->ref == 0)
497      evas_cache_image_drop(&op->op.image.src->cache_entry);
498    evas_common_pipe_op_free(op);
499 }
500
501 static void
502 evas_common_pipe_image_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
503 {
504    if (info)
505      {
506         RGBA_Draw_Context context;
507
508         memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
509 #ifdef EVAS_SLI
510         evas_common_draw_context_set_sli(&(context), info->y, info->h);
511 #else
512         evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
513 #endif
514         if (op->op.image.smooth)
515           evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
516                                                        dst, &(context),
517                                                        op->op.image.sx,
518                                                        op->op.image.sy,
519                                                        op->op.image.sw,
520                                                        op->op.image.sh,
521                                                        op->op.image.dx,
522                                                        op->op.image.dy,
523                                                        op->op.image.dw,
524                                                        op->op.image.dh);
525         else
526           evas_common_scale_rgba_in_to_out_clip_sample(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         if (op->op.image.smooth)
540           evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
541                                                        dst, &(op->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         else
551           evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
552                                                        dst, &(op->context),
553                                                        op->op.image.sx,
554                                                        op->op.image.sy,
555                                                        op->op.image.sw,
556                                                        op->op.image.sh,
557                                                        op->op.image.dx,
558                                                        op->op.image.dy,
559                                                        op->op.image.dw,
560                                                        op->op.image.dh);
561      }
562 }
563
564 EAPI void
565 evas_common_pipe_image_draw(RGBA_Image *src, RGBA_Image *dst,
566                            RGBA_Draw_Context *dc, int smooth,
567                            int src_region_x, int src_region_y,
568                            int src_region_w, int src_region_h,
569                            int dst_region_x, int dst_region_y,
570                            int dst_region_w, int dst_region_h)
571 {
572    RGBA_Pipe_Op *op;
573
574    if (!src) return;
575 //   evas_common_pipe_flush(src);
576    dst->pipe = evas_common_pipe_add(dst->pipe, &op);
577    if (!dst->pipe) return;
578    op->op.image.smooth = smooth;
579    op->op.image.sx = src_region_x;
580    op->op.image.sy = src_region_y;
581    op->op.image.sw = src_region_w;
582    op->op.image.sh = src_region_h;
583    op->op.image.dx = dst_region_x;
584    op->op.image.dy = dst_region_y;
585    op->op.image.dw = dst_region_w;
586    op->op.image.dh = dst_region_h;
587    src->ref++;
588    op->op.image.src = src;
589    op->op_func = evas_common_pipe_image_draw_do;
590    op->free_func = evas_common_pipe_op_image_free;
591    evas_common_pipe_draw_context_copy(dc, op);
592 }