e_output: substitute e_input APIs for ecore_drm APIs and remove ecore drm dependency
[platform/upstream/enlightenment.git] / src / bin / e_output.c
1 #include "e.h"
2
3 #define DUMP_FPS 30
4
5 typedef struct _E_Output_Capture E_Output_Capture;
6
7 struct _E_Output_Capture
8 {
9    E_Output *output;
10    tdm_capture *tcapture;
11    tbm_surface_h surface;
12    E_Output_Capture_Cb func;
13    void *data;
14    Eina_Bool in_using;
15    Eina_Bool dequeued;
16 };
17
18 static int _e_output_hooks_delete = 0;
19 static int _e_output_hooks_walking = 0;
20
21 static Eina_Inlist *_e_output_hooks[] =
22 {
23    [E_OUTPUT_HOOK_DPMS_CHANGE] = NULL,
24 };
25
26 static Eina_Bool _e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate);
27 static void _e_output_vblank_handler(tdm_output *output, unsigned int sequence,
28                                      unsigned int tv_sec, unsigned int tv_usec, void *data);
29
30
31 static void
32 _e_output_hooks_clean(void)
33 {
34    Eina_Inlist *l;
35    E_Output_Hook *ch;
36    unsigned int x;
37    for (x = 0; x < E_OUTPUT_HOOK_LAST; x++)
38      EINA_INLIST_FOREACH_SAFE(_e_output_hooks[x], l, ch)
39        {
40           if (!ch->delete_me) continue;
41           _e_output_hooks[x] = eina_inlist_remove(_e_output_hooks[x], EINA_INLIST_GET(ch));
42          free(ch);
43        }
44 }
45
46 static void
47 _e_output_hook_call(E_Output_Hook_Point hookpoint, E_Output *output)
48 {
49    E_Output_Hook *ch;
50
51    _e_output_hooks_walking++;
52    EINA_INLIST_FOREACH(_e_output_hooks[hookpoint], ch)
53      {
54         if (ch->delete_me) continue;
55         ch->func(ch->data, output);
56      }
57    _e_output_hooks_walking--;
58    if ((_e_output_hooks_walking == 0) && (_e_output_hooks_delete > 0))
59      _e_output_hooks_clean();
60 }
61
62 static E_Client *
63 _e_output_zoom_top_visible_ec_get()
64 {
65    E_Client *ec;
66    Evas_Object *o;
67    E_Comp_Wl_Client_Data *cdata;
68
69    for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
70      {
71         ec = evas_object_data_get(o, "E_Client");
72
73         /* check e_client and skip e_clients not intersects with zone */
74         if (!ec) continue;
75         if (e_object_is_del(E_OBJECT(ec))) continue;
76         if (e_client_util_ignored_get(ec)) continue;
77         if (ec->iconic) continue;
78         if (ec->visible == 0) continue;
79         if (!(ec->visibility.obscured == 0 || ec->visibility.obscured == 1)) continue;
80         if (!ec->frame) continue;
81         if (!evas_object_visible_get(ec->frame)) continue;
82         /* if ec is subsurface, skip this */
83         cdata = (E_Comp_Wl_Client_Data *)ec->comp_data;
84         if (cdata && cdata->sub.data) continue;
85
86         return ec;
87      }
88
89    return NULL;
90 }
91
92 static int
93 _e_output_zoom_get_angle(E_Output *output)
94 {
95    E_Client *ec = NULL;
96    int angle = 0;
97    int ec_angle = 0;
98
99    ec = _e_output_zoom_top_visible_ec_get();
100    if (ec)
101      ec_angle = ec->e.state.rot.ang.curr;
102
103    angle = (ec_angle + output->config.rotation) % 360;
104
105    return angle;
106 }
107
108 static void
109 _e_output_zoom_coordinate_cal_with_angle(E_Output *output, int angle)
110 {
111    int x, y;
112    int w, h;
113
114    if (angle == 0 || angle == 180)
115      {
116         w = output->config.geom.w;
117         h = output->config.geom.h;
118      }
119    else
120      {
121         w = output->config.geom.h;
122         h = output->config.geom.w;
123      }
124
125    if (angle == output->zoom_conf.init_angle)
126      {
127         if (angle == 0)
128           {
129              output->zoom_conf.adjusted_cx = output->zoom_conf.init_cx;
130              output->zoom_conf.adjusted_cy = output->zoom_conf.init_cy;
131           }
132         else if (angle == 90)
133           {
134              output->zoom_conf.adjusted_cx = output->zoom_conf.init_cy;
135              output->zoom_conf.adjusted_cy = w - output->zoom_conf.init_cx - 1;
136           }
137         else if (angle == 180)
138           {
139              output->zoom_conf.adjusted_cx = w - output->zoom_conf.init_cx - 1;
140              output->zoom_conf.adjusted_cy = h - output->zoom_conf.init_cy - 1;
141           }
142         else /* angle == 270 */
143           {
144              output->zoom_conf.adjusted_cx = h - output->zoom_conf.init_cy - 1;
145              output->zoom_conf.adjusted_cy = output->zoom_conf.init_cx;
146           }
147      }
148    else
149      {
150         if ((angle % 180) == (output->zoom_conf.init_angle % 180)) /* 180 changed from init, don't have to cal ratio */
151           {
152              x = output->zoom_conf.init_cx;
153              y = output->zoom_conf.init_cy;
154           }
155         else /* 90 or 270 changed from init, need ratio cal*/
156           {
157              if (angle == 90 || angle == 270)
158                {
159                   x = (float)output->config.geom.h / output->config.geom.w * output->zoom_conf.init_cx;
160                   y = (float)output->config.geom.w / output->config.geom.h * output->zoom_conf.init_cy;
161                }
162              else /* 0 or 180 */
163                {
164                   x = (float)output->config.geom.w / output->config.geom.h * output->zoom_conf.init_cx;
165                   y = (float)output->config.geom.h / output->config.geom.w * output->zoom_conf.init_cy;
166                }
167           }
168         if (angle == 0)
169           {
170              output->zoom_conf.adjusted_cx = x;
171              output->zoom_conf.adjusted_cy = y;
172           }
173         else if (angle == 90)
174           {
175              output->zoom_conf.adjusted_cx = y;
176              output->zoom_conf.adjusted_cy = w - x - 1;
177           }
178         else if (angle == 180)
179           {
180              output->zoom_conf.adjusted_cx = w - x - 1;
181              output->zoom_conf.adjusted_cy = h - y - 1;
182           }
183         else /* angle == 270 */
184           {
185              output->zoom_conf.adjusted_cx = h - y - 1;
186              output->zoom_conf.adjusted_cy = x;
187           }
188      }
189 }
190
191 static void
192 _e_output_zoom_scaled_rect_get(int out_w, int out_h, double zoomx, double zoomy, int cx, int cy, Eina_Rectangle *rect)
193 {
194    double x, y;
195    double dx, dy;
196
197    rect->w = (int)((double)out_w / zoomx);
198    rect->h = (int)((double)out_h / zoomy);
199
200    x = 0 - cx;
201    y = 0 - cy;
202
203    x = (((double)x) * zoomx);
204    y = (((double)y) * zoomy);
205
206    x = x + cx;
207    y = y + cy;
208
209    if (x == 0)
210      dx = 0;
211    else
212      dx = 0 - x;
213
214    if (y == 0)
215      dy = 0;
216    else
217      dy = 0 - y;
218
219    rect->x = (int)(dx / zoomx);
220    rect->y = (int)(dy / zoomy);
221 }
222
223 static Eina_Bool
224 _e_output_zoom_touch_transform(E_Output *output, Eina_Bool set)
225 {
226    E_Input_Device *dev = NULL;
227    Eina_Bool ret = EINA_FALSE;
228    const Eina_List *l;
229    E_Output *primary_output = NULL;
230    int w = 0, h = 0;
231
232    EINA_LIST_FOREACH(e_input_devices_get(), l, dev)
233      {
234         primary_output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
235         if (primary_output != NULL)
236           break;
237      }
238
239    if (!primary_output)
240      {
241         ERR("fail get primary_output");
242         return EINA_FALSE;
243      }
244
245    if (set)
246      ret = e_input_device_touch_transformation_set(dev,
247                                                      output->zoom_conf.rect.x, output->zoom_conf.rect.y,
248                                                      output->zoom_conf.rect.w, output->zoom_conf.rect.h);
249    else
250      {
251         e_output_size_get(output, &w, &h);
252         ret = e_input_device_touch_transformation_set(dev, 0, 0, w, h);
253      }
254
255    if (ret != EINA_TRUE)
256      ERR("fail e_input_device_touch_transformation_set");
257
258    return ret;
259 }
260
261 static Eina_Bool
262 _e_output_cb_ecore_event_mouse_up(void *data, int type EINA_UNUSED, void *event EINA_UNUSED)
263 {
264    E_Output *output = NULL;
265
266    if (!data)
267      return ECORE_CALLBACK_PASS_ON;
268
269    output = data;
270
271    if (output->zoom_conf.need_touch_set)
272      {
273         if (e_comp_wl->touch.pressed == 0)
274           {
275              _e_output_zoom_touch_transform(output, EINA_TRUE);
276              output->zoom_conf.need_touch_set = EINA_FALSE;
277
278              E_FREE_FUNC(output->touch_up_handler, ecore_event_handler_del);
279           }
280      }
281
282    return ECORE_CALLBACK_PASS_ON;
283 }
284
285 static Eina_Bool
286 _e_output_zoom_touch_set(E_Output *output)
287 {
288    Eina_Bool ret = EINA_FALSE;
289
290    if (output->zoom_conf.need_touch_set) return EINA_TRUE;
291
292    if (e_comp_wl->touch.pressed)
293      {
294         if (output->touch_up_handler == NULL)
295           output->touch_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
296                                                              _e_output_cb_ecore_event_mouse_up, output);
297
298         output->zoom_conf.need_touch_set = EINA_TRUE;
299         return EINA_TRUE;
300      }
301    output->zoom_conf.need_touch_set = EINA_FALSE;
302
303    ret = _e_output_zoom_touch_transform(output, EINA_TRUE);
304
305    return ret;
306 }
307
308 static Eina_Bool
309 _e_output_zoom_touch_unset(E_Output *output)
310 {
311    Eina_Bool ret = EINA_FALSE;
312
313    if (!output) return EINA_FALSE;
314
315    output->zoom_conf.need_touch_set = EINA_FALSE;
316
317    if (output->touch_up_handler)
318      E_FREE_FUNC(output->touch_up_handler, ecore_event_handler_del);
319
320    ret = _e_output_zoom_touch_transform(output, EINA_FALSE);
321
322    return ret;
323 }
324
325 static Eina_Bool
326 _e_output_animating_check()
327 {
328    E_Client *ec = NULL;
329
330    E_CLIENT_FOREACH(ec)
331      {
332         if (ec->visible && !ec->input_only)
333           {
334              if (e_comp_object_is_animating(ec->frame))
335                return EINA_TRUE;
336           }
337      }
338
339    return EINA_FALSE;
340 }
341
342 static void
343 _e_output_render_update(E_Output *output)
344 {
345    E_Client *ec = NULL;
346
347    if (_e_output_animating_check())
348      return;
349
350    E_CLIENT_FOREACH(ec)
351      {
352         if (ec->visible && !ec->input_only)
353           e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
354      }
355
356    e_output_render(output);
357 }
358
359 static void
360 _e_output_zoom_rotate(E_Output *output)
361 {
362    E_Plane *ep = NULL;
363    Eina_List *l;
364    int w, h;
365
366    EINA_SAFETY_ON_NULL_RETURN(output);
367
368    e_output_size_get(output, &w, &h);
369
370    _e_output_zoom_coordinate_cal_with_angle(output, output->zoom_conf.current_angle);
371
372    /* get the scaled rect */
373    _e_output_zoom_scaled_rect_get(w, h, output->zoom_conf.zoomx, output->zoom_conf.zoomy,
374                                   output->zoom_conf.adjusted_cx, output->zoom_conf.adjusted_cy, &output->zoom_conf.rect);
375    DBG("zoom_rect rotate(x:%d,y:%d) (w:%d,h:%d)",
376        output->zoom_conf.rect.x, output->zoom_conf.rect.y, output->zoom_conf.rect.w, output->zoom_conf.rect.h);
377
378    EINA_LIST_FOREACH(output->planes, l, ep)
379      {
380         if (!e_plane_is_fb_target(ep)) continue;
381
382         e_plane_zoom_set(ep, &output->zoom_conf.rect);
383         break;
384      }
385
386    /* update the ecore_evas */
387    _e_output_render_update(output);
388 }
389
390 static void
391 _e_output_zoom_rotating_check(E_Output *output)
392 {
393    int angle = 0;
394
395    angle = _e_output_zoom_get_angle(output);
396    if (output->zoom_conf.current_angle != angle)
397      {
398         output->zoom_conf.current_angle = angle;
399         _e_output_zoom_rotate(output);
400      }
401 }
402
403 static Eina_Bool
404 _e_output_visible_client_check(E_Output *output)
405 {
406    Eina_Rectangle r;
407    E_Client *ec;
408    Eina_Bool found = EINA_FALSE;
409    int x, y, w, h;
410    E_Zone *zone = NULL;
411    E_Comp_Wl_Client_Data *cdata = NULL;
412    E_Output *zone_output = NULL;
413    Eina_List *l;
414
415    EINA_LIST_FOREACH(e_comp->zones, l, zone)
416      {
417         zone_output = e_output_find(zone->output_id);
418         if (!zone_output) continue;
419         if (zone_output != output) continue;
420
421         EINA_RECTANGLE_SET(&r, zone->x, zone->y, zone->w, zone->h);
422
423         E_CLIENT_REVERSE_FOREACH(ec)
424           {
425               if (e_object_is_del(E_OBJECT(ec))) continue;
426               if (e_client_util_ignored_get(ec)) continue;
427               if (!ec->frame) continue;
428               if (ec->is_cursor) continue;
429               if (!ec->visible) continue;
430               if (!evas_object_visible_get(ec->frame)) continue;
431               cdata = (E_Comp_Wl_Client_Data *)ec->comp_data;
432               if (cdata && cdata->sub.data) continue; /* skip subsurface */
433               if (cdata && !cdata->mapped) continue;
434               if (!ec->iconic) continue;
435               e_client_geometry_get(ec, &x, &y, &w, &h);
436               if (E_INTERSECTS(x, y, w, h, r.x, r.y, r.w, r.h))
437                 {
438                   found = EINA_TRUE;
439                   break;
440                 }
441           }
442      }
443
444    return found;
445 }
446
447 static void
448 _e_output_dpms_on_render(E_Output *output)
449 {
450    if (!output) return;
451
452    if (_e_output_visible_client_check(output))
453      ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
454 }
455
456 static void
457 _e_output_cb_output_change(tdm_output *toutput,
458                                   tdm_output_change_type type,
459                                   tdm_value value,
460                                   void *user_data)
461 {
462    E_Output *e_output = NULL;
463    E_OUTPUT_DPMS edpms;
464    tdm_output_dpms tdpms = (tdm_output_dpms)value.u32;
465    static Eina_Bool override = EINA_FALSE;
466
467    EINA_SAFETY_ON_NULL_RETURN(toutput);
468    EINA_SAFETY_ON_NULL_RETURN(user_data);
469
470    e_output = (E_Output *)user_data;
471
472    switch (type)
473      {
474        case TDM_OUTPUT_CHANGE_DPMS:
475           if (tdpms == TDM_OUTPUT_DPMS_OFF)
476             {
477                edpms = E_OUTPUT_DPMS_OFF;
478                if (!override)
479                  {
480                     e_comp_override_add();
481                     override = EINA_TRUE;
482                  }
483             }
484           else if (tdpms == TDM_OUTPUT_DPMS_ON)
485             {
486                edpms = E_OUTPUT_DPMS_ON;
487                if (override)
488                  {
489                     e_comp_override_del();
490                     override = EINA_FALSE;
491                  }
492                _e_output_dpms_on_render(e_output);
493             }
494           else if (tdpms == TDM_OUTPUT_DPMS_STANDBY) edpms = E_OUTPUT_DPMS_STANDBY;
495           else if (tdpms == TDM_OUTPUT_DPMS_SUSPEND) edpms = E_OUTPUT_DPMS_SUSPEND;
496           else edpms = e_output->dpms;
497
498           e_output->dpms = edpms;
499
500           _e_output_hook_call(E_OUTPUT_HOOK_DPMS_CHANGE, e_output);
501
502           break;
503        default:
504           break;
505      }
506 }
507
508 static void
509 _e_output_update_fps()
510 {
511    static double time = 0.0;
512    static double lapse = 0.0;
513    static int cframes = 0;
514    static int flapse = 0;
515
516    if (e_comp->calc_fps)
517      {
518         double dt;
519         double tim = ecore_time_get();
520
521         dt = tim - e_comp->frametimes[0];
522         e_comp->frametimes[0] = tim;
523
524         time += dt;
525         cframes++;
526
527         if (lapse == 0.0)
528           {
529              lapse = tim;
530              flapse = cframes;
531           }
532         else if ((tim - lapse) >= 0.5)
533           {
534              e_comp->fps = (cframes - flapse) / (tim - lapse);
535              lapse = tim;
536              flapse = cframes;
537              time = 0.0;
538           }
539      }
540 }
541
542 EINTERN Eina_Bool
543 e_output_init(void)
544 {
545    /* nothing */
546    return EINA_TRUE;
547 }
548
549 EINTERN void
550 e_output_shutdown(void)
551 {
552    ;
553 }
554
555 static char *
556 _output_type_to_str(tdm_output_type output_type)
557 {
558    if (output_type == TDM_OUTPUT_TYPE_Unknown) return "Unknown";
559    else if (output_type == TDM_OUTPUT_TYPE_VGA) return "VGA";
560    else if (output_type == TDM_OUTPUT_TYPE_DVII) return "DVII";
561    else if (output_type == TDM_OUTPUT_TYPE_DVID) return "DVID";
562    else if (output_type == TDM_OUTPUT_TYPE_DVIA) return "DVIA";
563    else if (output_type == TDM_OUTPUT_TYPE_SVIDEO) return "SVIDEO";
564    else if (output_type == TDM_OUTPUT_TYPE_LVDS) return "LVDS";
565    else if (output_type == TDM_OUTPUT_TYPE_Component) return "Component";
566    else if (output_type == TDM_OUTPUT_TYPE_9PinDIN) return "9PinDIN";
567    else if (output_type == TDM_OUTPUT_TYPE_DisplayPort) return "DisplayPort";
568    else if (output_type == TDM_OUTPUT_TYPE_HDMIA) return "HDMIA";
569    else if (output_type == TDM_OUTPUT_TYPE_HDMIB) return "HDMIB";
570    else if (output_type == TDM_OUTPUT_TYPE_TV) return "TV";
571    else if (output_type == TDM_OUTPUT_TYPE_eDP) return "eDP";
572    else if (output_type == TDM_OUTPUT_TYPE_DSI) return "DSI";
573    else return "Unknown";
574 }
575
576 static int
577 _e_output_cb_planes_sort(const void *d1, const void *d2)
578 {
579    E_Plane *plane1 = (E_Plane *)d1;
580    E_Plane *plane2 = (E_Plane *)d2;
581
582    if (!plane1) return(1);
583    if (!plane2) return(-1);
584
585    return (plane1->zpos - plane2->zpos);
586 }
587
588 static tdm_capture *
589 _e_output_tdm_capture_create(E_Output *output, tdm_capture_capability cap)
590 {
591    tdm_error error = TDM_ERROR_NONE;
592    tdm_capture *tcapture = NULL;
593    tdm_capture_capability capabilities;
594    E_Comp_Screen *e_comp_screen = NULL;
595
596    e_comp_screen = e_comp->e_comp_screen;
597    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE);
598
599    error = tdm_display_get_capture_capabilities(e_comp_screen->tdisplay, &capabilities);
600    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
601
602    if (!(capabilities & cap))
603      return NULL;
604
605    tcapture = tdm_output_create_capture(output->toutput, &error);
606    if (error != TDM_ERROR_NONE)
607      {
608         ERR("create tdm_capture failed");
609         return NULL;
610      }
611
612    return tcapture;
613 }
614
615 static void
616 _e_output_center_rect_get (int src_w, int src_h, int dst_w, int dst_h, Eina_Rectangle *fit)
617 {
618    float rw, rh;
619
620    if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0 || !fit)
621      return;
622
623    rw = (float)src_w / dst_w;
624    rh = (float)src_h / dst_h;
625
626    if (rw > rh)
627      {
628         fit->w = dst_w;
629         fit->h = src_h / rw;
630         fit->x = 0;
631         fit->y = (dst_h - fit->h) / 2;
632      }
633    else if (rw < rh)
634      {
635         fit->w = src_w / rh;
636         fit->h = dst_h;
637         fit->x = (dst_w - fit->w) / 2;
638         fit->y = 0;
639      }
640    else
641      {
642         fit->w = dst_w;
643         fit->h = dst_h;
644         fit->x = 0;
645         fit->y = 0;
646      }
647
648    if (fit->x % 2)
649      fit->x = fit->x - 1;
650 }
651
652 static Eina_Bool
653 _e_output_capture_position_get(E_Output *output, int dst_w, int dst_h, Eina_Rectangle *fit, Eina_Bool rotate)
654 {
655    int output_w = 0, output_h = 0;
656
657    e_output_size_get(output, &output_w, &output_h);
658
659    if (output_w == 0 || output_h == 0)
660      return EINA_FALSE;
661
662    if (rotate)
663      _e_output_center_rect_get(output_h, output_w, dst_w, dst_h, fit);
664    else
665      _e_output_center_rect_get(output_w, output_h, dst_w, dst_h, fit);
666
667    return EINA_TRUE;
668 }
669
670 static unsigned int
671 _e_output_aligned_width_get(tbm_surface_h tsurface)
672 {
673    unsigned int aligned_width = 0;
674    tbm_surface_info_s surf_info;
675
676    tbm_surface_get_info(tsurface, &surf_info);
677
678    switch (surf_info.format)
679      {
680       case TBM_FORMAT_YUV420:
681       case TBM_FORMAT_YVU420:
682       case TBM_FORMAT_YUV422:
683       case TBM_FORMAT_YVU422:
684       case TBM_FORMAT_NV12:
685       case TBM_FORMAT_NV21:
686         aligned_width = surf_info.planes[0].stride;
687         break;
688       case TBM_FORMAT_YUYV:
689       case TBM_FORMAT_UYVY:
690         aligned_width = surf_info.planes[0].stride >> 1;
691         break;
692       case TBM_FORMAT_ARGB8888:
693       case TBM_FORMAT_XRGB8888:
694         aligned_width = surf_info.planes[0].stride >> 2;
695         break;
696       default:
697         ERR("not supported format: %x", surf_info.format);
698      }
699
700    return aligned_width;
701 }
702
703 static E_Client *
704 _e_output_top_visible_ec_get()
705 {
706    E_Client *ec;
707    Evas_Object *o;
708    E_Comp_Wl_Client_Data *cdata;
709
710    for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
711      {
712         ec = evas_object_data_get(o, "E_Client");
713
714         /* check e_client and skip e_clients not intersects with zone */
715         if (!ec) continue;
716         if (e_object_is_del(E_OBJECT(ec))) continue;
717         if (e_client_util_ignored_get(ec)) continue;
718         if (ec->iconic) continue;
719         if (ec->visible == 0) continue;
720         if (!(ec->visibility.obscured == 0 || ec->visibility.obscured == 1)) continue;
721         if (!ec->frame) continue;
722         if (!evas_object_visible_get(ec->frame)) continue;
723         /* if ec is subsurface, skip this */
724         cdata = (E_Comp_Wl_Client_Data *)ec->comp_data;
725         if (cdata && cdata->sub.data) continue;
726
727         return ec;
728      }
729
730    return NULL;
731 }
732
733 static int
734 _e_output_top_ec_angle_get(void)
735 {
736    E_Client *ec = NULL;
737
738    ec = _e_output_top_visible_ec_get();
739    if (ec)
740      return ec->e.state.rot.ang.curr;
741
742    return 0;
743 }
744
745 static E_Output_Capture *
746 _e_output_tdm_stream_capture_find_data(E_Output *output, tbm_surface_h tsurface)
747 {
748    E_Output_Capture *cdata = NULL;
749    Eina_List *l;
750
751    EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
752      {
753         if (!cdata) continue;
754
755         if (cdata->surface == tsurface)
756           return cdata;
757      }
758
759    return NULL;
760 }
761
762 static Eina_Bool
763 _e_output_tdm_stream_capture_stop(void *data)
764 {
765    E_Output *output = data;
766
767    EINA_SAFETY_ON_NULL_RETURN_VAL(output, ECORE_CALLBACK_CANCEL);
768
769    if (output->stream_capture.tcapture)
770      {
771         DBG("e_output stream capture stop.");
772         tdm_capture_destroy(output->stream_capture.tcapture);
773         output->stream_capture.tcapture = NULL;
774      }
775
776    output->stream_capture.timer = NULL;
777
778    return ECORE_CALLBACK_CANCEL;
779 }
780
781 static void
782 _e_output_tdm_stream_capture_done_handler(tdm_capture *tcapture,
783                                           tbm_surface_h tsurface, void *user_data)
784 {
785    E_Output *output = NULL;
786    E_Output_Capture *cdata = NULL;
787
788    output = (E_Output *)user_data;
789
790    tbm_surface_internal_unref(tsurface);
791
792    cdata = _e_output_tdm_stream_capture_find_data(output, tsurface);
793    if (cdata)
794      {
795         output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
796         if (!cdata->dequeued)
797           cdata->func(output, tsurface, cdata->data);
798         E_FREE(cdata);
799      }
800
801    if (!output->stream_capture.start)
802      {
803         if (eina_list_count(output->stream_capture.data) == 0)
804           output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
805                                          _e_output_tdm_stream_capture_stop, output);
806      }
807 }
808
809 static Eina_Bool
810 _e_output_tdm_capture_info_set(E_Output *output, tdm_capture *tcapture, tbm_surface_h tsurface,
811                                tdm_capture_type type, Eina_Bool auto_rotate)
812 {
813    tdm_error error = TDM_ERROR_NONE;
814    tdm_info_capture capture_info;
815    tbm_error_e tbm_error = TBM_ERROR_NONE;
816    tbm_surface_info_s surf_info;
817    Eina_Rectangle dst_pos;
818    unsigned int width;
819    int angle = 0;
820    int output_angle = 0;
821    Eina_Bool ret;
822    Eina_Bool rotate_check = EINA_FALSE;
823
824    tbm_error = tbm_surface_get_info(tsurface, &surf_info);
825    EINA_SAFETY_ON_FALSE_RETURN_VAL(tbm_error == TBM_ERROR_NONE, EINA_FALSE);
826
827    width = _e_output_aligned_width_get(tsurface);
828    EINA_SAFETY_ON_TRUE_RETURN_VAL(width == 0, EINA_FALSE);
829
830    memset(&capture_info, 0, sizeof(tdm_info_capture));
831    capture_info.dst_config.size.h = width;
832    capture_info.dst_config.size.v = surf_info.height;
833    capture_info.dst_config.format = surf_info.format;
834    capture_info.transform = TDM_TRANSFORM_NORMAL;
835
836    angle = _e_output_top_ec_angle_get();
837    output_angle = output->config.rotation;
838
839    if (auto_rotate &&
840       (((angle + output_angle) % 360 == 90) || ((angle + output_angle) % 360 == 270)))
841      rotate_check = EINA_TRUE;
842
843    ret = _e_output_capture_position_get(output, surf_info.width, surf_info.height, &dst_pos, rotate_check);
844    if (ret)
845      {
846         capture_info.dst_config.pos.x = dst_pos.x;
847         capture_info.dst_config.pos.y = dst_pos.y;
848         capture_info.dst_config.pos.w = dst_pos.w;
849         capture_info.dst_config.pos.h = dst_pos.h;
850
851         if (rotate_check)
852           {
853              int tmp = (angle + output_angle) % 360;
854              if (tmp == 90)
855                capture_info.transform = TDM_TRANSFORM_90;
856              else if (tmp == 180)
857                capture_info.transform = TDM_TRANSFORM_180;
858              else if (tmp == 270)
859                capture_info.transform = TDM_TRANSFORM_270;
860           }
861         else if (auto_rotate && output_angle == 90)
862           capture_info.transform = TDM_TRANSFORM_90;
863         else if (auto_rotate && output_angle == 180)
864           capture_info.transform = TDM_TRANSFORM_180;
865         else if (auto_rotate && output_angle == 270)
866           capture_info.transform = TDM_TRANSFORM_270;
867      }
868    else
869      {
870         capture_info.dst_config.pos.x = 0;
871         capture_info.dst_config.pos.y = 0;
872         capture_info.dst_config.pos.w = surf_info.width;
873         capture_info.dst_config.pos.h = surf_info.height;
874      }
875
876    capture_info.type = type;
877
878    error = tdm_capture_set_info(tcapture, &capture_info);
879    if (error != TDM_ERROR_NONE)
880      {
881         ERR("tdm_capture set_info failed");
882         return EINA_FALSE;
883      }
884
885    return EINA_TRUE;
886 }
887
888 static void
889 _e_output_tdm_capture_done_handler(tdm_capture *tcapture, tbm_surface_h tsurface, void *user_data)
890 {
891    E_Output *output = NULL;
892    E_Output_Capture *cdata = NULL;
893
894    cdata = (E_Output_Capture *)user_data;
895    output = cdata->output;
896
897    tbm_surface_internal_unref(tsurface);
898
899    cdata->func(output, tsurface, cdata->data);
900
901    tdm_capture_destroy(cdata->tcapture);
902
903    E_FREE(cdata);
904
905    DBG("tdm_capture done.(%p)", tsurface);
906 }
907
908 static Eina_Bool
909 _e_output_tdm_capture(E_Output *output, tdm_capture *tcapture,
910                       tbm_surface_h tsurface, E_Output_Capture_Cb func, void *data)
911 {
912    tdm_error error = TDM_ERROR_NONE;
913    E_Output_Capture *cdata = NULL;
914
915    cdata = E_NEW(E_Output_Capture, 1);
916    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
917
918    cdata->output = output;
919    cdata->tcapture = tcapture;
920    cdata->data = data;
921    cdata->func = func;
922
923    tbm_surface_internal_ref(tsurface);
924
925    error = tdm_capture_set_done_handler(tcapture, _e_output_tdm_capture_done_handler, cdata);
926    EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
927
928    error = tdm_capture_attach(tcapture, tsurface);
929    EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
930
931    error = tdm_capture_commit(tcapture);
932    EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
933
934    return EINA_TRUE;
935
936 fail:
937    tbm_surface_internal_unref(tsurface);
938
939    if (cdata)
940      E_FREE(cdata);
941
942    return EINA_FALSE;
943 }
944
945 static Eina_Bool
946 _e_output_stream_capture_cb_timeout(void *data)
947 {
948    E_Output *output = data;
949    E_Output_Capture *cdata = NULL;
950    Eina_List *l;
951
952    EINA_SAFETY_ON_NULL_GOTO(output, done);
953
954    if (!output->stream_capture.start)
955      {
956         EINA_LIST_FREE(output->stream_capture.data, cdata)
957           {
958              tbm_surface_internal_unref(cdata->surface);
959
960              E_FREE(cdata);
961           }
962
963         if (output->stream_capture.tcapture)
964           {
965              tdm_capture_destroy(output->stream_capture.tcapture);
966              output->stream_capture.tcapture = NULL;
967           }
968
969         DBG("e_output stream capture stop.");
970
971         output->stream_capture.timer = NULL;
972
973         return ECORE_CALLBACK_CANCEL;
974      }
975
976    EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
977      {
978         if (!cdata->in_using) break;
979      }
980
981    /* can be null when client doesn't queue a buffer previously */
982    if (!cdata)
983      goto done;
984
985    cdata->in_using = EINA_TRUE;
986
987    tbm_surface_internal_unref(cdata->surface);
988
989    output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
990
991    cdata->func(output, cdata->surface, cdata->data);
992    E_FREE(cdata);
993
994 done:
995    return ECORE_CALLBACK_RENEW;
996 }
997
998 static Eina_Bool
999 _e_output_tdm_stream_capture(E_Output *output, tdm_capture *tcapture,
1000                              tbm_surface_h tsurface, E_Output_Capture_Cb func, void *data)
1001 {
1002    tdm_error error = TDM_ERROR_NONE;
1003    E_Output_Capture *cdata = NULL;
1004    E_Output_Capture *tmp_cdata = NULL;
1005    Eina_List *l, *ll;
1006
1007    cdata = E_NEW(E_Output_Capture, 1);
1008    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
1009
1010    cdata->output = output;
1011    cdata->tcapture = tcapture;
1012    cdata->surface = tsurface;
1013    cdata->data = data;
1014    cdata->func = func;
1015
1016    tbm_surface_internal_ref(tsurface);
1017
1018    output->stream_capture.data = eina_list_append(output->stream_capture.data, cdata);
1019
1020    if (output->stream_capture.start)
1021      {
1022         if (e_output_dpms_get(output))
1023           {
1024              if (!output->stream_capture.timer)
1025                output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
1026                                                               _e_output_stream_capture_cb_timeout, output);
1027              EINA_SAFETY_ON_NULL_RETURN_VAL(output->stream_capture.timer, EINA_FALSE);
1028
1029              return EINA_TRUE;
1030           }
1031         else if (output->stream_capture.timer)
1032           {
1033              ecore_timer_del(output->stream_capture.timer);
1034              output->stream_capture.timer = NULL;
1035
1036              EINA_LIST_FOREACH_SAFE(output->stream_capture.data, l, ll, tmp_cdata)
1037                {
1038                   if (!tmp_cdata) continue;
1039
1040                   if (!tmp_cdata->in_using)
1041                     {
1042                        tmp_cdata->in_using = EINA_TRUE;
1043
1044                        error = tdm_capture_attach(tcapture, tsurface);
1045                        if (error != TDM_ERROR_NONE)
1046                          {
1047                             ERR("tdm_capture_attach fail");
1048                             output->stream_capture.data = eina_list_remove_list(output->stream_capture.data, l);
1049                             tmp_cdata->func(tmp_cdata->output, tmp_cdata->surface, tmp_cdata->data);
1050                             E_FREE(tmp_cdata);
1051
1052                             return EINA_FALSE;
1053                          }
1054                     }
1055                }
1056              error = tdm_capture_commit(tcapture);
1057              if (error != TDM_ERROR_NONE)
1058                {
1059                   ERR("tdm_capture_commit fail");
1060                   return EINA_FALSE;
1061                }
1062           }
1063         else
1064           {
1065              cdata->in_using = EINA_TRUE;
1066
1067              error = tdm_capture_attach(tcapture, tsurface);
1068              EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1069
1070              error = tdm_capture_commit(tcapture);
1071              EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1072           }
1073      }
1074    else
1075      {
1076         if (e_output_dpms_get(output))
1077           return EINA_TRUE;
1078
1079         cdata->in_using = EINA_TRUE;
1080
1081         error = tdm_capture_attach(tcapture, tsurface);
1082         EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
1083      }
1084
1085    return EINA_TRUE;
1086
1087 fail:
1088    output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1089
1090    tbm_surface_internal_unref(tsurface);
1091
1092    if (cdata)
1093      E_FREE(cdata);
1094
1095    return EINA_FALSE;
1096 }
1097
1098 static Eina_Bool
1099 _e_output_watch_vblank_timer(void *data)
1100 {
1101    E_Output *output = data;
1102
1103    EINA_SAFETY_ON_NULL_RETURN_VAL(output, ECORE_CALLBACK_RENEW);
1104
1105    _e_output_vblank_handler(NULL, 0, 0, 0, (void *)output);
1106
1107    return ECORE_CALLBACK_RENEW;
1108 }
1109
1110 static Eina_Bool
1111 _e_output_watch_vblank(E_Output *output)
1112 {
1113    tdm_error ret;
1114    int per_vblank;
1115
1116    /* If not DPMS_ON, we call vblank handler directly to dump screen */
1117    if (e_output_dpms_get(output))
1118      {
1119         if (!output->stream_capture.timer)
1120           output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
1121                                                          _e_output_watch_vblank_timer, output);
1122         EINA_SAFETY_ON_NULL_RETURN_VAL(output->stream_capture.timer, EINA_FALSE);
1123
1124         return EINA_TRUE;
1125      }
1126    else if (output->stream_capture.timer)
1127      {
1128         ecore_timer_del(output->stream_capture.timer);
1129         output->stream_capture.timer = NULL;
1130      }
1131
1132    if (output->stream_capture.wait_vblank)
1133      return EINA_TRUE;
1134
1135    per_vblank = output->config.mode.refresh / (DUMP_FPS * 1000);
1136
1137    ret = tdm_output_wait_vblank(output->toutput, per_vblank, 0,
1138                                 _e_output_vblank_handler, output);
1139    EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
1140
1141    output->stream_capture.wait_vblank = EINA_TRUE;
1142
1143    return EINA_TRUE;
1144 }
1145
1146 static void
1147 _e_output_vblank_handler(tdm_output *toutput, unsigned int sequence,
1148                          unsigned int tv_sec, unsigned int tv_usec, void *data)
1149 {
1150    E_Output *output = data;
1151    E_Output_Capture *cdata = NULL;
1152    Eina_List *l;
1153    Eina_Bool ret = EINA_FALSE;
1154
1155    EINA_SAFETY_ON_NULL_RETURN(output);
1156
1157    output->stream_capture.wait_vblank = EINA_FALSE;
1158
1159    if (!output->stream_capture.start)
1160      {
1161         EINA_LIST_FREE(output->stream_capture.data, cdata)
1162           {
1163              tbm_surface_internal_unref(cdata->surface);
1164
1165              E_FREE(cdata);
1166           }
1167
1168         if (output->stream_capture.timer)
1169           {
1170              ecore_timer_del(output->stream_capture.timer);
1171              output->stream_capture.timer = NULL;
1172           }
1173         DBG("e_output stream capture stop.");
1174
1175         return;
1176      }
1177
1178    EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
1179      {
1180         if (!cdata->in_using) break;
1181      }
1182
1183    /* can be null when client doesn't queue a buffer previously */
1184    if (!cdata)
1185      return;
1186
1187    output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1188
1189    ret = _e_output_capture(output, cdata->surface, EINA_FALSE);
1190    if (ret == EINA_FALSE)
1191      ERR("capture fail");
1192
1193    tbm_surface_internal_unref(cdata->surface);
1194
1195    cdata->func(output, cdata->surface, cdata->data);
1196
1197    E_FREE(cdata);
1198
1199    /* timer is a substitution for vblank during dpms off. so if timer is running,
1200     * we don't watch vblank events recursively.
1201     */
1202    if (!output->stream_capture.timer)
1203      _e_output_watch_vblank(output);
1204 }
1205
1206 static Eina_Bool
1207 _e_output_vblank_stream_capture(E_Output *output, tbm_surface_h tsurface,
1208                                 E_Output_Capture_Cb func, void *data)
1209 {
1210    E_Output_Capture *cdata = NULL;
1211    Eina_Bool ret = EINA_FALSE;
1212
1213    cdata = E_NEW(E_Output_Capture, 1);
1214    EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, EINA_FALSE);
1215
1216    cdata->output = output;
1217    cdata->surface = tsurface;
1218    cdata->data = data;
1219    cdata->func = func;
1220
1221    tbm_surface_internal_ref(tsurface);
1222
1223    output->stream_capture.data = eina_list_append(output->stream_capture.data, cdata);
1224
1225    if (output->stream_capture.start)
1226      {
1227         ret = _e_output_watch_vblank(output);
1228         if (ret == EINA_FALSE)
1229           {
1230              output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
1231              tbm_surface_internal_unref(tsurface);
1232              E_FREE(cdata);
1233
1234              return EINA_FALSE;
1235           }
1236      }
1237
1238    return EINA_TRUE;
1239 }
1240
1241 static void
1242 _e_output_capture_showing_rect_get(Eina_Rectangle *out_rect, Eina_Rectangle *dst_rect, Eina_Rectangle *showing_rect)
1243 {
1244    showing_rect->x = dst_rect->x;
1245    showing_rect->y = dst_rect->y;
1246
1247    if (dst_rect->x >= out_rect->w)
1248      showing_rect->w = 0;
1249    else if (dst_rect->x + dst_rect->w > out_rect->w)
1250      showing_rect->w = out_rect->w - dst_rect->x;
1251    else
1252      showing_rect->w = dst_rect->w;
1253
1254    if (dst_rect->y >= out_rect->h)
1255      showing_rect->h = 0;
1256    else if (dst_rect->y + dst_rect->h > out_rect->h)
1257      showing_rect->h = out_rect->h - dst_rect->y;
1258    else
1259      showing_rect->h = dst_rect->h;
1260 }
1261
1262 static Eina_Bool
1263 _e_output_capture_src_crop_get(E_Output *output, tdm_layer *layer, Eina_Rectangle *fit, Eina_Rectangle *showing_rect)
1264 {
1265    tdm_info_layer info;
1266    tdm_error error = TDM_ERROR_NONE;
1267    const tdm_output_mode *mode = NULL;
1268    float ratio_x, ratio_y;
1269    Eina_Rectangle out_rect;
1270    Eina_Rectangle dst_rect;
1271
1272    fit->x = 0;
1273    fit->y = 0;
1274    fit->w = 0;
1275    fit->h = 0;
1276
1277    tdm_output_get_mode(output->toutput, &mode);
1278    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1279
1280    out_rect.x = 0;
1281    out_rect.y = 0;
1282    out_rect.w = mode->hdisplay;
1283    out_rect.h = mode->vdisplay;
1284
1285    error = tdm_layer_get_info(layer, &info);
1286    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1287
1288    dst_rect.x = info.dst_pos.x;
1289    dst_rect.y = info.dst_pos.y;
1290    dst_rect.w = info.dst_pos.w;
1291    dst_rect.h = info.dst_pos.h;
1292
1293    _e_output_capture_showing_rect_get(&out_rect, &dst_rect, showing_rect);
1294
1295    fit->x = info.src_config.pos.x;
1296    fit->y = info.src_config.pos.y;
1297
1298    if (info.transform % 2 == 0)
1299      {
1300         ratio_x = (float)info.src_config.pos.w / dst_rect.w;
1301         ratio_y = (float)info.src_config.pos.h / dst_rect.h;
1302
1303         fit->w = showing_rect->w * ratio_x;
1304         fit->h = showing_rect->h * ratio_y;
1305      }
1306    else
1307      {
1308         ratio_x = (float)info.src_config.pos.w / dst_rect.h;
1309         ratio_y = (float)info.src_config.pos.h / dst_rect.w;
1310
1311         fit->w = showing_rect->h * ratio_x;
1312         fit->h = showing_rect->w * ratio_y;
1313      }
1314
1315    return EINA_TRUE;
1316 }
1317
1318 static void
1319 _e_output_capture_dst_crop_get(E_Comp_Wl_Video_Buf *tmp, E_Comp_Wl_Video_Buf *dst, tdm_layer *layer,
1320                                int w, int h, Eina_Rectangle *pos, Eina_Rectangle *showing_pos,
1321                                Eina_Rectangle *dst_crop, int rotate)
1322 {
1323    tdm_info_layer info;
1324    tdm_error error = TDM_ERROR_NONE;
1325
1326    dst_crop->x = 0;
1327    dst_crop->y = 0;
1328    dst_crop->w = 0;
1329    dst_crop->h = 0;
1330
1331    error = tdm_layer_get_info(layer, &info);
1332    EINA_SAFETY_ON_FALSE_RETURN(error == TDM_ERROR_NONE);
1333
1334    if (info.src_config.pos.w == w && info.src_config.pos.h == h &&
1335        pos->x == 0 && pos->y == 0 && pos->w == tmp->width && pos->h == tmp->height)
1336      {
1337         dst_crop->x = pos->x;
1338         dst_crop->y = pos->y;
1339         dst_crop->w = pos->w;
1340         dst_crop->h = pos->h;
1341      }
1342    else if ((w == pos->w) && (h == pos->h) && (showing_pos->w == pos->w) && (showing_pos->h == pos->h))
1343      {
1344         dst_crop->x = info.dst_pos.x + pos->x;
1345         dst_crop->y = info.dst_pos.y + pos->y;
1346         dst_crop->w = info.dst_pos.w;
1347         dst_crop->h = info.dst_pos.h;
1348      }
1349    else if (rotate == 0)
1350      {
1351         dst_crop->x = showing_pos->x * pos->w / w + pos->x;
1352         dst_crop->y = showing_pos->y * pos->h / h + pos->y;
1353         dst_crop->w = showing_pos->w * pos->w / w;
1354         dst_crop->h = showing_pos->h * pos->h / h;
1355      }
1356    else if (rotate == 90)
1357      {
1358         dst_crop->x = (h - showing_pos->y - showing_pos->h) * pos->w / h + pos->x;
1359         dst_crop->y = showing_pos->x * pos->h / w + pos->y;
1360         dst_crop->w = showing_pos->h * pos->w / h;
1361         dst_crop->h = showing_pos->w * pos->h / w;
1362      }
1363    else if (rotate == 180)
1364      {
1365         dst_crop->x = (w - showing_pos->x - showing_pos->w) * pos->w / w + pos->x;
1366         dst_crop->y = (h - showing_pos->y - showing_pos->h) * pos->h / h + pos->y;
1367         dst_crop->w = showing_pos->w * pos->w / w;
1368         dst_crop->h = showing_pos->h * pos->h / h;
1369      }
1370    else if (rotate == 270)
1371      {
1372         dst_crop->x = showing_pos->y * pos->w / h + pos->x;
1373         dst_crop->y = (w - showing_pos->x - showing_pos->w) * pos->h / w + pos->y;
1374         dst_crop->w = showing_pos->h * pos->w / h;
1375         dst_crop->h = showing_pos->w * pos->h / w;
1376      }
1377    else
1378      {
1379         dst_crop->x = pos->x;
1380         dst_crop->y = pos->y;
1381         dst_crop->w = pos->w;
1382         dst_crop->h = pos->h;
1383         ERR("get_cropinfo: unknown case error");
1384      }
1385 }
1386
1387 static Eina_Bool
1388 _e_output_video_buffer_capture(E_Output *output, E_Comp_Wl_Video_Buf *vbuf, Eina_Bool auto_rotate)
1389 {
1390    tdm_error error = TDM_ERROR_NONE;
1391    int width = 0, height = 0, rotate = 0;
1392    int i, count;
1393    int angle = 0;
1394    int output_angle = 0;
1395    Eina_Bool rotate_check = EINA_FALSE;
1396
1397    e_output_size_get(output, &width, &height);
1398    if (width == 0 || height == 0)
1399      return EINA_FALSE;
1400
1401    angle = _e_output_top_ec_angle_get();
1402    output_angle = output->config.rotation;
1403
1404    if (auto_rotate &&
1405       ((angle + output_angle) % 360 == 90 || (angle + output_angle) % 360 == 270))
1406      rotate_check = EINA_TRUE;
1407
1408    if (rotate_check)
1409      {
1410         int tmp = (angle + output_angle) % 360;
1411
1412         if (tmp == 90)
1413           rotate = 90;
1414         else if (tmp == 180)
1415           rotate = 180;
1416         else if (tmp == 270)
1417           rotate = 270;
1418      }
1419    else if (auto_rotate && output_angle == 90)
1420      rotate = 90;
1421    else if (auto_rotate && output_angle == 180)
1422      rotate = 180;
1423    else if (auto_rotate && output_angle == 270)
1424      rotate = 270;
1425
1426    error = tdm_output_get_layer_count(output->toutput, &count);
1427    EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1428    EINA_SAFETY_ON_FALSE_RETURN_VAL(count >= 0, EINA_FALSE);
1429
1430    for (i = 0; i < count; i++)
1431      {
1432         E_Comp_Wl_Video_Buf *tmp = NULL;
1433         tdm_layer *layer;
1434         tdm_layer_capability capability;
1435         tbm_surface_h surface = NULL;
1436         Eina_Rectangle showing_pos = {0, };
1437         Eina_Rectangle dst_pos = {0, };
1438         Eina_Rectangle src_crop = {0, };
1439         Eina_Rectangle dst_crop = {0, };
1440         Eina_Bool ret;
1441
1442         layer = tdm_output_get_layer(output->toutput, i, &error);
1443         EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1444
1445         error = tdm_layer_get_capabilities(layer, &capability);
1446         EINA_SAFETY_ON_FALSE_RETURN_VAL(error == TDM_ERROR_NONE, EINA_FALSE);
1447         if (capability & TDM_LAYER_CAPABILITY_VIDEO)
1448           continue;
1449
1450         surface = tdm_layer_get_displaying_buffer(layer, &error);
1451         if (surface == NULL)
1452           continue;
1453
1454         tmp = e_comp_wl_video_buffer_create_tbm(surface);
1455         if (tmp == NULL)
1456           continue;
1457
1458         ret = _e_output_capture_src_crop_get(output, layer, &src_crop, &showing_pos);
1459         if (ret == EINA_FALSE)
1460           {
1461              e_comp_wl_video_buffer_unref(tmp);
1462              continue;
1463           }
1464
1465         ret = _e_output_capture_position_get(output, vbuf->width, vbuf->height, &dst_pos, rotate_check);
1466         if (ret == EINA_FALSE)
1467           {
1468              e_comp_wl_video_buffer_unref(tmp);
1469              continue;
1470           }
1471
1472         _e_output_capture_dst_crop_get(tmp, vbuf, layer, width, height,
1473                                        &dst_pos, &showing_pos, &dst_crop, rotate);
1474
1475         e_comp_wl_video_buffer_convert(tmp, vbuf,
1476                                        src_crop.x, src_crop.y, src_crop.w, src_crop.h,
1477                                        dst_crop.x, dst_crop.y, dst_crop.w, dst_crop.h,
1478                                        EINA_TRUE, rotate, 0, 0);
1479
1480         e_comp_wl_video_buffer_unref(tmp);
1481      }
1482
1483    return EINA_TRUE;
1484 }
1485
1486 static Eina_Bool
1487 _e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate)
1488 {
1489    E_Comp_Wl_Video_Buf *vbuf = NULL;
1490    Eina_Bool ret = EINA_FALSE;
1491
1492    vbuf = e_comp_wl_video_buffer_create_tbm(tsurface);
1493    EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, EINA_FALSE);
1494
1495    e_comp_wl_video_buffer_clear(vbuf);
1496
1497    ret = _e_output_video_buffer_capture(output, vbuf, auto_rotate);
1498
1499    e_comp_wl_video_buffer_unref(vbuf);
1500
1501    return ret;
1502 }
1503
1504 static void
1505 _e_output_tdm_strem_capture_support(E_Output *output)
1506 {
1507    tdm_error error = TDM_ERROR_NONE;
1508    tdm_capture_capability capabilities;
1509    E_Comp_Screen *e_comp_screen = NULL;
1510
1511    e_comp_screen = e_comp->e_comp_screen;
1512    EINA_SAFETY_ON_NULL_RETURN(e_comp_screen);
1513
1514    error = tdm_display_get_capture_capabilities(e_comp_screen->tdisplay, &capabilities);
1515    EINA_SAFETY_ON_FALSE_RETURN(error == TDM_ERROR_NONE);
1516
1517    if (capabilities & TDM_CAPTURE_CAPABILITY_STREAM)
1518      output->stream_capture.possible_tdm_capture = EINA_TRUE;
1519 }
1520
1521 EINTERN E_Output *
1522 e_output_new(E_Comp_Screen *e_comp_screen, int index)
1523 {
1524    E_Output *output = NULL;
1525    E_Plane *plane = NULL;
1526    E_Plane *default_fb = NULL;
1527    tdm_output *toutput = NULL;
1528    tdm_error error;
1529    char *id = NULL;
1530    char *name;
1531    int num_layers;
1532    int i;
1533    int size = 0;
1534    tdm_output_type output_type;
1535    int min_w, min_h, max_w, max_h, preferred_align;
1536
1537    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, NULL);
1538
1539    output = E_NEW(E_Output, 1);
1540    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
1541    output->index = index;
1542
1543    toutput = tdm_display_get_output(e_comp_screen->tdisplay, index, NULL);
1544    if (!toutput) goto fail;
1545    output->toutput = toutput;
1546
1547    error = tdm_output_add_change_handler(toutput, _e_output_cb_output_change, output);
1548    if (error != TDM_ERROR_NONE)
1549      WRN("fail to tdm_output_add_change_handler");
1550
1551    error = tdm_output_get_output_type(toutput, &output_type);
1552    if (error != TDM_ERROR_NONE) goto fail;
1553
1554    error = tdm_output_get_cursor_available_size(toutput, &min_w, &min_h, &max_w, &max_h, &preferred_align);
1555    if (error == TDM_ERROR_NONE)
1556      {
1557         output->cursor_available.min_w = min_w;
1558         output->cursor_available.min_h = min_h;
1559         output->cursor_available.max_w = min_w;
1560         output->cursor_available.max_h = min_h;
1561         output->cursor_available.preferred_align = preferred_align;
1562      }
1563    else
1564      {
1565         output->cursor_available.min_w = -1;
1566         output->cursor_available.min_h = -1;
1567         output->cursor_available.max_w = -1;
1568         output->cursor_available.max_h = -1;
1569         output->cursor_available.preferred_align = -1;
1570      }
1571
1572    name = _output_type_to_str(output_type);
1573    size = strlen(name) + 4;
1574
1575    id = calloc(1, size);
1576    if (!id) goto fail;
1577    snprintf(id, size, "%s-%d", name, index);
1578
1579    output->id = id;
1580    INF("E_OUTPUT: (%d) output_id = %s", index, output->id);
1581
1582    tdm_output_get_layer_count(toutput, &num_layers);
1583    if (num_layers < 1)
1584      {
1585         ERR("fail to get tdm_output_get_layer_count\n");
1586         goto fail;
1587      }
1588    output->plane_count = num_layers;
1589    INF("E_OUTPUT: num_planes %i", output->plane_count);
1590
1591    if (!e_plane_init())
1592      {
1593         ERR("fail to e_plane_init.");
1594         goto fail;
1595      }
1596
1597    for (i = 0; i < output->plane_count; i++)
1598      {
1599         plane = e_plane_new(output, i);
1600         if (!plane)
1601           {
1602              ERR("fail to create the e_plane.");
1603              goto fail;
1604           }
1605         output->planes = eina_list_append(output->planes, plane);
1606      }
1607
1608    output->planes = eina_list_sort(output->planes, eina_list_count(output->planes), _e_output_cb_planes_sort);
1609
1610    default_fb = e_output_default_fb_target_get(output);
1611    if (!default_fb)
1612      {
1613         ERR("fail to get default_fb_target plane");
1614         goto fail;
1615      }
1616
1617    if (!e_plane_fb_target_set(default_fb, EINA_TRUE))
1618      {
1619         ERR("fail to set fb_target plane");
1620         goto fail;
1621      }
1622
1623    output->e_comp_screen = e_comp_screen;
1624
1625    _e_output_tdm_strem_capture_support(output);
1626
1627    return output;
1628
1629 fail:
1630    if (output) e_output_del(output);
1631
1632    return NULL;
1633 }
1634
1635 EINTERN void
1636 e_output_del(E_Output *output)
1637 {
1638    E_Plane *plane;
1639    E_Output_Mode *m;
1640
1641    if (!output) return;
1642
1643    e_plane_shutdown();
1644
1645    if (output->id) free(output->id);
1646    if (output->info.screen) free(output->info.screen);
1647    if (output->info.name) free(output->info.name);
1648    if (output->info.edid) free(output->info.edid);
1649
1650    tdm_output_remove_change_handler(output->toutput, _e_output_cb_output_change, output);
1651
1652    EINA_LIST_FREE(output->info.modes, m) free(m);
1653
1654    EINA_LIST_FREE(output->planes, plane) e_plane_free(plane);
1655    free(output);
1656 }
1657
1658 EINTERN Eina_Bool
1659 e_output_rotate(E_Output *output, int rotate)
1660 {
1661    unsigned int transform = WL_OUTPUT_TRANSFORM_NORMAL;
1662    int rot_dif;
1663
1664    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
1665
1666    /* FIXME: currently the screen size can't be changed in runtime. To make it
1667     * possible, the output mode should be changeable first.
1668     */
1669    rot_dif = output->config.rotation - rotate;
1670    if (rot_dif < 0) rot_dif = -rot_dif;
1671
1672    if ((rot_dif % 180) && (output->config.geom.w != output->config.geom.h))
1673      {
1674         ERR("output size(%dx%d) should be squre.",
1675             output->config.geom.w, output->config.geom.h);
1676         return EINA_FALSE;
1677      }
1678
1679    switch (rotate)
1680      {
1681       case 90:
1682         transform = WL_OUTPUT_TRANSFORM_90;
1683         break;
1684       case 180:
1685         transform = WL_OUTPUT_TRANSFORM_180;
1686         break;
1687       case 270:
1688         transform = WL_OUTPUT_TRANSFORM_270;
1689         break;
1690       case 0:
1691       default:
1692         transform = WL_OUTPUT_TRANSFORM_NORMAL;
1693         break;
1694      }
1695
1696    output->config.rotation = rotate;
1697
1698    e_comp_wl_output_init(output->id, output->info.name,
1699                          output->info.screen,
1700                          output->config.geom.x, output->config.geom.y,
1701                          output->config.geom.w, output->config.geom.h,
1702                          output->info.size.w, output->info.size.h,
1703                          output->config.mode.refresh, 0, transform);
1704
1705    ELOGF("TRANSFORM", "output(%s) transform(%d)", NULL, NULL, output->info.name, transform);
1706
1707    return EINA_TRUE;
1708 }
1709
1710 EINTERN Eina_Bool
1711 e_output_update(E_Output *output)
1712 {
1713    E_Output_Mode *m = NULL;
1714    Eina_List *modes = NULL;
1715    Eina_Bool connected = EINA_TRUE;
1716    tdm_error error;
1717    tdm_output_conn_status status;
1718    int i;
1719
1720    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
1721
1722    error = tdm_output_get_conn_status(output->toutput, &status);
1723    if (error != TDM_ERROR_NONE)
1724      {
1725         ERR("failt to get conn status.");
1726         return EINA_FALSE;
1727      }
1728
1729    if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) connected = EINA_FALSE;
1730
1731    if (connected)
1732      {
1733         /* disconnect --> connect */
1734         if (connected != output->info.connected)
1735           {
1736              char *name;
1737              const char *screen;
1738              const char *maker;
1739              unsigned int phy_w, phy_h;
1740              const tdm_output_mode *tmodes = NULL;
1741              int num_tmodes = 0;
1742              unsigned int pipe = 0;
1743              int size = 0;
1744
1745              error = tdm_output_get_model_info(output->toutput, &maker, &screen, NULL);
1746              if (error != TDM_ERROR_NONE)
1747                {
1748                   ERR("fail to get model info.");
1749                   return EINA_FALSE;
1750                }
1751
1752              /* we apply the screen rotation only for the primary output */
1753              error = tdm_output_get_pipe(output->toutput, &pipe);
1754              if (error == TDM_ERROR_NONE && pipe == 0)
1755                output->config.rotation = e_comp->e_comp_screen->rotation;
1756
1757              if (maker)
1758                {
1759                   size = strlen(output->id) + 1 + strlen(maker) + 1;
1760                   name = calloc(1, size);
1761                   if (!name) return EINA_FALSE;
1762                   snprintf(name, size, "%s-%s", output->id, maker);
1763                }
1764              else
1765                {
1766                   size = strlen(output->id) + 1;
1767                   name = calloc(1, size);
1768                   if (!name) return EINA_FALSE;
1769                   snprintf(name, size, "%s", output->id);
1770                }
1771              INF("E_OUTPUT: screen = %s, name = %s", screen, name);
1772
1773              error = tdm_output_get_physical_size(output->toutput, &phy_w, &phy_h);
1774              if (error != TDM_ERROR_NONE)
1775                {
1776                   ERR("fail to get physical_size.");
1777                   free(name);
1778                   return EINA_FALSE;
1779                }
1780
1781              error = tdm_output_get_available_modes(output->toutput, &tmodes, &num_tmodes);
1782              if (error != TDM_ERROR_NONE || num_tmodes == 0)
1783                {
1784                   ERR("fail to get tmodes");
1785                   free(name);
1786                   return EINA_FALSE;
1787                }
1788
1789              for (i = 0; i < num_tmodes; i++)
1790                {
1791                   E_Output_Mode *rmode;
1792
1793                   rmode = E_NEW(E_Output_Mode, 1);
1794                   if (!rmode) continue;
1795
1796                   if (tmodes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
1797                      rmode->preferred = EINA_TRUE;
1798
1799                   rmode->w = tmodes[i].hdisplay;
1800                   rmode->h = tmodes[i].vdisplay;
1801                   rmode->refresh = tmodes[i].vrefresh;
1802                   rmode->tmode = &tmodes[i];
1803
1804                   modes = eina_list_append(modes, rmode);
1805                }
1806
1807              /* resetting the output->info */
1808              if (output->info.screen) free(output->info.screen);
1809              if (output->info.name) free(output->info.name);
1810              EINA_LIST_FREE(output->info.modes, m) free(m);
1811
1812              output->info.screen = strdup(screen);
1813              output->info.name = name;
1814              output->info.modes = modes;
1815              output->info.size.w = phy_w;
1816              output->info.size.h = phy_h;
1817
1818              output->info.connected = EINA_TRUE;
1819
1820              INF("E_OUTPUT: id(%s) connected..", output->id);
1821           }
1822
1823 #if 0
1824         /* check the crtc setting */
1825         if (status != TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
1826           {
1827               const tdm_output_mode *mode = NULL;
1828
1829               error = tdm_output_get_mode(output->toutput, &mode);
1830               if (error != TDM_ERROR_NONE || mode == NULL)
1831                 {
1832                    ERR("fail to get mode.");
1833                    return EINA_FALSE;
1834                 }
1835
1836               output->config.geom.x = 0;
1837               output->config.geom.y = 0;
1838               output->config.geom.w = mode->hdisplay;
1839               output->config.geom.h = mode->vdisplay;
1840
1841               output->config.mode.w = mode->hdisplay;
1842               output->config.mode.h = mode->vdisplay;
1843               output->config.mode.refresh = mode->vrefresh;
1844
1845               output->config.enabled = 1;
1846
1847               INF("E_OUTPUT: '%s' %i %i %ix%i", output->info.name,
1848                      output->config.geom.x, output->config.geom.y,
1849                      output->config.geom.w, output->config.geom.h);
1850           }
1851 #endif
1852
1853      }
1854    else
1855      {
1856         output->info.connected = EINA_FALSE;
1857
1858         /* reset output info */
1859         if (output->info.screen)
1860           {
1861              free(output->info.screen);
1862              output->info.screen = NULL;
1863           }
1864         if (output->info.name)
1865           {
1866              free(output->info.name);
1867              output->info.name = NULL;
1868           }
1869         EINA_LIST_FREE(output->info.modes, m) free(m);
1870         output->info.modes = NULL;
1871
1872         output->info.size.w = 0;
1873         output->info.size.h = 0;
1874
1875         /* reset output config */
1876         output->config.geom.x = 0;
1877         output->config.geom.y = 0;
1878         output->config.geom.w = 0;
1879         output->config.geom.h = 0;
1880
1881         output->config.mode.w = 0;
1882         output->config.mode.h = 0;
1883         output->config.mode.refresh = 0;
1884
1885         output->config.rotation = 0;
1886         output->config.priority = 0;
1887         output->config.enabled = 0;
1888
1889         INF("E_OUTPUT: disconnected.. id: %s", output->id);
1890      }
1891
1892    /* the index of the tdm_output is higher, the tdm_output is important.
1893    the priority of the e_output is higher, the e_output is more important. */
1894    output->config.priority = 100 - output->index;
1895
1896    return EINA_TRUE;
1897 }
1898
1899 EINTERN Eina_Bool
1900 e_output_mode_apply(E_Output *output, E_Output_Mode *mode)
1901 {
1902    tdm_error error;
1903
1904    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
1905
1906    if (!output->info.connected)
1907      {
1908         ERR("output is not connected.");
1909         return EINA_FALSE;
1910      }
1911
1912    error = tdm_output_set_mode(output->toutput, mode->tmode);
1913    if (error != TDM_ERROR_NONE)
1914      {
1915         ERR("fail to set tmode.");
1916         return EINA_FALSE;
1917      }
1918
1919    output->config.geom.x = 0;
1920    output->config.geom.y = 0;
1921    output->config.geom.w = mode->w;
1922    output->config.geom.h = mode->h;
1923
1924    output->config.mode.w = mode->w;
1925    output->config.mode.h = mode->h;
1926    output->config.mode.refresh = mode->refresh;
1927
1928    output->config.enabled = 1;
1929
1930    INF("E_OUTPUT: '%s' %i %i %ix%i %i %i", output->info.name,
1931        output->config.geom.x, output->config.geom.y,
1932        output->config.geom.w, output->config.geom.h,
1933        output->config.rotation, output->config.priority);
1934
1935    INF("E_OUTPUT: rotation = %d", output->config.rotation);
1936
1937    return EINA_TRUE;
1938 }
1939
1940 EINTERN Eina_Bool
1941 e_output_setup(E_Output *output)
1942 {
1943    Eina_List *l, *ll;
1944    E_Plane *plane = NULL;
1945
1946    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
1947
1948    EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane)
1949      {
1950         if (plane->is_fb)
1951           {
1952              if (!e_plane_setup(plane)) return EINA_FALSE;
1953              else return EINA_TRUE;
1954           }
1955      }
1956
1957    return EINA_FALSE;
1958 }
1959
1960
1961 EINTERN E_Output_Mode *
1962 e_output_best_mode_find(E_Output *output)
1963 {
1964    Eina_List *l = NULL;
1965    E_Output_Mode *mode = NULL;
1966    E_Output_Mode *best_mode = NULL;
1967    int size = 0;
1968    int best_size = 0;
1969    double best_refresh = 0.0;
1970
1971    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
1972    EINA_SAFETY_ON_NULL_RETURN_VAL(output->info.modes, NULL);
1973
1974   if (!output->info.connected)
1975      {
1976         ERR("output is not connected.");
1977         return NULL;
1978      }
1979
1980    EINA_LIST_FOREACH(output->info.modes, l, mode)
1981      {
1982         size = mode->w + mode->h;
1983
1984         if (mode->preferred)
1985           {
1986              best_mode = mode;
1987              best_size = size;
1988              best_refresh = mode->refresh;
1989              break;
1990           }
1991
1992         if (size > best_size)
1993           {
1994              best_mode = mode;
1995              best_size = size;
1996              best_refresh = mode->refresh;
1997              continue;
1998           }
1999         if (size == best_size && mode->refresh > best_refresh)
2000           {
2001              best_mode = mode;
2002              best_refresh = mode->refresh;
2003           }
2004      }
2005
2006    return best_mode;
2007 }
2008
2009 EINTERN Eina_Bool
2010 e_output_connected(E_Output *output)
2011 {
2012    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2013
2014    return output->info.connected;
2015 }
2016
2017 EINTERN Eina_Bool
2018 e_output_dpms_set(E_Output *output, E_OUTPUT_DPMS val)
2019 {
2020    tdm_output_dpms tval;
2021    Eina_Bool ret = EINA_TRUE;
2022    tdm_error error;
2023
2024    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2025
2026    if (val == E_OUTPUT_DPMS_OFF) tval = TDM_OUTPUT_DPMS_OFF;
2027    else if (val == E_OUTPUT_DPMS_ON) tval = TDM_OUTPUT_DPMS_ON;
2028    else if (val == E_OUTPUT_DPMS_STANDBY) tval = TDM_OUTPUT_DPMS_STANDBY;
2029    else if (val == E_OUTPUT_DPMS_SUSPEND) tval = TDM_OUTPUT_DPMS_SUSPEND;
2030    else ret = EINA_FALSE;
2031
2032    if (!ret) return EINA_FALSE;
2033
2034    error = tdm_output_set_dpms(output->toutput, tval);
2035    if (error != TDM_ERROR_NONE)
2036      {
2037         ERR("fail to set the dpms(value:%d).", tval);
2038         return EINA_FALSE;
2039      }
2040
2041    return EINA_TRUE;
2042 }
2043
2044 E_API E_OUTPUT_DPMS
2045 e_output_dpms_get(E_Output *output)
2046 {
2047    EINA_SAFETY_ON_NULL_RETURN_VAL(output, E_OUTPUT_DPMS_OFF);
2048
2049    return output->dpms;
2050 }
2051
2052 EINTERN void
2053 e_output_size_get(E_Output *output, int *w, int *h)
2054 {
2055    EINA_SAFETY_ON_NULL_RETURN(output);
2056
2057    *w = output->config.mode.w;
2058    *h = output->config.mode.h;
2059 }
2060
2061 EINTERN Eina_Bool
2062 e_output_fake_config_set(E_Output *output, int w, int h)
2063 {
2064    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2065
2066    output->config.geom.x = 0;
2067    output->config.geom.y = 0;
2068    output->config.geom.w = w;
2069    output->config.geom.h = h;
2070
2071    output->config.mode.w = w;
2072    output->config.mode.h = h;
2073    output->config.mode.refresh = 60;
2074    output->config.enabled = 1;
2075
2076    return EINA_TRUE;
2077 }
2078
2079
2080 EINTERN Eina_Bool
2081 e_output_render(E_Output *output)
2082 {
2083    E_Plane *plane = NULL;
2084    Eina_List *l;
2085
2086    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2087
2088    EINA_LIST_REVERSE_FOREACH(output->planes, l, plane)
2089      {
2090         if (!e_plane_render(plane))
2091          {
2092             ERR("fail to e_plane_render.");
2093             return EINA_FALSE;
2094          }
2095      }
2096
2097   return EINA_TRUE;
2098 }
2099
2100 EINTERN Eina_Bool
2101 e_output_commit(E_Output *output)
2102 {
2103    E_Plane *plane = NULL, *fb_target = NULL;
2104    Eina_List *l;
2105    Eina_Bool fb_commit = EINA_FALSE;
2106
2107    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2108
2109    if (!output->config.enabled)
2110      {
2111         WRN("E_Output disconnected");
2112         return EINA_FALSE;
2113      }
2114
2115    fb_target = e_output_fb_target_get(output);
2116
2117    /* fetch the fb_target at first */
2118    fb_commit = e_plane_fetch(fb_target);
2119    // TODO: to be fixed. check fps of fb_target currently.
2120    if (fb_commit) _e_output_update_fps();
2121
2122    if (output->zoom_set)
2123      {
2124         /* unset check */
2125         EINA_LIST_FOREACH(output->planes, l, plane)
2126           {
2127              /* skip the fb_target fetch because we do this previously */
2128              if (e_plane_is_fb_target(plane)) continue;
2129              if (!e_plane_is_unset_candidate(plane)) continue;
2130
2131              e_plane_unset_try_set(plane, EINA_TRUE);
2132
2133              /* if the plane is trying to unset,
2134               * 1. if fetching the fb is not available, continue.
2135               * 2. if fetching the fb is available, verify the unset commit check.  */
2136              if (e_plane_is_unset_try(plane))
2137                {
2138                   if (!e_plane_unset_commit_check(plane, fb_commit))
2139                     continue;
2140                }
2141
2142              /* fetch the surface to the plane */
2143              if (!e_plane_fetch(plane)) continue;
2144
2145              if (output->dpms == E_OUTPUT_DPMS_OFF)
2146                e_plane_unfetch(plane);
2147
2148              if (e_plane_is_unset_try(plane))
2149                e_plane_unset_try_set(plane, EINA_FALSE);
2150
2151              if (output->dpms == E_OUTPUT_DPMS_OFF)
2152                {
2153                   if (!e_plane_offscreen_commit(plane))
2154                     ERR("fail to e_plane_offscreen_commit");
2155                }
2156              else
2157                {
2158                   if (!e_plane_commit(plane))
2159                     ERR("fail to e_plane_commit");
2160                }
2161           }
2162
2163         EINA_LIST_FOREACH(output->planes, l, plane)
2164           {
2165              if (e_plane_is_fetch_retry(plane))
2166                {
2167                  if (!e_plane_fetch(plane)) continue;
2168                  if (e_plane_is_fb_target(plane))
2169                    {
2170                       fb_commit = EINA_TRUE;
2171                       _e_output_update_fps();
2172                    }
2173                }
2174           }
2175
2176         /* zoom commit only primary */
2177         if (!fb_commit) return EINA_TRUE;
2178
2179         _e_output_zoom_rotating_check(output);
2180
2181         /* zoom commit */
2182         if (output->dpms == E_OUTPUT_DPMS_OFF)
2183           {
2184              if (!e_plane_offscreen_commit(fb_target))
2185                ERR("fail to e_plane_offscreen_commit");
2186           }
2187         else
2188           {
2189              if (!e_plane_pp_commit(fb_target))
2190                ERR("fail to e_plane_pp_commit");
2191           }
2192      }
2193    else
2194      {
2195         /* set planes */
2196         EINA_LIST_FOREACH(output->planes, l, plane)
2197           {
2198              /* skip the fb_target fetch because we do this previously */
2199              if (e_plane_is_fb_target(plane)) continue;
2200
2201              /* if the plane is the candidate to unset,
2202                 set the plane to be unset_try */
2203              if (e_plane_is_unset_candidate(plane))
2204                e_plane_unset_try_set(plane, EINA_TRUE);
2205
2206              /* if the plane is trying to unset,
2207               * 1. if fetching the fb is not available, continue.
2208               * 2. if fetching the fb is available, verify the unset commit check.  */
2209              if (e_plane_is_unset_try(plane))
2210                {
2211                  if (!e_plane_unset_commit_check(plane, fb_commit))
2212                    continue;
2213                }
2214
2215              /* fetch the surface to the plane */
2216              if (!e_plane_fetch(plane)) continue;
2217
2218              if (e_plane_is_unset_try(plane))
2219                e_plane_unset_try_set(plane, EINA_FALSE);
2220           }
2221
2222         EINA_LIST_FOREACH(output->planes, l, plane)
2223           {
2224              if (e_plane_is_fetch_retry(plane))
2225                {
2226                  if (!e_plane_fetch(plane)) continue;
2227                  if (e_plane_is_fb_target(plane))
2228                    {
2229                       fb_commit = EINA_TRUE;
2230                       _e_output_update_fps();
2231                    }
2232                }
2233           }
2234
2235         EINA_LIST_FOREACH(output->planes, l, plane)
2236           {
2237              if (e_plane_is_unset_try(plane)) continue;
2238
2239              if (output->dpms == E_OUTPUT_DPMS_OFF)
2240                {
2241                   if (!e_plane_offscreen_commit(plane))
2242                     ERR("fail to e_plane_offscreen_commit");
2243                }
2244              else
2245                {
2246                   if (!e_plane_commit(plane))
2247                     ERR("fail to e_plane_commit");
2248                }
2249           }
2250      }
2251
2252    return EINA_TRUE;
2253 }
2254
2255 E_API E_Output *
2256 e_output_find(const char *id)
2257 {
2258    E_Output *output;
2259    E_Comp_Screen *e_comp_screen;
2260    Eina_List *l;
2261
2262    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
2263    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL);
2264    EINA_SAFETY_ON_NULL_RETURN_VAL(id, NULL);
2265
2266    e_comp_screen = e_comp->e_comp_screen;
2267
2268    EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
2269      {
2270         if (!strcmp(output->id, id)) return output;
2271      }
2272    return NULL;
2273 }
2274
2275 E_API const Eina_List *
2276 e_output_planes_get(E_Output *output)
2277 {
2278    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
2279    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, NULL);
2280
2281    return output->planes;
2282 }
2283
2284 E_API void
2285 e_output_util_planes_print(void)
2286 {
2287    Eina_List *l, *ll, *p_l;
2288    E_Output * output = NULL;
2289    E_Comp_Screen *e_comp_screen = NULL;
2290
2291    EINA_SAFETY_ON_NULL_RETURN(e_comp);
2292    EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
2293
2294    e_comp_screen = e_comp->e_comp_screen;
2295
2296    EINA_LIST_FOREACH_SAFE(e_comp_screen->outputs, l, ll, output)
2297      {
2298         E_Plane *plane;
2299         E_Client *ec;
2300
2301         if (!output || !output->planes) continue;
2302
2303         fprintf(stderr, "HWC in %s .. \n", output->id);
2304         fprintf(stderr, "HWC \tzPos \t on_plane \t\t\t\t on_prepare \t \n");
2305
2306         EINA_LIST_REVERSE_FOREACH(output->planes, p_l, plane)
2307           {
2308              ec = plane->ec;
2309              if (ec) fprintf(stderr, "HWC \t[%d]%s\t %s (0x%08x)",
2310                              plane->zpos,
2311                              plane->is_primary ? "--" : "  ",
2312                              ec->icccm.title, (unsigned int)ec->frame);
2313
2314              ec = plane->prepare_ec;
2315              if (ec) fprintf(stderr, "\t\t\t %s (0x%08x)",
2316                              ec->icccm.title, (unsigned int)ec->frame);
2317              fputc('\n', stderr);
2318           }
2319         fputc('\n', stderr);
2320      }
2321 }
2322
2323 E_API Eina_Bool
2324 e_output_is_fb_composing(E_Output *output)
2325 {
2326    Eina_List *p_l;
2327    E_Plane *ep;
2328
2329    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2330    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
2331
2332    EINA_LIST_FOREACH(output->planes, p_l, ep)
2333      {
2334         if (e_plane_is_fb_target(ep))
2335           {
2336              if(ep->ec == NULL) return EINA_TRUE;
2337           }
2338      }
2339
2340    return EINA_FALSE;
2341 }
2342
2343 E_API Eina_Bool
2344 e_output_is_fb_full_compositing(E_Output *output)
2345 {
2346    Eina_List *p_l;
2347    E_Plane *ep;
2348
2349    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2350    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
2351
2352    EINA_LIST_FOREACH(output->planes, p_l, ep)
2353      if(ep->ec) return EINA_FALSE;
2354
2355    return EINA_FALSE;
2356 }
2357
2358 E_API E_Plane *
2359 e_output_fb_target_get(E_Output *output)
2360 {
2361    Eina_List *p_l;
2362    E_Plane *ep;
2363
2364    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2365    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
2366
2367    EINA_LIST_FOREACH(output->planes, p_l, ep)
2368      {
2369         if (e_plane_is_fb_target(ep))
2370           return ep;
2371      }
2372
2373    return NULL;
2374 }
2375
2376 EINTERN E_Plane *
2377 e_output_default_fb_target_get(E_Output *output)
2378 {
2379    Eina_List *p_l;
2380    E_Plane *ep;
2381
2382    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2383    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
2384
2385    if (e_comp->hwc_ignore_primary)
2386      {
2387         /* find lowest zpos graphic type layer */
2388         EINA_LIST_FOREACH(output->planes, p_l, ep)
2389           {
2390              Eina_List *formats = NULL;
2391              Eina_List *formats_l = NULL;
2392              Eina_Bool available_rgb = EINA_FALSE;
2393              tbm_format *format;
2394
2395              if (e_plane_type_get(ep) != E_PLANE_TYPE_GRAPHIC) continue;
2396
2397              formats = e_plane_available_formats_get(ep);
2398              if (!formats) continue;
2399
2400              EINA_LIST_FOREACH(formats, formats_l, format)
2401                {
2402                   if (*format == TBM_FORMAT_ARGB8888 ||
2403                       *format == TBM_FORMAT_XRGB8888)
2404                     {
2405                        available_rgb = EINA_TRUE;
2406                        break;
2407                     }
2408                }
2409
2410              if (!available_rgb) continue;
2411
2412              return ep;
2413           }
2414      }
2415    else
2416      {
2417         /* find primary layer */
2418         EINA_LIST_FOREACH(output->planes, p_l, ep)
2419           {
2420              if (ep->is_primary)
2421                return ep;
2422           }
2423      }
2424
2425    return NULL;
2426 }
2427
2428 E_API E_Output *
2429 e_output_find_by_index(int index)
2430 {
2431    E_Output *output;
2432    E_Comp_Screen *e_comp_screen;
2433    Eina_List *l;
2434
2435    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
2436    EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL);
2437
2438    e_comp_screen = e_comp->e_comp_screen;
2439
2440    EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
2441      {
2442         if (output->index == index)
2443           return output;
2444      }
2445
2446    return NULL;
2447 }
2448
2449 E_API E_Plane *
2450 e_output_plane_get_by_zpos(E_Output *output, int zpos)
2451 {
2452    Eina_List *p_l;
2453    E_Plane *ep;
2454
2455    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2456    EINA_SAFETY_ON_NULL_RETURN_VAL(output->planes, EINA_FALSE);
2457
2458    EINA_LIST_FOREACH(output->planes, p_l, ep)
2459      {
2460         if (ep->zpos == zpos)
2461           return ep;
2462      }
2463
2464    return NULL;
2465 }
2466
2467 EINTERN Eina_Bool
2468 e_output_zoom_set(E_Output *output, double zoomx, double zoomy, int cx, int cy)
2469 {
2470    E_Plane *ep = NULL;
2471    int w, h;
2472    int angle = 0;
2473
2474    if (!e_comp_screen_pp_support())
2475      {
2476         WRN("Comp Screen does not support the Zoom.");
2477         return EINA_FALSE;
2478      }
2479
2480    EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
2481
2482    e_output_size_get(output, &w, &h);
2483    angle = _e_output_zoom_get_angle(output);
2484
2485    if (cx < 0 || cy < 0) return EINA_FALSE;
2486    if (zoomx <= 0 || zoomy <= 0) return EINA_FALSE;
2487    if (angle % 180 == 0)
2488      {
2489         if (cx >= w || cy >= h) return EINA_FALSE;
2490      }
2491    else
2492      {
2493         if (cx >= h || cy >= w) return EINA_FALSE;
2494      }
2495
2496    ep = e_output_fb_target_get(output);
2497    EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE);
2498
2499 #ifdef ENABLE_HWC_MULTI
2500    e_comp_hwc_multi_plane_set(EINA_FALSE);
2501 #endif
2502
2503    output->zoom_conf.zoomx = zoomx;
2504    output->zoom_conf.zoomy = zoomy;
2505    output->zoom_conf.init_cx = cx;
2506    output->zoom_conf.init_cy = cy;
2507    output->zoom_conf.init_angle = angle;
2508    output->zoom_conf.current_angle = angle;
2509
2510    _e_output_zoom_coordinate_cal_with_angle(output, angle);
2511
2512    /* get the scaled rect */
2513    _e_output_zoom_scaled_rect_get(w, h, output->zoom_conf.zoomx, output->zoom_conf.zoomy,
2514                                   output->zoom_conf.adjusted_cx, output->zoom_conf.adjusted_cy, &output->zoom_conf.rect);
2515
2516    if (!e_plane_zoom_set(ep, &output->zoom_conf.rect))
2517      {
2518         ERR("e_plane_zoom_set failed.");
2519 #ifdef ENABLE_HWC_MULTI
2520         e_comp_hwc_multi_plane_set(EINA_TRUE);
2521 #endif
2522         return EINA_FALSE;
2523      }
2524
2525    if (!_e_output_zoom_touch_set(output))
2526      ERR("fail _e_output_zoom_touch_set");
2527
2528    if (!output->zoom_set) output->zoom_set = EINA_TRUE;
2529    DBG("zoom set output:%s, zoom(x:%f, y:%f, cx:%d, cy:%d) rect(x:%d, y:%d, w:%d, h:%d)",
2530        output->id, zoomx, zoomy, cx, cy,
2531        output->zoom_conf.rect.x, output->zoom_conf.rect.y, output->zoom_conf.rect.w, output->zoom_conf.rect.h);
2532
2533    /* update the ecore_evas */
2534    _e_output_render_update(output);
2535
2536    return EINA_TRUE;
2537 }
2538
2539 EINTERN void
2540 e_output_zoom_unset(E_Output *output)
2541 {
2542    E_Plane *ep = NULL;
2543
2544    EINA_SAFETY_ON_NULL_RETURN(output);
2545
2546    if (!output->zoom_set) return;
2547
2548    ep = e_output_fb_target_get(output);
2549    EINA_SAFETY_ON_NULL_RETURN(ep);
2550
2551    if (!_e_output_zoom_touch_unset(output))
2552      ERR("fail _e_output_zoom_touch_unset");
2553
2554    output->zoom_conf.zoomx = 0;
2555    output->zoom_conf.zoomy = 0;
2556    output->zoom_conf.init_cx = 0;
2557    output->zoom_conf.init_cy = 0;
2558    output->zoom_conf.init_angle = 0;
2559    output->zoom_conf.current_angle = 0;
2560    output->zoom_conf.adjusted_cx = 0;
2561    output->zoom_conf.adjusted_cy = 0;
2562    output->zoom_conf.rect.x = 0;
2563    output->zoom_conf.rect.y = 0;
2564    output->zoom_conf.rect.w = 0;
2565    output->zoom_conf.rect.h = 0;
2566
2567    e_plane_zoom_unset(ep);
2568
2569    output->zoom_set = EINA_FALSE;
2570
2571 #ifdef ENABLE_HWC_MULTI
2572    e_comp_hwc_multi_plane_set(EINA_TRUE);
2573 #endif
2574
2575    /* update the ecore_evas */
2576    _e_output_render_update(output);
2577
2578    DBG("e_output_zoom_unset: output:%s", output->id);
2579 }
2580
2581 E_API E_Output_Hook *
2582 e_output_hook_add(E_Output_Hook_Point hookpoint, E_Output_Hook_Cb func, const void *data)
2583 {
2584    E_Output_Hook *ch;
2585
2586    EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_OUTPUT_HOOK_LAST, NULL);
2587    ch = E_NEW(E_Output_Hook, 1);
2588    if (!ch) return NULL;
2589    ch->hookpoint = hookpoint;
2590    ch->func = func;
2591    ch->data = (void*)data;
2592    _e_output_hooks[hookpoint] = eina_inlist_append(_e_output_hooks[hookpoint], EINA_INLIST_GET(ch));
2593    return ch;
2594 }
2595
2596 E_API void
2597 e_output_hook_del(E_Output_Hook *ch)
2598 {
2599    ch->delete_me = 1;
2600    if (_e_output_hooks_walking == 0)
2601      {
2602         _e_output_hooks[ch->hookpoint] = eina_inlist_remove(_e_output_hooks[ch->hookpoint], EINA_INLIST_GET(ch));
2603         free(ch);
2604      }
2605    else
2606      _e_output_hooks_delete++;
2607 }
2608
2609 EINTERN Eina_Bool
2610 e_output_capture(E_Output *output, tbm_surface_h tsurface, Eina_Bool auto_rotate, E_Output_Capture_Cb func, void *data)
2611 {
2612    Eina_Bool ret = EINA_FALSE;
2613    tdm_capture *tcapture = NULL;
2614
2615    if (e_output_dpms_get(output))
2616      {
2617         func(output, tsurface, data);
2618         return EINA_TRUE;
2619      }
2620
2621    tcapture = _e_output_tdm_capture_create(output, TDM_CAPTURE_CAPABILITY_ONESHOT);
2622    if (tcapture)
2623      {
2624         ret = _e_output_tdm_capture_info_set(output, tcapture, tsurface, TDM_CAPTURE_TYPE_ONESHOT, auto_rotate);
2625         EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
2626
2627         ret = _e_output_tdm_capture(output, tcapture, tsurface, func, data);
2628         EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
2629      }
2630    else
2631      {
2632         ret = _e_output_capture(output, tsurface, auto_rotate);
2633         EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
2634
2635         DBG("capture done(%p)", tsurface);
2636
2637         func(output, tsurface, data);
2638      }
2639
2640    return EINA_TRUE;
2641
2642 fail:
2643    if (tcapture)
2644      tdm_capture_destroy(tcapture);
2645
2646    return EINA_FALSE;
2647 }
2648
2649 EINTERN Eina_Bool
2650 e_output_stream_capture_queue(E_Output *output, tbm_surface_h tsurface, E_Output_Capture_Cb func, void *data)
2651 {
2652    Eina_Bool ret = EINA_FALSE;
2653    tdm_capture *tcapture = NULL;
2654    tdm_error error = TDM_ERROR_NONE;
2655
2656    if (output->stream_capture.possible_tdm_capture)
2657      {
2658         if (!output->stream_capture.tcapture)
2659           {
2660              tcapture = _e_output_tdm_capture_create(output, TDM_CAPTURE_CAPABILITY_STREAM);
2661              EINA_SAFETY_ON_NULL_RETURN_VAL(tcapture, EINA_FALSE);
2662
2663              ret = _e_output_tdm_capture_info_set(output, tcapture, tsurface, TDM_CAPTURE_TYPE_STREAM, EINA_FALSE);
2664              EINA_SAFETY_ON_FALSE_GOTO(ret == EINA_TRUE, fail);
2665
2666              error = tdm_capture_set_done_handler(tcapture,
2667                                                   _e_output_tdm_stream_capture_done_handler, output);
2668              EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
2669
2670              output->stream_capture.tcapture = tcapture;
2671
2672              DBG("create tcapture(%p)", tcapture);
2673           }
2674         else
2675           {
2676              tcapture = output->stream_capture.tcapture;
2677           }
2678
2679         ret = _e_output_tdm_stream_capture(output, tcapture, tsurface, func, data);
2680         EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == EINA_TRUE, EINA_FALSE);
2681      }
2682    else
2683      {
2684         ret = _e_output_vblank_stream_capture(output, tsurface, func, data);
2685         EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == EINA_TRUE, EINA_FALSE);
2686      }
2687
2688    return EINA_TRUE;
2689
2690 fail:
2691    tdm_capture_destroy(tcapture);
2692
2693    return EINA_FALSE;
2694 }
2695
2696 EINTERN Eina_Bool
2697 e_output_stream_capture_dequeue(E_Output *output, tbm_surface_h tsurface)
2698 {
2699    E_Output_Capture *cdata = NULL;
2700
2701    cdata = _e_output_tdm_stream_capture_find_data(output, tsurface);
2702
2703    if (!cdata) return EINA_FALSE;
2704
2705    if (!cdata->in_using)
2706      {
2707         output->stream_capture.data = eina_list_remove(output->stream_capture.data, cdata);
2708
2709         tbm_surface_internal_unref(tsurface);
2710         E_FREE(cdata);
2711      }
2712    else
2713      cdata->dequeued = EINA_TRUE;
2714
2715    return EINA_TRUE;
2716 }
2717
2718 EINTERN Eina_Bool
2719 e_output_stream_capture_start(E_Output *output)
2720 {
2721    tdm_error error = TDM_ERROR_NONE;
2722    int count = 0;
2723
2724    if (output->stream_capture.start) return EINA_TRUE;
2725
2726    count = eina_list_count(output->stream_capture.data);
2727    if (count == 0)
2728      {
2729         ERR("no queued buffer");
2730         return EINA_FALSE;
2731      }
2732
2733    DBG("e_output stream capture start.");
2734
2735    output->stream_capture.start = EINA_TRUE;
2736
2737    if (output->stream_capture.possible_tdm_capture)
2738      {
2739         if (e_output_dpms_get(output))
2740           {
2741              if (!output->stream_capture.timer)
2742                output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
2743                                                               _e_output_stream_capture_cb_timeout, output);
2744              EINA_SAFETY_ON_NULL_GOTO(output->stream_capture.timer, fail);
2745
2746              return EINA_TRUE;
2747           }
2748
2749         error = tdm_capture_commit(output->stream_capture.tcapture);
2750         EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
2751      }
2752    else
2753      _e_output_watch_vblank(output);
2754
2755    return EINA_TRUE;
2756
2757 fail:
2758    output->stream_capture.start = EINA_FALSE;
2759
2760    return EINA_FALSE;
2761 }
2762
2763 EINTERN void
2764 e_output_stream_capture_stop(E_Output *output)
2765 {
2766    E_Output_Capture *cdata = NULL;
2767    Eina_Bool capturing = EINA_FALSE;
2768    Eina_List *l;
2769
2770    if (!output->stream_capture.start) return;
2771
2772    output->stream_capture.start = EINA_FALSE;
2773
2774    if (eina_list_count(output->stream_capture.data) == 0)
2775      {
2776         if (!output->stream_capture.timer)
2777           {
2778              output->stream_capture.timer = ecore_timer_add((double)1 / DUMP_FPS,
2779                                             _e_output_tdm_stream_capture_stop, output);
2780              return;
2781           }
2782      }
2783
2784    if (!output->stream_capture.timer && !output->stream_capture.wait_vblank)
2785      {
2786         EINA_LIST_FOREACH(output->stream_capture.data, l, cdata)
2787           {
2788              if (cdata->in_using)
2789                capturing = EINA_TRUE;
2790           }
2791
2792         if (capturing == EINA_FALSE)
2793           {
2794              EINA_LIST_FREE(output->stream_capture.data, cdata)
2795                {
2796                   tbm_surface_internal_unref(cdata->surface);
2797
2798                   E_FREE(cdata);
2799                }
2800
2801              if (output->stream_capture.tcapture)
2802                {
2803                   tdm_capture_destroy(output->stream_capture.tcapture);
2804                   output->stream_capture.tcapture = NULL;
2805                }
2806           }
2807
2808         DBG("e_output stream capture stop.");
2809      }
2810 }