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