e_client: use e_client_visibility_set/get funtions
[platform/upstream/enlightenment.git] / src / bin / video / iface / e_video_hwc.c
1 #include "e_zone_video_intern.h"
2 #include "e_client_video_intern.h"
3 #include "e_video_hwc_intern.h"
4 #include "e_comp_screen_intern.h"
5 #include "e_comp_wl_intern.h"
6 #include "e_comp_wl_subsurface_intern.h"
7 #include "e_comp_wl_viewport_intern.h"
8 #include "e_output_intern.h"
9 #include "e_comp_wl_video_buffer_intern.h"
10 #include "e_util_video_intern.h"
11 #include "e_video_debug_intern.h"
12 #include "e_client_intern.h"
13
14 #include <wayland-tbm-server.h>
15
16 #ifdef DUMP_BUFFER
17 #include <tdm_helper.h>
18 #endif
19
20 #define GEO_FMT   "(%dx%d+%d+%d) -> (%dx%d+%d+%d) transform(%d)"
21 #define GEO_ARG(g) \
22    (g)->input_r.w, (g)->input_r.h, (g)->input_r.x, (g)->input_r.y, \
23    (g)->output_r.w, (g)->output_r.h, (g)->output_r.x, (g)->output_r.y, \
24    (g)->transform
25
26 #define IFACE_ENTRY                                      \
27    E_Video_Hwc *evh;                                    \
28    evh = container_of(iface, E_Video_Hwc, iface)
29
30 static Eina_Bool _e_video_hwc_render(E_Video_Hwc *evh, const char *func);
31 static void _e_video_hwc_buffer_show(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf, unsigned int transform);
32 static void _e_video_hwc_buffer_commit(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf);
33
34 static E_Client *
35 _e_video_hwc_client_offscreen_parent_get(E_Client *ec)
36 {
37    E_Client *parent = NULL;
38
39    if (!e_comp_wl_subsurface_check(ec))
40      return NULL;
41
42    parent = e_comp_wl_subsurface_parent_get(ec);
43    while (parent)
44      {
45         if (!e_comp_wl_subsurface_check(parent))
46           return NULL;
47
48         if (parent->comp_data->sub.data->remote_surface.offscreen_parent)
49           return parent->comp_data->sub.data->remote_surface.offscreen_parent;
50
51         parent = e_comp_wl_subsurface_parent_get(parent);
52      }
53
54    return NULL;
55 }
56
57 static Eina_Bool
58 _e_video_hwc_client_visible_get(E_Client *ec)
59 {
60    E_Client *offscreen_parent;
61
62    if (!e_pixmap_resource_get(ec->pixmap))
63      {
64         VDB("no comp buffer", ec);
65         return EINA_FALSE;
66      }
67
68    if ((e_comp_wl_subsurface_check(ec)) &&
69        (e_comp_wl_subsurface_stand_alone_mode_get(ec)))
70      return EINA_TRUE;
71
72    offscreen_parent = _e_video_hwc_client_offscreen_parent_get(ec);
73    if (offscreen_parent && e_client_visibility_get(offscreen_parent) == E_VISIBILITY_FULLY_OBSCURED)
74      {
75         VDB("video surface invisible: offscreen fully obscured", ec);
76         return EINA_FALSE;
77      }
78
79    if (!evas_object_visible_get(ec->frame))
80      {
81         VDB("evas obj invisible", ec);
82         return EINA_FALSE;
83      }
84
85    return EINA_TRUE;
86 }
87
88 /* Video Buffer implementation */
89 static E_Comp_Wl_Video_Buf *
90 _e_video_hwc_vbuf_find(Eina_List *list, tbm_surface_h buffer)
91 {
92    E_Comp_Wl_Video_Buf *vbuf;
93    Eina_List *l = NULL;
94
95    EINA_LIST_FOREACH(list, l, vbuf)
96      {
97         if (vbuf->tbm_surface == buffer)
98           return vbuf;
99      }
100
101    return NULL;
102 }
103
104 static E_Comp_Wl_Video_Buf *
105 _e_video_hwc_vbuf_find_with_comp_buffer(Eina_List *list, E_Comp_Wl_Buffer *comp_buffer)
106 {
107    E_Comp_Wl_Video_Buf *vbuf;
108    Eina_List *l = NULL;
109
110    EINA_LIST_FOREACH(list, l, vbuf)
111      {
112         if (vbuf->comp_buffer == comp_buffer)
113           return vbuf;
114      }
115
116    return NULL;
117 }
118
119 static Eina_Bool
120 _e_video_hwc_video_buffer_scanout_check(E_Comp_Wl_Video_Buf *vbuf)
121 {
122    tbm_surface_h tbm_surface = NULL;
123    tbm_bo bo = NULL;
124    int flag;
125
126    tbm_surface = vbuf->tbm_surface;
127    EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, EINA_FALSE);
128
129    bo = tbm_surface_internal_get_bo(tbm_surface, 0);
130    EINA_SAFETY_ON_NULL_RETURN_VAL(bo, EINA_FALSE);
131
132    flag = tbm_bo_get_flags(bo);
133    if (flag & TBM_BO_SCANOUT)
134      return EINA_TRUE;
135
136    return EINA_FALSE;
137 }
138
139 static void
140 _e_video_hwc_input_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
141 {
142    E_Video_Hwc *evh = data;
143    Eina_Bool need_hide = EINA_FALSE;
144
145    DBG("Buffer(%p) to be free, refcnt(%d)", vbuf, vbuf->ref_cnt);
146
147    evh->input_buffer_list = eina_list_remove(evh->input_buffer_list, vbuf);
148
149    if (vbuf->comp_buffer)
150      e_comp_wl_buffer_reference(&vbuf->buffer_ref, NULL);
151
152    if (evh->current_fb == vbuf)
153      {
154         VIN("current fb destroyed", evh->ec);
155         e_comp_wl_video_buffer_set_use(evh->current_fb, EINA_FALSE);
156         evh->current_fb = NULL;
157         need_hide = EINA_TRUE;
158      }
159
160    if (evh->committed_vbuf == vbuf)
161      {
162         VIN("committed fb destroyed", evh->ec);
163         e_comp_wl_video_buffer_set_use(evh->committed_vbuf, EINA_FALSE);
164         evh->committed_vbuf = NULL;
165         need_hide = EINA_TRUE;
166      }
167
168    if (eina_list_data_find(evh->bqueue, vbuf))
169      {
170         VIN("waiting fb destroyed", evh->ec);
171         evh->bqueue = eina_list_remove(evh->bqueue, vbuf);
172      }
173
174    if (need_hide)
175      evh->backend.buffer_commit(evh, NULL);
176 }
177
178 static E_Comp_Wl_Video_Buf *
179 _e_video_hwc_input_buffer_get(E_Video_Hwc *evh, E_Comp_Wl_Buffer *comp_buffer)
180 {
181    E_Comp_Wl_Video_Buf *vbuf;
182
183    vbuf = _e_video_hwc_vbuf_find_with_comp_buffer(evh->input_buffer_list, comp_buffer);
184    if (vbuf)
185      goto end;
186
187    vbuf = e_comp_wl_video_buffer_create_comp(comp_buffer);
188    if (!vbuf)
189      {
190         VER("failed 'e_comp_wl_video_buffer_create_comp()'", evh->ec);
191         return NULL;
192      }
193
194    DBG("Buffer(%p) created, refcnt:%d", vbuf, vbuf->ref_cnt);
195
196    evh->input_buffer_list = eina_list_append(evh->input_buffer_list, vbuf);
197    e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_hwc_input_buffer_cb_free, evh);
198
199    struct wl_resource *surface = e_comp_wl_client_surface_get(evh->ec);
200    DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p) created",
201        e_client_util_name_get(evh->ec) ?: "No Name" , evh->ec->netwm.pid,
202        wl_resource_get_id(surface), vbuf);
203 end:
204    vbuf->content_r = evh->geo.input_r;
205    return vbuf;
206 }
207 /* End of Video Buffer implementation */
208
209 /* PP implementation */
210 static void
211 _e_video_hwc_pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
212 {
213    E_Video_Hwc *evh = (E_Video_Hwc *)user_data;
214    E_Comp_Wl_Video_Buf *input_buffer, *pp_buffer;
215
216    input_buffer = _e_video_hwc_vbuf_find(evh->input_buffer_list, sb);
217    if (input_buffer)
218      e_comp_wl_video_buffer_unref(input_buffer);
219
220    pp_buffer = _e_video_hwc_vbuf_find(evh->pp_buffer_list, db);
221    if (pp_buffer)
222      {
223         e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
224         if (!_e_video_hwc_client_visible_get(evh->ec)) return;
225
226         _e_video_hwc_buffer_show(evh, pp_buffer, 0);
227      }
228    else
229      {
230         VER("There is no pp_buffer", evh->ec);
231         // there is no way to set in_use flag.
232         // This will cause issue when server get available pp_buffer.
233      }
234 }
235
236 static void
237 _e_video_hwc_pp_destroy(E_Video_Hwc_PP *pp)
238 {
239    tdm_pp_destroy(pp->tdm_handle);
240    free(pp);
241 }
242
243 static E_Video_Hwc_PP *
244 _e_video_hwc_pp_create(tdm_display *display, void *user_data)
245 {
246    E_Video_Hwc_PP *pp;
247    tdm_pp_capability caps;
248    tdm_error err;
249
250    pp = E_NEW(E_Video_Hwc_PP, 1);
251    if (!pp)
252      return NULL;
253
254    pp->tdm_handle = tdm_display_create_pp(display, NULL);
255    if (!pp->tdm_handle)
256      {
257         VER("Failed 'tdm_display_create_pp()'", NULL);
258         free(pp);
259         return NULL;
260      }
261
262    tdm_display_get_pp_available_size(display,
263                                      &pp->minw, &pp->minh,
264                                      &pp->maxw, &pp->maxh,
265                                      &pp->align);
266    tdm_display_get_pp_preferred_align_vertical(display, &pp->align_vertical);
267
268    err = tdm_display_get_pp_capabilities(display, &caps);
269    if (err == TDM_ERROR_NONE)
270      {
271         if ((caps & TDM_PP_CAPABILITY_NO_CSC) || (caps & TDM_PP_CAPABILITY_NO_TRANSFORM_ROTATION))
272           {
273              VER("tdm pp not support csc or transform", NULL);
274              goto not_support;
275           }
276
277         if (caps & TDM_PP_CAPABILITY_SCANOUT)
278           pp->scanout = EINA_TRUE;
279      }
280
281    err = tdm_pp_set_done_handler(pp->tdm_handle, _e_video_hwc_pp_cb_done, user_data);
282    if (err != TDM_ERROR_NONE)
283      {
284         VER("tdm_pp_set_done_handler() failed", NULL);
285         goto not_support;
286      }
287
288    return pp;
289
290 not_support:
291         tdm_pp_destroy(pp->tdm_handle);
292         free(pp);
293         return NULL;
294 }
295
296 static Eina_Bool
297 _e_video_hwc_pp_size_limit_check(E_Video_Hwc_PP *pp, const Eina_Rectangle *input_rect, const Eina_Rectangle *output_rect)
298 {
299    if (pp->minw > 0)
300      {
301         if ((input_rect->w < pp->minw) ||
302             (output_rect->w < pp->minw))
303           goto err;
304      }
305
306    if (pp->minh > 0)
307      {
308         if ((input_rect->h < pp->minh) ||
309             (output_rect->h < pp->minh))
310           goto err;
311      }
312
313    if (pp->maxw > 0)
314      {
315         if ((input_rect->w > pp->maxw) ||
316             (output_rect->w > pp->maxw))
317           goto err;
318      }
319
320    if (pp->maxh > 0)
321      {
322         if ((input_rect->h > pp->maxh) ||
323             (output_rect->h > pp->maxh))
324           goto err;
325      }
326
327    return EINA_TRUE;
328 err:
329    INF("size(%dx%d, %dx%d) is out of PP range",
330        input_rect->w, input_rect->h, output_rect->w, output_rect->h);
331
332    return EINA_FALSE;
333 }
334
335 static E_Comp_Wl_Video_Buf *
336 _e_video_hwc_pp_input_buffer_get(E_Video_Hwc *evh, E_Comp_Wl_Buffer *comp_buffer)
337 {
338    E_Comp_Wl_Video_Buf *vbuf;
339    Eina_Bool input_buffer_scanout;
340
341    vbuf = _e_video_hwc_vbuf_find_with_comp_buffer(evh->input_buffer_list, comp_buffer);
342    if (vbuf)
343      goto end;
344
345    vbuf = e_comp_wl_video_buffer_create_comp(comp_buffer);
346    if (!vbuf)
347      {
348         VER("failed to create video buffer", evh->ec);
349         return NULL;
350      }
351
352    input_buffer_scanout = _e_video_hwc_video_buffer_scanout_check(vbuf);
353
354    if (((evh->pp->align != -1) && (vbuf->width_from_pitch % evh->pp->align != 0)) ||
355        ((evh->pp->scanout) && (!input_buffer_scanout)))
356      {
357         VER("cannot use this input buffer as an source buffer for pp: "
358             "pp align(%d) bwidth(%d) pp scanout(%d) bscanout(%d)", evh->ec,
359             evh->pp->align, vbuf->width_from_pitch, evh->pp->scanout,
360             input_buffer_scanout);
361         e_comp_wl_video_buffer_unref(vbuf);
362         return NULL;
363      }
364
365    DBG("Buffer(%p) created, refcnt:%d scanout:%d",
366        vbuf, vbuf->ref_cnt, (evh->pp->scanout || input_buffer_scanout));
367
368    evh->input_buffer_list = eina_list_append(evh->input_buffer_list, vbuf);
369    e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_hwc_input_buffer_cb_free, evh);
370
371    struct wl_resource *surface = e_comp_wl_client_surface_get(evh->ec);
372    DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p) created",
373        e_client_util_name_get(evh->ec) ?: "No Name" , evh->ec->netwm.pid,
374        wl_resource_get_id(surface), vbuf);
375 end:
376    vbuf->content_r = evh->geo.input_r;
377    return vbuf;
378 }
379
380 static void
381 _e_video_hwc_pp_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
382 {
383    E_Video_Hwc *evh = data;
384
385    e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
386
387    if (evh->current_fb == vbuf)
388      evh->current_fb = NULL;
389
390    if (evh->committed_vbuf == vbuf)
391      evh->committed_vbuf = NULL;
392
393    evh->bqueue = eina_list_remove(evh->bqueue, vbuf);
394
395    evh->pp_buffer_list = eina_list_remove(evh->pp_buffer_list, vbuf);
396 }
397
398 static int
399 _e_video_hwc_pp_gcd_get(int x, int y)
400 {
401    int temp = 0;
402
403    while (y > 0)
404      {
405         temp = y;
406         y = x % y;
407         x = temp;
408      }
409
410    return x;
411 }
412
413 static void
414 _e_video_hwc_pp_aligned_value_get(E_Video_Hwc *evh, int *aligned_width, int *aligned_height)
415 {
416    int width_align = 0;
417
418    if (evh->pp->minw != -1)
419      {
420         if (evh->pp->minw > *aligned_width)
421           *aligned_width = evh->pp->minw;
422      }
423
424    if (evh->pp->minh != -1)
425      {
426         if (evh->pp->minh > *aligned_height)
427           *aligned_height = evh->pp->minh;
428      }
429
430    if (evh->pp->align > 0)
431      {
432         if (evh->output_align != -1)
433           {
434              if (evh->output_align >= evh->pp->align)
435                width_align = _e_video_hwc_pp_gcd_get(evh->output_align, evh->pp->align);
436              else
437                width_align = _e_video_hwc_pp_gcd_get(evh->pp->align, evh->output_align);
438
439              width_align = evh->output_align * evh->pp->align / width_align;
440           }
441         else
442           {
443              width_align = evh->pp->align;
444           }
445      }
446    else
447      {
448         if (evh->output_align != -1)
449           width_align = evh->output_align;
450         else
451           width_align = *aligned_width;
452      }
453
454    *aligned_width = ROUNDUP(*aligned_width, width_align);
455
456    if (evh->pp->align_vertical != -1)
457      *aligned_height = ROUNDUP(*aligned_height, evh->pp->align_vertical);
458
459 }
460
461 static E_Comp_Wl_Video_Buf *
462 _e_video_hwc_pp_buffer_get(E_Video_Hwc *evh, int width, int height)
463 {
464    E_Comp_Wl_Video_Buf *vbuf;
465    Eina_List *l;
466    int i = 0;
467    int aligned_width = width;
468    int aligned_height = height;
469
470    _e_video_hwc_pp_aligned_value_get(evh, &aligned_width, &aligned_height);
471
472    if (evh->pp_buffer_list)
473      {
474         vbuf = eina_list_data_get(evh->pp_buffer_list);
475         EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
476
477         /* if we need bigger pp_buffers, destroy all pp_buffers and create */
478         if (aligned_width > vbuf->width_from_pitch || aligned_height != vbuf->height)
479           {
480              Eina_List *ll;
481
482              VIN("pp buffer changed: %dx%d => %dx%d", evh->ec,
483                  vbuf->width_from_pitch, vbuf->height,
484                  aligned_width, aligned_height);
485
486              EINA_LIST_FOREACH_SAFE(evh->pp_buffer_list, l, ll, vbuf)
487                {
488                   /* free forcely */
489                   e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
490                   e_comp_wl_video_buffer_unref(vbuf);
491                }
492              if (evh->pp_buffer_list)
493                NEVER_GET_HERE();
494
495              if (evh->bqueue)
496                NEVER_GET_HERE();
497           }
498      }
499
500    if (!evh->pp_buffer_list)
501      {
502         for (i = 0; i < BUFFER_MAX_COUNT; i++)
503           {
504              vbuf = e_comp_wl_video_buffer_alloc(aligned_width, aligned_height, evh->pp_tbmfmt, EINA_TRUE);
505              EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
506
507              e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_hwc_pp_buffer_cb_free, evh);
508              evh->pp_buffer_list = eina_list_append(evh->pp_buffer_list, vbuf);
509
510           }
511
512         VIN("pp buffer created: %dx%d, %c%c%c%c", evh->ec,
513             vbuf->width_from_pitch, aligned_height, FOURCC_STR(evh->pp_tbmfmt));
514
515         evh->next_buffer = evh->pp_buffer_list;
516      }
517
518    EINA_SAFETY_ON_NULL_RETURN_VAL(evh->pp_buffer_list, NULL);
519    EINA_SAFETY_ON_NULL_RETURN_VAL(evh->next_buffer, NULL);
520
521    l = evh->next_buffer;
522    while ((vbuf = evh->next_buffer->data))
523      {
524         evh->next_buffer = (evh->next_buffer->next) ? evh->next_buffer->next : evh->pp_buffer_list;
525
526         if (!vbuf->in_use)
527           {
528              vbuf->content_r.w = width;
529              vbuf->content_r.h = height;
530              return vbuf;
531           }
532
533         if (l == evh->next_buffer)
534           {
535              VWR("all video framebuffers in use (max:%d)", evh->ec, BUFFER_MAX_COUNT);
536              return NULL;
537           }
538      }
539
540    return NULL;
541 }
542
543 static Eina_Bool
544 _e_video_hwc_pp_commit(E_Video_Hwc_PP *pp, E_Comp_Wl_Video_Buf *input_buffer, E_Comp_Wl_Video_Buf *pp_buffer, unsigned int transform)
545 {
546    tdm_info_pp info;
547    tdm_error err;
548
549    CLEAR(info);
550    info.src_config.size.h = input_buffer->width_from_pitch;
551    info.src_config.size.v = input_buffer->height_from_size;
552    info.src_config.pos.x = input_buffer->content_r.x;
553    info.src_config.pos.y = input_buffer->content_r.y;
554    info.src_config.pos.w = input_buffer->content_r.w;
555    info.src_config.pos.h = input_buffer->content_r.h;
556    info.src_config.format = input_buffer->tbmfmt;
557    info.dst_config.size.h = pp_buffer->width_from_pitch;
558    info.dst_config.size.v = pp_buffer->height_from_size;
559    info.dst_config.pos.w = pp_buffer->content_r.w;
560    info.dst_config.pos.h = pp_buffer->content_r.h;
561    info.dst_config.format = pp_buffer->tbmfmt;
562    info.transform = transform;
563
564    if (memcmp(&pp->info, &info, sizeof info) != 0)
565      {
566         memcpy(&pp->info, &info, sizeof info);
567         err = tdm_pp_set_info(pp->tdm_handle, &info);
568         if (err != TDM_ERROR_NONE)
569           {
570              VER("tdm_pp_set_info() failed", NULL);
571              return EINA_FALSE;
572           }
573      }
574
575    err = tdm_pp_attach(pp->tdm_handle, input_buffer->tbm_surface, pp_buffer->tbm_surface);
576    if (err != TDM_ERROR_NONE)
577      {
578         VER("tdm_pp_attach() failed", NULL);
579         return EINA_FALSE;
580      }
581
582    err = tdm_pp_commit(pp->tdm_handle);
583    if (err != TDM_ERROR_NONE)
584      {
585         VER("tdm_pp_commit() failed", NULL);
586         return EINA_FALSE;
587      }
588
589    return EINA_TRUE;
590 }
591
592 static Eina_Bool
593 _e_video_hwc_pp_render(E_Video_Hwc *evh, E_Comp_Wl_Buffer *comp_buffer)
594 {
595    E_Comp_Wl_Video_Buf *input_buffer, *pp_buffer;
596    Eina_Bool res;
597
598    if (!evh->pp)
599      {
600         evh->pp = _e_video_hwc_pp_create(e_comp->e_comp_screen->tdisplay, evh);
601         if (!evh->pp)
602           return EINA_FALSE;
603      }
604
605    res = _e_video_hwc_pp_size_limit_check(evh->pp,
606                                           &evh->geo.input_r, &evh->geo.tdm.output_r);
607    if (!res)
608      return res;
609
610    input_buffer = _e_video_hwc_pp_input_buffer_get(evh, comp_buffer);
611    if (!input_buffer)
612      return EINA_FALSE;
613
614    pp_buffer = _e_video_hwc_pp_buffer_get(evh,
615                                           evh->geo.tdm.output_r.w,
616                                           evh->geo.tdm.output_r.h);
617    if (!pp_buffer)
618      goto render_fail;
619
620    e_comp_wl_video_buffer_set_use(pp_buffer, EINA_TRUE);
621    e_comp_wl_buffer_reference(&input_buffer->buffer_ref, input_buffer->comp_buffer);
622
623    res = _e_video_hwc_pp_commit(evh->pp, input_buffer, pp_buffer, evh->geo.tdm.transform);
624    if (!res)
625      goto render_fail;
626
627    return EINA_TRUE;
628
629 render_fail:
630    e_comp_wl_video_buffer_unref(input_buffer);
631    return EINA_FALSE;
632 }
633 /* End of PP implementation */
634
635 static Eina_Bool
636 _e_video_hwc_can_commit(E_Video_Hwc *evh)
637 {
638    if (e_output_dpms_get(evh->e_output))
639      return EINA_FALSE;
640
641    return _e_video_hwc_client_visible_get(evh->ec);
642 }
643
644 static Eina_Bool
645 _e_video_hwc_current_fb_update(E_Video_Hwc *evh)
646 {
647    tbm_surface_h displaying_buffer;
648
649    EINA_SAFETY_ON_NULL_RETURN_VAL(evh, EINA_FALSE);
650
651    if ((evh->committed_vbuf) &&
652        (_e_video_hwc_can_commit(evh)))
653      {
654         displaying_buffer = evh->backend.displaying_buffer_get(evh);
655
656         if (evh->committed_vbuf->tbm_surface != displaying_buffer)
657           return EINA_FALSE;
658      }
659
660    /* client can attachs the same wl_buffer twice. */
661    if ((evh->current_fb) &&
662        (VBUF_IS_VALID(evh->current_fb)) &&
663        (evh->committed_vbuf != evh->current_fb))
664      {
665         e_comp_wl_video_buffer_set_use(evh->current_fb, EINA_FALSE);
666
667         if (evh->current_fb->comp_buffer)
668           e_comp_wl_buffer_reference(&evh->current_fb->buffer_ref, NULL);
669      }
670
671    evh->current_fb = evh->committed_vbuf;
672    evh->committed_vbuf = NULL;
673
674    VDB("current_fb(%d)", evh->ec, MSTAMP(evh->current_fb));
675
676    return EINA_TRUE;
677 }
678
679 static void
680 _e_video_hwc_buffer_enqueue(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf)
681 {
682    /* Remove enqueued video buffer first. */
683    evh->bqueue = eina_list_remove(evh->bqueue, vbuf);
684    evh->bqueue = eina_list_append(evh->bqueue, vbuf);
685    VDB("There are waiting fbs more than 1", evh->ec);
686 }
687
688 static E_Comp_Wl_Video_Buf *
689 _e_video_hwc_buffer_dequeue(E_Video_Hwc *evh)
690 {
691    E_Comp_Wl_Video_Buf *vbuf;
692
693    if (!evh->bqueue)
694      return NULL;
695
696    vbuf = eina_list_nth(evh->bqueue, 0);
697    evh->bqueue = eina_list_remove(evh->bqueue, vbuf);
698
699    return vbuf;
700 }
701
702 static void
703 _e_video_hwc_wait_buffer_commit(E_Video_Hwc *evh)
704 {
705    E_Comp_Wl_Video_Buf *vbuf;
706
707    /* committed_vbuf has to be null */
708    EINA_SAFETY_ON_FALSE_RETURN(evh->committed_vbuf == NULL);
709
710    vbuf = _e_video_hwc_buffer_dequeue(evh);
711    if (!vbuf)
712      return;
713
714    _e_video_hwc_buffer_commit(evh, vbuf);
715 }
716
717 static void
718 _e_video_hwc_buffer_commit(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf)
719 {
720    /* Send a message 'wl_surface.frame', right before commit a buffer to
721     * tdm driver. */
722    e_pixmap_image_clear(evh->ec->pixmap, EINA_TRUE);
723
724    if ((evh->committed_vbuf) && (evh->committed_vbuf != evh->current_fb))
725      {
726         e_comp_wl_video_buffer_set_use(evh->committed_vbuf, EINA_FALSE);
727         e_comp_wl_buffer_reference(&evh->committed_vbuf->buffer_ref, NULL);
728      }
729
730    evh->committed_vbuf = vbuf;
731
732    if (!_e_video_hwc_can_commit(evh))
733      goto no_commit;
734
735    if (!evh->backend.buffer_commit(evh, vbuf))
736      goto no_commit;
737
738    return;
739
740 no_commit:
741    _e_video_hwc_current_fb_update(evh);
742    _e_video_hwc_wait_buffer_commit(evh);
743 }
744
745 static void
746 _e_video_hwc_buffer_show(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf, unsigned int transform)
747 {
748    vbuf->content_t = transform;
749
750    e_comp_wl_video_buffer_set_use(vbuf, EINA_TRUE);
751
752    /* 'comp_buffer' of vbuf can be null in case of pp buffer */
753    if (vbuf->comp_buffer)
754      e_comp_wl_buffer_reference(&vbuf->buffer_ref, vbuf->comp_buffer);
755
756    if ((evh->hwc_policy == E_HWC_POLICY_PLANES) && (evh->committed_vbuf))
757      _e_video_hwc_buffer_enqueue(evh, vbuf);
758    else
759      _e_video_hwc_buffer_commit(evh, vbuf);
760 }
761
762 static void
763 _e_video_hwc_hide(E_Video_Hwc *evh)
764 {
765    E_Comp_Wl_Video_Buf *vbuf;
766
767    if ((evh->current_fb) || (evh->committed_vbuf))
768      {
769         if (evh->current_fb)
770           e_comp_wl_video_buffer_set_use(evh->current_fb, EINA_FALSE);
771
772         if (evh->committed_vbuf)
773           {
774              e_comp_wl_video_buffer_set_use(evh->committed_vbuf, EINA_FALSE);
775              e_comp_wl_buffer_reference(&evh->committed_vbuf->buffer_ref,
776                                         NULL);
777              evh->committed_vbuf = NULL;
778           }
779
780         evh->backend.buffer_commit(evh, NULL);
781      }
782
783    if (evh->old_comp_buffer)
784      evh->old_comp_buffer = NULL;
785
786    EINA_LIST_FREE(evh->bqueue, vbuf)
787       e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
788 }
789
790 static Eina_Rectangle
791 _screen_rect_get(E_Zone *zone, enum wl_output_transform transform)
792 {
793    Eina_Rectangle ret;
794
795    switch (transform & 0x3)
796      {
797       case WL_OUTPUT_TRANSFORM_90:
798       case WL_OUTPUT_TRANSFORM_270:
799          EINA_RECTANGLE_SET(&ret, zone->x, zone->y, zone->h, zone->w);
800          break;
801       default:
802          EINA_RECTANGLE_SET(&ret, zone->x, zone->y, zone->w, zone->h);
803          break;
804      }
805
806    return ret;
807 }
808
809 static void
810 _point_translate(Evas_Point *point, int x_axis, int y_axis)
811 {
812    point->x -= x_axis;
813    point->y -= y_axis;
814 }
815
816 static void
817 _rect_to_points(Eina_Rectangle *rect, Evas_Point points[2])
818 {
819    points[0].x = rect->x;
820    points[0].y = rect->y;
821    points[1].x = rect->x + rect->w;
822    points[1].y = rect->y + rect->h;
823 }
824
825 static void
826 _points_to_rect(Evas_Point points[2], Eina_Rectangle *rect)
827 {
828    rect->x = MIN(points[0].x, points[1].x);
829    rect->y = MIN(points[0].y, points[1].y);
830    rect->w = MAX(points[0].x, points[1].x) - rect->x;
831    rect->h = MAX(points[0].y, points[1].y) - rect->y;
832 }
833
834 /* Translate ox/oy position of output_rect-local coordinates to
835  * new position of buffer_rect-local coordinates. */
836 static void
837 _output_to_buffer_point(Eina_Rectangle *output_rect, Eina_Rectangle *buffer_rect, enum wl_output_transform buffer_transform, int ox, int oy, int *bx, int *by)
838 {
839    float ratio_w, ratio_h;
840
841    switch (buffer_transform)
842      {
843       case WL_OUTPUT_TRANSFORM_NORMAL:
844       default:
845          *bx = ox, *by = oy;
846          break;
847       case WL_OUTPUT_TRANSFORM_90:
848          *bx = oy, *by = output_rect->w - ox;
849          break;
850       case WL_OUTPUT_TRANSFORM_180:
851          *bx = output_rect->w - ox, *by = output_rect->h - oy;
852          break;
853       case WL_OUTPUT_TRANSFORM_270:
854          *bx = output_rect->h - oy, *by = ox;
855          break;
856       case WL_OUTPUT_TRANSFORM_FLIPPED:
857          *bx = output_rect->w - ox, *by = oy;
858          break;
859       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
860          *bx = oy, *by = ox;
861          break;
862       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
863          *bx = ox, *by = output_rect->h - oy;
864          break;
865       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
866          *bx = output_rect->h - oy, *by = output_rect->w - ox;
867          break;
868      }
869
870    if (buffer_transform & 0x1)
871      {
872         ratio_w = (float)buffer_rect->w / output_rect->h;
873         ratio_h = (float)buffer_rect->h / output_rect->w;
874      }
875    else
876      {
877         ratio_w = (float)buffer_rect->w / output_rect->w;
878         ratio_h = (float)buffer_rect->h / output_rect->h;
879      }
880
881    *bx = (*bx) * ratio_w + buffer_rect->x;
882    *by = (*by) * ratio_h + buffer_rect->y;
883 }
884
885 /* Cropping source/destination of viewport.
886  * @in      zone            A E_Zone instance to be used to get screen rectangle.
887  * @inout   input_r         A Source of viewport to be set to tdm_info.src_config
888  *          tdm.output_r    A Destination of viewport to be set to tdm_info.dst_pos
889  * tdm.output_r will be cropped by given region of zone, and then input_r will be
890  * cropped accordingly.
891  */
892 static void
893 _e_video_hwc_viewport_crop_by_screen(E_Video_Hwc_Geometry *in_out, E_Zone *zone, enum wl_output_transform output_transform)
894 {
895    Eina_Rectangle *output_rect, *buffer_rect;
896    Eina_Rectangle cropped_output_rect, screen_rect;
897    Evas_Point points[2];
898
899    buffer_rect = &in_out->input_r;
900    output_rect = &in_out->tdm.output_r;
901    screen_rect = _screen_rect_get(zone, output_transform);
902
903    /* No need to crop in case output region doesn't stick out of screen region. */
904    if (E_CONTAINS(screen_rect.x, screen_rect.y,
905                   screen_rect.w, screen_rect.h,
906                   output_rect->x, output_rect->y,
907                   output_rect->w, output_rect->h))
908      return;
909
910    EINA_RECTANGLE_SET(&cropped_output_rect,
911                       output_rect->x, output_rect->y,
912                       output_rect->w, output_rect->h);
913    if (!eina_rectangle_intersection(&cropped_output_rect, &screen_rect))
914      {
915         VER("Video won't be displayed because there is no intersection between "
916             "screen region and output region.\n"
917             "\toutput(%d,%d %dx%d) screen(%d,%d %dx%d)",
918             NULL, EINA_RECTANGLE_ARGS(output_rect),
919             EINA_RECTANGLE_ARGS(&screen_rect));
920         EINA_RECTANGLE_SET(output_rect, 0, 0, 0, 0);
921         /* NOTE: Does buffer_rect need to be handled as well? */
922         return;
923      }
924
925    VIN("Crop video viewport by screen", NULL);
926    VIN("Screen(%d,%d %dx%d)", NULL, EINA_RECTANGLE_ARGS(&screen_rect));
927    VIN("Viewport: source of buffer(%d,%d %dx%d) destination of screen(%d,%d %dx%d)",
928        NULL, EINA_RECTANGLE_ARGS(buffer_rect), EINA_RECTANGLE_ARGS(output_rect));
929
930    _rect_to_points(&cropped_output_rect, points);
931
932    /* Get points of cropped rectangle mapped on output_rect-local coordinates. */
933    _point_translate(&points[0], output_rect->x, output_rect->y);
934    _point_translate(&points[1], output_rect->x, output_rect->y);
935
936    /* Calculate new points of source buffer for cropped output */
937    _output_to_buffer_point(output_rect, buffer_rect,
938                            in_out->transform,
939                            points[0].x, points[0].y,
940                            &points[0].x, &points[0].y);
941    _output_to_buffer_point(output_rect, buffer_rect,
942                            in_out->transform,
943                            points[1].x, points[1].y,
944                            &points[1].x, &points[1].y);
945
946    _points_to_rect(points, buffer_rect);
947
948    EINA_RECTANGLE_SET(output_rect,
949                       cropped_output_rect.x, cropped_output_rect.y,
950                       cropped_output_rect.w, cropped_output_rect.h);
951
952    VIN("Cropped source of buffer(%d,%d %dx%d)",
953        NULL, EINA_RECTANGLE_ARGS(buffer_rect));
954    VIN("Cropped destination of screen(%d,%d %dx%d)",
955        NULL, EINA_RECTANGLE_ARGS(output_rect));
956 }
957
958 static void
959 _e_video_hwc_geometry_tdm_config_update(E_Client *ec, E_Video_Hwc_Geometry *out)
960 {
961    E_Zone *zone;
962    Eina_Array *outputs;
963    E_Comp_Wl_Output *output;
964    E_Client *topmost;
965    int tran, flip;
966    int transform;
967
968    topmost = e_comp_wl_topmost_parent_get(ec);
969    EINA_SAFETY_ON_NULL_GOTO(topmost, normal);
970
971    outputs = e_comp_wl_output_find_all(topmost);
972    if (!outputs)
973        goto normal;
974
975    /* NOTE: Not support multi output yet. So we use the first output. */
976    output = eina_array_data_get(outputs, 0);
977    eina_array_free(outputs);
978
979    zone = topmost->zone;
980    EINA_SAFETY_ON_NULL_GOTO(zone, normal);
981
982    tran = out->transform & 0x3;
983    flip = out->transform & 0x4;
984    transform = flip + (tran + output->transform) % 4;
985    switch(transform)
986      {
987       case WL_OUTPUT_TRANSFORM_90:
988          out->tdm.transform = TDM_TRANSFORM_270;
989          break;
990       case WL_OUTPUT_TRANSFORM_180:
991          out->tdm.transform = TDM_TRANSFORM_180;
992          break;
993       case WL_OUTPUT_TRANSFORM_270:
994          out->tdm.transform = TDM_TRANSFORM_90;
995          break;
996       case WL_OUTPUT_TRANSFORM_FLIPPED:
997          out->tdm.transform = TDM_TRANSFORM_FLIPPED;
998          break;
999       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1000          out->tdm.transform = TDM_TRANSFORM_FLIPPED_270;
1001          break;
1002       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1003          out->tdm.transform = TDM_TRANSFORM_FLIPPED_180;
1004          break;
1005       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1006          out->tdm.transform = TDM_TRANSFORM_FLIPPED_90;
1007          break;
1008       case WL_OUTPUT_TRANSFORM_NORMAL:
1009       default:
1010          out->tdm.transform = TDM_TRANSFORM_NORMAL;
1011          break;
1012      }
1013
1014    if (output->transform % 2)
1015      {
1016         if (out->tdm.transform == TDM_TRANSFORM_FLIPPED)
1017           out->tdm.transform = TDM_TRANSFORM_FLIPPED_180;
1018         else if (out->tdm.transform == TDM_TRANSFORM_FLIPPED_90)
1019           out->tdm.transform = TDM_TRANSFORM_FLIPPED_270;
1020         else if (out->tdm.transform == TDM_TRANSFORM_FLIPPED_180)
1021           out->tdm.transform = TDM_TRANSFORM_FLIPPED;
1022         else if (out->tdm.transform == TDM_TRANSFORM_FLIPPED_270)
1023           out->tdm.transform = TDM_TRANSFORM_FLIPPED_90;
1024      }
1025
1026    if (output->transform == 0)
1027      out->tdm.output_r = out->output_r;
1028    else
1029      e_comp_wl_rect_convert(zone->w, zone->h, output->transform, 1,
1030                             out->output_r.x, out->output_r.y,
1031                             out->output_r.w, out->output_r.h,
1032                             &out->tdm.output_r.x, &out->tdm.output_r.y,
1033                             &out->tdm.output_r.w, &out->tdm.output_r.h);
1034
1035    VDB("geomtry: screen(%d,%d %dx%d | %d) => %d => physical(%d,%d %dx%d | %d)",
1036        ec, EINA_RECTANGLE_ARGS(&out->output_r), out->transform, transform,
1037        EINA_RECTANGLE_ARGS(&out->tdm.output_r), out->tdm.transform);
1038
1039    _e_video_hwc_viewport_crop_by_screen(out, zone, output->transform);
1040
1041    return;
1042 normal:
1043    out->tdm.output_r = out->output_r;
1044    out->tdm.transform = out->transform;
1045 }
1046
1047 /**
1048  * Convert given four coordinates to elements of rectangle
1049  * @in   p[4]        Coordinates to be converted
1050  * @out  rect        x, y, width, and height
1051  *       transform   Angle which represents TDM_TRANSFORM of rectangle
1052  * @return EINA_FALSE in following case, otherwise EINA_TRUE.
1053  *   1. The given coordinates are not represented by rectangle.
1054  *   2. All angles except for 0, 90, 180, 270.
1055  */
1056 #ifdef IS_CLOSE
1057 #undef IS_CLOSE
1058 #endif
1059 #define IS_CLOSE(x, y, m)  (abs((x - y)) < m)
1060
1061 #ifdef IS_PORTRAIT_RECT
1062 #undef IS_PORTRAIT_RECT
1063 #endif
1064 #define IS_PORTRAIT_RECT(p, m) \
1065    (IS_CLOSE(p[0].y, p[1].y, m) && IS_CLOSE(p[1].x, p[2].x, m) && \
1066     IS_CLOSE(p[2].y, p[3].y, m) && IS_CLOSE(p[3].x, p[0].x, m))
1067
1068 #ifdef IS_LANDSCAPE_RECT
1069 #undef IS_LANDSCAPE_RECT
1070 #endif
1071 #define IS_LANDSCAPE_RECT(p, m) \
1072    (IS_CLOSE(p[0].x, p[1].x, m) && IS_CLOSE(p[1].y, p[2].y, m) && \
1073     IS_CLOSE(p[2].x, p[3].x, m) && IS_CLOSE(p[3].y, p[0].y, m))
1074
1075 #ifdef VERTICES_TO_RECT
1076 #undef VERTICES_TO_RECT
1077 #endif
1078 #define VERTICES_TO_RECT(r, vs)              \
1079     (r)->x = MIN(vs[0].x, vs[2].x);          \
1080     (r)->y = MIN(vs[0].y, vs[2].y);          \
1081     (r)->w = MAX(vs[0].x, vs[2].x) - (r)->x; \
1082     (r)->h = MAX(vs[0].y, vs[2].y) - (r)->y
1083
1084 static Eina_Bool
1085 _e_video_hwc_coords_to_rectangle_convert(Evas_Point p[4], Eina_Rectangle *rect, uint *transform)
1086 {
1087    Eina_Rectangle boundary = {0,};
1088    Eina_Bool ret = EINA_FALSE;
1089    int margin = 2;
1090
1091    VERTICES_TO_RECT(&boundary, p);
1092    if ((boundary.w < 2) || (boundary.h < 2))
1093      margin = 1;
1094
1095    if (IS_PORTRAIT_RECT(p, margin))
1096      {
1097         /* 0 or 180 */
1098         if ((p[0].x < p[2].x) && (p[0].y < p[2].y))
1099           {
1100              *transform = TDM_TRANSFORM_NORMAL;
1101              VERTICES_TO_RECT(rect, p);
1102              ret = EINA_TRUE;
1103           }
1104         else if ((p[0].x > p[2].x) && (p[0].y > p[2].y))
1105           {
1106              *transform = TDM_TRANSFORM_180;
1107              VERTICES_TO_RECT(rect, p);
1108              ret = EINA_TRUE;
1109           }
1110      }
1111    else if (IS_LANDSCAPE_RECT(p, margin))
1112      {
1113         /* 90 or 270 */
1114         if ((p[0].x > p[2].x) && (p[0].y < p[2].y))
1115           {
1116              *transform = TDM_TRANSFORM_90;
1117              VERTICES_TO_RECT(rect, p);
1118              ret = EINA_TRUE;
1119           }
1120         else if ((p[0].x < p[2].x) && (p[0].y > p[2].y))
1121           {
1122              *transform = TDM_TRANSFORM_270;
1123              VERTICES_TO_RECT(rect, p);
1124              ret = EINA_TRUE;
1125           }
1126      }
1127
1128    return ret;
1129 }
1130
1131 #undef IS_CLOSE
1132 #undef IS_PORTRAIT_RECT
1133 #undef IS_LANDSCAPE_RECT
1134 #undef VERTICES_TO_RECT
1135
1136 /**
1137  * Merge transform value of E_Comp_Wl_Buffer_Viewport with given transform.
1138  * @in   vp          A 'E_Comp_Wl_Buffer_Viewport' instance to be merged
1139  *       transform   A transform operand to be merged
1140  * @return merged result transform
1141  */
1142 static uint
1143 _e_video_hwc_transform_merge_with_buffer_viewport(E_Comp_Wl_Buffer_Viewport *vp, uint transform)
1144 {
1145    int vp_transform, flip;
1146
1147    vp_transform = vp->buffer.transform & 0x3;
1148    flip = vp->buffer.transform & 0x4;
1149
1150    return (flip + (transform + vp_transform) % 4);
1151 }
1152
1153 static Eina_Bool
1154 _e_video_hwc_geometry_map_apply(E_Client *ec, E_Video_Hwc_Geometry *out)
1155 {
1156    E_Map *m;
1157    Evas_Point p[4];
1158    Eina_Rectangle output_r;
1159    uint transform;
1160    int i;
1161
1162    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
1163    EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
1164    EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE);
1165
1166    m = e_client_map_get(ec);
1167    if (!m) return EINA_TRUE;
1168
1169    /* If frame has map, it means that ec's geometry is decided by map's geometry.
1170     * ec->x,y,w,h and ec->client.x,y,w,h is not useful.
1171     */
1172
1173    for (i = 0; i < 4; i++)
1174      e_map_point_coord_get(m, i, &p[i].x, &p[i].y, NULL);
1175
1176    if (!_e_video_hwc_coords_to_rectangle_convert(p, &output_r, &transform))
1177      {
1178         VIN("Cannot convert given coords to rectangle.\n"
1179             "p1(%d %d) p2(%d %d) p3(%d %d) p4(%d %d)",
1180             ec, p[0].x, p[0].y, p[1].x, p[1].y,
1181             p[2].x, p[2].y, p[3].x, p[3].y);
1182         e_map_free(m);
1183         return EINA_FALSE;
1184      }
1185
1186    /* NOTE Merge transform value from evas_map with E_Comp_Wl_Buffer_Viewport's one.
1187     * Since buffer.transform isn't applied using evas_map,
1188     * it has to be taken into account here to apply buffer.transform
1189     * and rotation of e_client_transform together. */
1190    transform =
1191       _e_video_hwc_transform_merge_with_buffer_viewport(&ec->comp_data->scaler.buffer_viewport,
1192                                                         transform);
1193
1194    if ((!memcmp(&out->output_r, &output_r, sizeof(Eina_Rectangle))) &&
1195        (out->transform == transform))
1196      {
1197         e_map_free(m);
1198         return EINA_FALSE;
1199      }
1200
1201    VDB("frame(%p) m(%p) output(%d,%d %dx%d) trans(%d) => (%d,%d %dx%d) trans(%d)",
1202        ec, ec->frame, m, EINA_RECTANGLE_ARGS(&out->output_r), out->transform,
1203        EINA_RECTANGLE_ARGS(&output_r), transform);
1204
1205    out->output_r = output_r;
1206    out->transform = transform;
1207
1208    e_map_free(m);
1209    return EINA_TRUE;
1210 }
1211
1212 static void
1213 _e_video_hwc_cb_post_client_idler_before(void *data)
1214 {
1215    E_Video_Hwc *evh;
1216    E_Client *topmost;
1217    Eina_Bool render = EINA_FALSE;
1218    Eina_Bool render_fail = EINA_FALSE;
1219
1220    evh = data;
1221
1222    if (evh->render.map)
1223      {
1224         evh->render.map = EINA_FALSE;
1225         render = _e_video_hwc_geometry_map_apply(evh->ec, &evh->geo);
1226      }
1227
1228    if (evh->render.topmost_viewport)
1229      {
1230         evh->render.topmost_viewport = EINA_FALSE;
1231         topmost = e_comp_wl_topmost_parent_get(evh->ec);
1232         if (topmost)
1233           e_comp_wl_viewport_apply(topmost);
1234         render = EINA_TRUE;
1235      }
1236
1237    if ((render) || (evh->render.redraw))
1238      {
1239         evh->render.redraw = EINA_FALSE;
1240         render_fail = !_e_video_hwc_render(evh, __FUNCTION__);
1241      }
1242
1243    if ((render_fail || e_video_debug_display_primary_plane_value_get()) && (evh->render_fail.cb))
1244      {
1245         evh->render_fail.walking = EINA_TRUE;
1246         evh->render_fail.cb(evh->ecv);
1247         evh->render_fail.walking = EINA_FALSE;
1248
1249         if (evh->deleted)
1250           {
1251              VIN("Delete HWC interface", evh->ec);
1252              evh->backend.destroy(evh);
1253           }
1254      }
1255
1256    E_FREE_FUNC(evh->render.post_client_idler_before_hook, e_main_hook_del);
1257 }
1258
1259 static void
1260 _e_video_hwc_render_queue(E_Video_Hwc *evh)
1261 {
1262    if (evh->render.post_client_idler_before_hook)
1263      return;
1264
1265    evh->render.post_client_idler_before_hook =
1266       e_main_hook_add(E_MAIN_HOOK_POST_CLIENT_IDLER_BEFORE,
1267                       _e_video_hwc_cb_post_client_idler_before,
1268                       evh);
1269 }
1270
1271 static void
1272 _e_video_hwc_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1273 {
1274    E_Video_Hwc *evh = data;
1275
1276    /* Since video content will be displayed on the overlay plane,
1277     * it's reasonable to keep the size of composite object to 1x1.
1278     * Otherwise, it will cause memory usage to be increased unnecessarily. */
1279    evas_object_resize(evh->ec->frame, 1, 1);
1280
1281    evh->render.map = EINA_TRUE;
1282    _e_video_hwc_render_queue(evh);
1283 }
1284
1285 static void
1286 _e_video_hwc_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1287 {
1288    E_Video_Hwc *evh = data;
1289
1290    evh->render.map = EINA_TRUE;
1291    _e_video_hwc_render_queue(evh);
1292 }
1293
1294 static void
1295 _e_video_hwc_input_buffer_valid(E_Video_Hwc *evh, E_Comp_Wl_Buffer *comp_buffer)
1296 {
1297    E_Comp_Wl_Video_Buf *vbuf;
1298    Eina_List *l;
1299
1300    EINA_LIST_FOREACH(evh->input_buffer_list, l, vbuf)
1301      {
1302         tbm_surface_h tbm_surf;
1303         tbm_bo bo;
1304         uint32_t size = 0, offset = 0, pitch = 0;
1305
1306         if (!vbuf->comp_buffer) continue;
1307         if (vbuf->resource == comp_buffer->resource)
1308           {
1309              WRN("got wl_buffer@%d twice", wl_resource_get_id(comp_buffer->resource));
1310              return;
1311           }
1312
1313         tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
1314         bo = tbm_surface_internal_get_bo(tbm_surf, 0);
1315         tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
1316
1317         if (vbuf->names[0] == tbm_bo_export(bo) && vbuf->offsets[0] == offset)
1318           {
1319              WRN("can tearing: wl_buffer@%d, wl_buffer@%d are same. gem_name(%d)",
1320                  wl_resource_get_id(vbuf->resource),
1321                  wl_resource_get_id(comp_buffer->resource), vbuf->names[0]);
1322              return;
1323           }
1324      }
1325 }
1326
1327 static tbm_format
1328 _e_video_hwc_comp_buffer_tbm_format_get(E_Comp_Wl_Buffer *comp_buffer)
1329 {
1330    tbm_surface_h tbm_surf;
1331
1332    tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
1333    EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surf, 0);
1334
1335    return tbm_surface_get_format(tbm_surf);
1336 }
1337
1338 static tbm_surface_h
1339 _e_video_hwc_client_tbm_surface_get(E_Client *ec)
1340 {
1341    E_Comp_Wl_Buffer *comp_buffer;
1342    tbm_surface_h tbmsurf;
1343
1344    comp_buffer = e_pixmap_resource_get(ec->pixmap);
1345    if (!comp_buffer)
1346      {
1347         /* No comp buffer */
1348         return NULL;
1349      }
1350
1351    tbmsurf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server,
1352                                             comp_buffer->resource);
1353
1354    return tbmsurf;
1355 }
1356
1357 static void
1358 buffer_transform(int width, int height, uint32_t transform, int32_t scale,
1359                  int sx, int sy, int *dx, int *dy)
1360 {
1361    switch (transform)
1362      {
1363       case WL_OUTPUT_TRANSFORM_NORMAL:
1364       default:
1365          *dx = sx, *dy = sy;
1366          break;
1367       case WL_OUTPUT_TRANSFORM_FLIPPED:
1368          *dx = width - sx, *dy = sy;
1369          break;
1370       case WL_OUTPUT_TRANSFORM_90:
1371          *dx = height - sy, *dy = sx;
1372          break;
1373       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1374          *dx = height - sy, *dy = width - sx;
1375          break;
1376       case WL_OUTPUT_TRANSFORM_180:
1377          *dx = width - sx, *dy = height - sy;
1378          break;
1379       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
1380          *dx = sx, *dy = height - sy;
1381          break;
1382       case WL_OUTPUT_TRANSFORM_270:
1383          *dx = sy, *dy = width - sx;
1384          break;
1385       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1386          *dx = sy, *dy = sx;
1387          break;
1388      }
1389
1390    *dx *= scale;
1391    *dy *= scale;
1392 }
1393
1394 static void
1395 _e_video_hwc_geometry_input_rect_get_with_viewport(tbm_surface_h tbm_surf, E_Comp_Wl_Buffer_Viewport *vp, Eina_Rectangle *out)
1396 {
1397    int bw, bh;
1398    int x1, y1, x2, y2;
1399    int tx1, ty1, tx2, ty2;
1400    int width_from_buffer, height_from_buffer;
1401
1402    bw = tbm_surface_get_width(tbm_surf);
1403    bh = tbm_surface_get_height(tbm_surf);
1404    VDB("TBM buffer size %d %d", NULL, bw, bh);
1405
1406    switch (vp->buffer.transform)
1407      {
1408       case WL_OUTPUT_TRANSFORM_90:
1409       case WL_OUTPUT_TRANSFORM_270:
1410       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
1411       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
1412          width_from_buffer = bh / vp->buffer.scale;
1413          height_from_buffer = bw / vp->buffer.scale;
1414          break;
1415       default:
1416          width_from_buffer = bw / vp->buffer.scale;
1417          height_from_buffer = bh / vp->buffer.scale;
1418          break;
1419      }
1420
1421    if (vp->buffer.src_width == wl_fixed_from_int(-1))
1422      {
1423         x1 = 0.0;
1424         y1 = 0.0;
1425         x2 = width_from_buffer;
1426         y2 = height_from_buffer;
1427      }
1428    else
1429      {
1430         x1 = wl_fixed_to_int(vp->buffer.src_x);
1431         y1 = wl_fixed_to_int(vp->buffer.src_y);
1432         x2 = wl_fixed_to_int(vp->buffer.src_x + vp->buffer.src_width);
1433         y2 = wl_fixed_to_int(vp->buffer.src_y + vp->buffer.src_height);
1434      }
1435
1436    VDB("transform(%d) scale(%d) buffer(%dx%d) src(%d,%d %d,%d)",
1437        NULL, vp->buffer.transform, vp->buffer.scale,
1438        width_from_buffer, height_from_buffer,
1439        x1, y1, x2 - x1, y2 - y1);
1440
1441    buffer_transform(width_from_buffer, height_from_buffer,
1442                     vp->buffer.transform, vp->buffer.scale, x1, y1, &tx1, &ty1);
1443    buffer_transform(width_from_buffer, height_from_buffer,
1444                     vp->buffer.transform, vp->buffer.scale, x2, y2, &tx2, &ty2);
1445
1446    out->x = (tx1 <= tx2) ? tx1 : tx2;
1447    out->y = (ty1 <= ty2) ? ty1 : ty2;
1448    out->w = (tx1 <= tx2) ? tx2 - tx1 : tx1 - tx2;
1449    out->h = (ty1 <= ty2) ? ty2 - ty1 : ty1 - ty2;
1450 }
1451
1452 static void
1453 _e_video_hwc_geometry_output_rect_get(E_Client *ec, Eina_Rectangle *out)
1454 {
1455    if (e_comp_wl_subsurface_check(ec))
1456      e_comp_wl_subsurface_global_coord_get(ec, &out->x, &out->y);
1457    else
1458      {
1459         out->x = ec->x;
1460         out->y = ec->y;
1461      }
1462
1463    out->w = ec->comp_data->width_from_viewport;
1464    out->w = (out->w + 1) & ~1;
1465    out->h = ec->comp_data->height_from_viewport;
1466
1467    e_comp_object_frame_xy_unadjust(ec->frame, out->x, out->y, &out->x, &out->y);
1468    e_comp_object_frame_wh_unadjust(ec->frame, out->w, out->h, &out->w, &out->h);
1469 }
1470
1471 /* convert from logical screen to physical output */
1472 static Eina_Bool
1473 _e_video_hwc_geometry_viewport_apply(E_Client *ec, E_Video_Hwc_Geometry *out)
1474 {
1475    E_Comp_Wl_Buffer_Viewport *vp;
1476    tbm_surface_h tbm_surf;
1477
1478    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
1479    EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE);
1480
1481    tbm_surf = _e_video_hwc_client_tbm_surface_get(ec);
1482    if (!tbm_surf)
1483      {
1484         /* No tbm_surface */
1485         return EINA_FALSE;
1486      }
1487
1488    vp = &ec->comp_data->scaler.buffer_viewport;
1489    _e_video_hwc_geometry_input_rect_get_with_viewport(tbm_surf, vp, &out->input_r);
1490
1491    _e_video_hwc_geometry_output_rect_get(ec, &out->output_r);
1492    out->transform = vp->buffer.transform;
1493
1494    VDB("geometry(%d,%d %dx%d  %d,%d %dx%d  %d)", ec,
1495        EINA_RECTANGLE_ARGS(&out->input_r),EINA_RECTANGLE_ARGS(&out->output_r),
1496        out->transform);
1497
1498    return EINA_TRUE;
1499 }
1500
1501 static Eina_Bool
1502 _e_video_hwc_geometry_get(E_Client *ec, E_Video_Hwc_Geometry *out)
1503 {
1504    Eina_Rectangle input_r = {0,};
1505
1506    /* get geometry information with buffer scale, transform and viewport. */
1507    if (!_e_video_hwc_geometry_viewport_apply(ec, out))
1508      return EINA_FALSE;
1509
1510    _e_video_hwc_geometry_map_apply(ec, out);
1511
1512    _e_video_hwc_geometry_tdm_config_update(ec, out);
1513
1514    e_comp_wl_video_buffer_size_get(ec, &input_r.w, &input_r.h);
1515    // when topmost is not mapped, input size can be abnormal.
1516    // in this case, it will be render by topmost showing.
1517    if (!eina_rectangle_intersection(&out->input_r, &input_r) || (out->input_r.w <= 10 || out->input_r.h <= 10))
1518      {
1519         VER("input area is empty", ec);
1520         return EINA_FALSE;
1521      }
1522
1523    return EINA_TRUE;
1524 }
1525
1526 static Eina_Bool
1527 _e_video_hwc_client_parent_viewable_get(E_Client *ec)
1528 {
1529    E_Client *topmost_parent;
1530
1531    topmost_parent = e_comp_wl_topmost_parent_get(ec);
1532
1533    if (!topmost_parent)
1534      return EINA_FALSE;
1535
1536    if (topmost_parent == ec)
1537      {
1538         VDB("There is no video parent surface", ec);
1539         return EINA_FALSE;
1540      }
1541
1542    if (!topmost_parent->visible)
1543      {
1544         VDB("parent(0x%08"PRIxPTR") not viewable", ec,
1545             (Ecore_Window)e_client_util_win_get(topmost_parent));
1546         return EINA_FALSE;
1547      }
1548
1549    if (!e_pixmap_resource_get(topmost_parent->pixmap))
1550      {
1551         VDB("parent(0x%08"PRIxPTR") no comp buffer", ec,
1552             (Ecore_Window)e_client_util_win_get(topmost_parent));
1553         return EINA_FALSE;
1554      }
1555
1556    return EINA_TRUE;
1557 }
1558
1559 static Eina_Bool
1560 _e_video_hwc_render(E_Video_Hwc *evh, const char *func)
1561 {
1562    E_Comp_Wl_Buffer *comp_buffer;
1563    E_Comp_Wl_Video_Buf *input_buffer = NULL;
1564    E_Client *topmost;
1565
1566    EINA_SAFETY_ON_NULL_GOTO(evh->ec, done);
1567
1568    /* buffer can be NULL when camera/video's mode changed. Do nothing and
1569     * keep previous frame in this case.
1570     */
1571    if (!evh->ec->pixmap)
1572      goto done;
1573
1574    if (!_e_video_hwc_client_visible_get(evh->ec))
1575      {
1576         evh->need_force_render = EINA_TRUE;
1577         _e_video_hwc_hide(evh);
1578         goto done;
1579      }
1580
1581    comp_buffer = e_pixmap_resource_get(evh->ec->pixmap);
1582    if (!comp_buffer) goto done;
1583
1584    evh->tbmfmt = _e_video_hwc_comp_buffer_tbm_format_get(comp_buffer);
1585
1586    topmost = e_comp_wl_topmost_parent_get(evh->ec);
1587    EINA_SAFETY_ON_NULL_GOTO(topmost, done);
1588
1589    if(e_comp_wl_viewport_is_changed(topmost))
1590      {
1591         VIN("need update viewport: apply topmost", evh->ec);
1592         e_comp_wl_viewport_apply(topmost);
1593      }
1594
1595    if (!_e_video_hwc_geometry_get(evh->ec, &evh->geo))
1596      {
1597         if(!evh->need_force_render && !_e_video_hwc_client_parent_viewable_get(evh->ec))
1598           {
1599              VIN("need force render", evh->ec);
1600              evh->need_force_render = EINA_TRUE;
1601           }
1602         goto done;
1603      }
1604
1605    DBG("====================================== (%s)", func);
1606    VDB("old: "GEO_FMT" buf(%p)", evh->ec, GEO_ARG(&evh->old_geo), evh->old_comp_buffer);
1607    VDB("new: "GEO_FMT" buf(%p) %c%c%c%c", evh->ec, GEO_ARG(&evh->geo), comp_buffer, FOURCC_STR(evh->tbmfmt));
1608
1609    if (!memcmp(&evh->old_geo, &evh->geo, sizeof evh->geo) &&
1610        evh->old_comp_buffer == comp_buffer)
1611      {
1612         /* Try sending 'wl_surface.frame' in case client
1613          * submitted same 'wl_buffer' */
1614         e_pixmap_image_clear(evh->ec->pixmap, EINA_TRUE);
1615         goto done;
1616      }
1617
1618    evh->need_force_render = EINA_FALSE;
1619
1620    _e_video_hwc_input_buffer_valid(evh, comp_buffer);
1621
1622    if ((evh->geo.tdm.output_r.w == 0) ||
1623        (evh->geo.tdm.output_r.h == 0))
1624      {
1625         VIN("Hide video by setting 0 dst size", evh->ec);
1626         e_pixmap_image_clear(evh->ec->pixmap, EINA_TRUE);
1627         _e_video_hwc_hide(evh);
1628         evh->old_geo = evh->geo;
1629         goto done;
1630      }
1631    if (!evh->backend.check_if_pp_needed(evh))
1632      {
1633         /* 1. non converting case */
1634         input_buffer = _e_video_hwc_input_buffer_get(evh, comp_buffer);
1635         if (!input_buffer)
1636           goto done;
1637
1638         _e_video_hwc_buffer_show(evh, input_buffer, evh->geo.tdm.transform);
1639      }
1640    else
1641      {
1642         if (!_e_video_hwc_pp_render(evh, comp_buffer))
1643           {
1644              VER("Failed to PP render", evh->ec);
1645              e_pixmap_image_clear(evh->ec->pixmap, EINA_TRUE);
1646              goto render_fail;
1647           }
1648      }
1649
1650    evh->old_geo = evh->geo;
1651    evh->old_comp_buffer = comp_buffer;
1652
1653    DBG("======================================.");
1654
1655 done:
1656    return EINA_TRUE;
1657 render_fail:
1658    return EINA_FALSE;
1659 }
1660
1661 static E_Client *
1662 _e_video_hwc_child_client_get(E_Client *ec)
1663 {
1664    E_Client *subc = NULL;
1665    Eina_List *l;
1666    if (!ec) return NULL;
1667    if (e_object_is_del(E_OBJECT(ec))) return NULL;
1668    if (!ec->comp_data) return NULL;
1669
1670    if (e_client_video_hw_composition_check(ec)) return ec;
1671
1672    EINA_LIST_FOREACH(ec->comp_data->sub.below_list, l, subc)
1673      {
1674         E_Client *temp= NULL;
1675         if (!subc->comp_data || e_object_is_del(E_OBJECT(subc))) continue;
1676         temp = _e_video_hwc_child_client_get(subc);
1677         if(temp) return temp;
1678      }
1679
1680    return NULL;
1681 }
1682
1683 static Eina_Bool
1684 _e_video_hwc_cb_client_show(void *data, int type, void *event)
1685 {
1686    E_Event_Client *ev = event;
1687    E_Client *ec;
1688    E_Client *video_ec = NULL;
1689    E_Video_Hwc *evh = NULL;
1690
1691    EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
1692    EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
1693
1694    ec = ev->ec;
1695    if (!ec->comp_data) return ECORE_CALLBACK_PASS_ON;
1696
1697    video_ec = _e_video_hwc_child_client_get(ec);
1698    if (!video_ec) return ECORE_CALLBACK_PASS_ON;
1699
1700    evh = data;
1701    if (!evh) return ECORE_CALLBACK_PASS_ON;
1702
1703    if (evh->old_comp_buffer)
1704      {
1705         VIN("video already rendering..", evh->ec);
1706         return ECORE_CALLBACK_PASS_ON;
1707      }
1708
1709    if (ec == e_comp_wl_topmost_parent_get(evh->ec))
1710      {
1711         VIN("video need rendering..", evh->ec);
1712         evh->render.topmost_viewport = EINA_TRUE;
1713         _e_video_hwc_render_queue(evh);
1714      }
1715
1716    return ECORE_CALLBACK_PASS_ON;
1717 }
1718
1719 static Eina_Bool
1720 _e_video_hwc_cb_client_buffer_change(void *data, int type, void *event)
1721 {
1722    E_Client *ec;
1723    E_Event_Client *ev = event;
1724    E_Video_Hwc *evh;
1725
1726    EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
1727    EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
1728
1729    evh = data;
1730    ec = ev->ec;
1731
1732    if (evh->ec != ec)
1733      return ECORE_CALLBACK_PASS_ON;
1734
1735    evh->render.redraw = EINA_TRUE;
1736    _e_video_hwc_render_queue(evh);
1737
1738    return ECORE_CALLBACK_PASS_ON;
1739 }
1740
1741 static void
1742 _e_video_hwc_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1743 {
1744    E_Video_Hwc *evh;
1745    E_Client *ec;
1746
1747    evh = data;
1748    ec = evh->ec;
1749
1750    if (evh->need_force_render)
1751      {
1752         VIN("video forcely rendering..", evh->ec);
1753         evh->render.redraw = EINA_TRUE;
1754         _e_video_hwc_render_queue(evh);
1755      }
1756
1757    /* if stand_alone is true, not show */
1758    if ((e_comp_wl_subsurface_check(ec)) &&
1759        (e_comp_wl_subsurface_stand_alone_mode_get(ec)))
1760      return;
1761
1762    if (evh->current_fb)
1763      _e_video_hwc_buffer_show(evh, evh->current_fb, evh->current_fb->content_t);
1764 }
1765
1766 static void
1767 _e_video_hwc_cb_surface_viewport(struct wl_listener *listener, void *data)
1768 {
1769    E_Video_Hwc *evh;
1770
1771    evh = container_of(listener, E_Video_Hwc, surface_viewport_listener);
1772
1773    VDB("Apply Viewport Signal", evh->ec);
1774    evh->render.redraw = EINA_TRUE;
1775    _e_video_hwc_render_queue(evh);
1776 }
1777
1778 static void
1779 _e_video_hwc_client_event_init(E_Video_Hwc *evh)
1780 {
1781    /* In order to try to redraw video whenever viewport changes. */
1782    evh->surface_viewport_listener.notify = _e_video_hwc_cb_surface_viewport;
1783    if (evh->ec->comp_data)
1784      {
1785         wl_signal_add(&evh->ec->comp_data->apply_viewport_signal,
1786                       &evh->surface_viewport_listener);
1787      }
1788
1789    evas_object_event_callback_add(evh->ec->frame, EVAS_CALLBACK_SHOW,
1790                                   _e_video_hwc_cb_evas_show, evh);
1791    evas_object_event_callback_add(evh->ec->frame, EVAS_CALLBACK_RESIZE,
1792                                   _e_video_hwc_cb_evas_resize, evh);
1793    evas_object_event_callback_add(evh->ec->frame, EVAS_CALLBACK_MOVE,
1794                                   _e_video_hwc_cb_evas_move, evh);
1795
1796    E_LIST_HANDLER_APPEND(evh->ec_event_handler, E_EVENT_CLIENT_SHOW,
1797                          _e_video_hwc_cb_client_show, evh);
1798    E_LIST_HANDLER_APPEND(evh->ec_event_handler, E_EVENT_CLIENT_BUFFER_CHANGE,
1799                          _e_video_hwc_cb_client_buffer_change, evh);
1800 }
1801
1802 static void
1803 _e_video_hwc_client_event_deinit(E_Video_Hwc *evh)
1804 {
1805    /* links for listener have to be removed only in case comp_data is valid. */
1806    if (evh->ec->comp_data)
1807      wl_list_remove(&evh->surface_viewport_listener.link);
1808
1809    evas_object_event_callback_del_full(evh->ec->frame, EVAS_CALLBACK_SHOW,
1810                                        _e_video_hwc_cb_evas_show, evh);
1811    evas_object_event_callback_del_full(evh->ec->frame, EVAS_CALLBACK_RESIZE,
1812                                        _e_video_hwc_cb_evas_resize, evh);
1813    evas_object_event_callback_del_full(evh->ec->frame, EVAS_CALLBACK_MOVE,
1814                                        _e_video_hwc_cb_evas_move, evh);
1815
1816    E_FREE_LIST(evh->ec_event_handler, ecore_event_handler_del);
1817 }
1818
1819 static void
1820 _e_video_hwc_iface_destroy(E_Video_Comp_Iface *iface)
1821 {
1822    E_Comp_Wl_Video_Buf *vbuf;
1823    Eina_List *l = NULL, *ll = NULL;
1824
1825    IFACE_ENTRY;
1826
1827    _e_video_hwc_hide(evh);
1828
1829    EINA_LIST_FOREACH_SAFE(evh->input_buffer_list, l, ll, vbuf)
1830      {
1831         e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
1832         e_comp_wl_video_buffer_unref(vbuf);
1833      }
1834
1835    EINA_LIST_FOREACH_SAFE(evh->pp_buffer_list, l, ll, vbuf)
1836      {
1837         e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
1838         e_comp_wl_video_buffer_unref(vbuf);
1839      }
1840
1841    if (evh->input_buffer_list)
1842      NEVER_GET_HERE();
1843    if (evh->pp_buffer_list)
1844      NEVER_GET_HERE();
1845
1846    /* destroy converter second */
1847    E_FREE_FUNC(evh->pp, _e_video_hwc_pp_destroy);
1848
1849    if (e_comp_object_mask_has(evh->ec->frame))
1850      e_comp_object_mask_set(evh->ec->frame, EINA_FALSE);
1851
1852    _e_video_hwc_client_event_deinit(evh);
1853
1854    E_FREE_FUNC(evh->render.post_client_idler_before_hook, e_main_hook_del);
1855
1856    if (evh->render_fail.walking)
1857      {
1858         evh->deleted = EINA_TRUE;
1859         return;
1860      }
1861
1862    evh->backend.destroy(evh);
1863 }
1864
1865 static Eina_Bool
1866 _e_video_hwc_iface_property_get(E_Video_Comp_Iface *iface, unsigned int id, tdm_value *value)
1867 {
1868    IFACE_ENTRY;
1869
1870    return evh->backend.property_get(evh, id, value);
1871 }
1872
1873 static Eina_Bool
1874 _e_video_hwc_iface_property_set(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value, Eina_Bool sync)
1875 {
1876    IFACE_ENTRY;
1877
1878    return evh->backend.property_set(evh, id, value, sync);
1879 }
1880
1881 static Eina_Bool
1882 _e_video_hwc_iface_property_delay_set(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value)
1883 {
1884    IFACE_ENTRY;
1885
1886    if (evh->hwc_policy != E_HWC_POLICY_PLANES)
1887      return EINA_FALSE;
1888    return e_video_hwc_planes_property_delay_set(evh, id, value);
1889 }
1890
1891 static Eina_Bool
1892 _e_video_hwc_iface_available_properties_get(E_Video_Comp_Iface *iface, const tdm_prop **props, int *count)
1893 {
1894    IFACE_ENTRY;
1895
1896    return evh->backend.available_properties_get(evh, props, count);
1897 }
1898
1899 static Eina_Bool
1900 _e_video_hwc_iface_info_get(E_Video_Comp_Iface *iface, E_Client_Video_Info *info)
1901 {
1902    IFACE_ENTRY;
1903
1904    if (evh->hwc_policy != E_HWC_POLICY_WINDOWS)
1905      return EINA_FALSE;
1906    return e_video_hwc_windows_info_get(evh, info);
1907 }
1908
1909 static Eina_Bool
1910 _e_video_hwc_iface_commit_data_release(E_Video_Comp_Iface *iface, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
1911 {
1912    IFACE_ENTRY;
1913
1914    if (evh->hwc_policy != E_HWC_POLICY_WINDOWS)
1915      return EINA_FALSE;
1916    return e_video_hwc_windows_commit_data_release(evh, sequence, tv_sec, tv_usec);
1917 }
1918
1919 static tbm_surface_h
1920 _e_video_hwc_iface_tbm_surface_get(E_Video_Comp_Iface *iface)
1921 {
1922    IFACE_ENTRY;
1923
1924    if (evh->hwc_policy != E_HWC_POLICY_WINDOWS)
1925      return NULL;
1926    return e_video_hwc_windows_tbm_surface_get(evh);
1927 }
1928
1929 static E_Video_Hwc *
1930 _e_video_hwc_create(E_Client *ec)
1931 {
1932    E_Video_Hwc *evh;
1933    E_Hwc_Policy hwc_policy;
1934    E_Output *output;
1935    E_Zone *zone;
1936
1937    zone = e_comp_zone_find_by_ec(ec);
1938    EINA_SAFETY_ON_NULL_RETURN_VAL(zone, NULL);
1939
1940    output = e_output_find(zone->output_id);
1941    if (!output)
1942      {
1943         VER("Failed to find 'E_Output': id %s", ec, zone->output_id);
1944         return NULL;
1945      }
1946
1947    hwc_policy = e_zone_video_hwc_policy_get(zone);
1948    if (hwc_policy == E_HWC_POLICY_PLANES)
1949      evh = e_video_hwc_planes_create(output, ec);
1950    else if (hwc_policy == E_HWC_POLICY_WINDOWS)
1951      evh = e_video_hwc_windows_create(output, ec);
1952    else
1953      {
1954         VER("Unknown HWC mode %d", ec, hwc_policy);
1955         return NULL;
1956      }
1957
1958    if (!evh)
1959      {
1960         VER("Failed to create 'E_Video_Hwc'", ec);
1961         return NULL;
1962      }
1963
1964    /* Since video content will be displayed on the overlay plane,
1965     * it's reasonable to keep the size of composite object to 1x1.
1966     * Otherwise, it will cause memory usage to be increased unnecessarily. */
1967    evas_object_resize(ec->frame, 1, 1);
1968
1969    evh->hwc_policy = hwc_policy;
1970    evh->e_output = output;
1971    evh->ec = ec;
1972
1973    //TODO: shoud this function be called here?
1974    tdm_output_get_available_size(output->toutput, NULL, NULL, NULL, NULL,
1975                                  &evh->output_align);
1976
1977    return evh;
1978 }
1979
1980 EINTERN E_Video_Comp_Iface *
1981 e_video_hwc_iface_create(E_Client_Video *ecv)
1982 {
1983    E_Video_Hwc *evh;
1984    E_Client *ec;
1985
1986    ec = e_client_video_ec_get(ecv);
1987
1988    VIN("Create HWC interface", ec);
1989
1990    evh = _e_video_hwc_create(ec);
1991    if (!evh)
1992      return NULL;
1993
1994    _e_video_hwc_client_event_init(evh);
1995
1996    evh->ecv = ecv;
1997
1998    evh->iface.destroy = _e_video_hwc_iface_destroy;
1999    evh->iface.property_get = _e_video_hwc_iface_property_get;
2000    evh->iface.property_set = _e_video_hwc_iface_property_set;
2001    evh->iface.property_delay_set = _e_video_hwc_iface_property_delay_set;
2002    evh->iface.available_properties_get = _e_video_hwc_iface_available_properties_get;
2003    evh->iface.info_get = _e_video_hwc_iface_info_get;
2004    evh->iface.commit_data_release = _e_video_hwc_iface_commit_data_release;
2005    evh->iface.tbm_surface_get = _e_video_hwc_iface_tbm_surface_get;
2006
2007    /* This ec is a video client now. */
2008    e_client_video_hw_composition_set(ecv);
2009
2010    return &evh->iface;
2011 }
2012
2013 EINTERN Eina_Bool
2014 e_video_hwc_current_fb_update(E_Video_Hwc *evh)
2015 {
2016    return _e_video_hwc_current_fb_update(evh);
2017 }
2018
2019 EINTERN void
2020 e_video_hwc_wait_buffer_commit(E_Video_Hwc *evh)
2021 {
2022    _e_video_hwc_wait_buffer_commit(evh);
2023 }
2024
2025 EINTERN void
2026 e_video_hwc_client_mask_update(E_Video_Hwc *evh)
2027 {
2028    E_Client *topmost;
2029    Eina_Bool punch = EINA_FALSE;
2030    int bw, bh;
2031
2032    if (e_video_debug_punch_value_get())
2033      punch = EINA_TRUE;
2034    else if ((topmost = e_comp_wl_topmost_parent_get(evh->ec)))
2035      {
2036         /* if it's laid above main surface */
2037         if ((topmost->comp_data) &&
2038             (eina_list_data_find(topmost->comp_data->sub.list, evh->ec)))
2039           punch = EINA_TRUE;
2040         /* if it's laid under main surface and main surface is transparent */
2041         else if (topmost->argb)
2042           {
2043              /* FIXME: the mask obj can be drawn at the wrong position in the beginnig
2044               * time. It happens caused by window manager policy.
2045               */
2046              if ((topmost->fullscreen || topmost->maximized) &&
2047                  (evh->geo.output_r.x == 0 || evh->geo.output_r.y == 0))
2048                {
2049                   e_pixmap_size_get(topmost->pixmap, &bw, &bh);
2050
2051                   if (bw > 100 && bh > 100 &&
2052                       evh->geo.output_r.w < 100 && evh->geo.output_r.h < 100)
2053                     {
2054                        VIN("don't punch. (%dx%d, %dx%d)", evh->ec,
2055                            bw, bh, evh->geo.output_r.w, evh->geo.output_r.h);
2056                        return;
2057                     }
2058                }
2059
2060              punch = EINA_TRUE;
2061           }
2062      }
2063
2064    if (punch)
2065      {
2066         if (!e_comp_object_mask_has(evh->ec->frame))
2067           {
2068              e_comp_object_mask_set(evh->ec->frame, EINA_TRUE);
2069              VIN("punched", evh->ec);
2070           }
2071      }
2072    else
2073      {
2074         if (e_comp_object_mask_has(evh->ec->frame))
2075           {
2076              e_comp_object_mask_set(evh->ec->frame, EINA_FALSE);
2077              VIN("Un-punched", evh->ec);
2078           }
2079      }
2080 }
2081
2082 /* Sets render fail callback
2083  *
2084  * @in iface A instance of this composition mode
2085  * @in func The function which will be called.
2086  *
2087  * This function will be called if rendering is failed.
2088  * Once this callback funtion has been called, callee will try to replace its
2089  * composition interface to another one. */
2090 EINTERN void
2091 e_video_hwc_render_fail_callback_set(E_Video_Comp_Iface *iface, E_Video_Hwc_Render_Fail_Cb func)
2092 {
2093    E_Video_Hwc *evh;
2094
2095    evh = container_of(iface, E_Video_Hwc, iface);
2096    if (!evh)
2097      return;
2098
2099    evh->render_fail.cb = func;
2100 }