video:hwc_planes: wait next vblank until commit callback handler is called.
[platform/upstream/enlightenment.git] / src / bin / video / iface / e_video_hwc_planes.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "e_video_internal.h"
6 #include "e_video_hwc.h"
7
8 #define CHECKING_PRIMARY_ZPOS
9
10 typedef struct _E_Video_Hwc_Planes E_Video_Hwc_Planes;
11
12 struct _E_Video_Hwc_Planes
13 {
14    E_Video_Hwc base;
15    E_Plane *e_plane;
16    E_Plane_Hook *video_plane_ready_handler;
17
18    struct
19      {
20         tdm_output *output;
21         tdm_layer *layer;
22         /* attributes */
23         Eina_List *prop_list;
24         Eina_List *late_prop_list;
25      } tdm;
26
27    struct
28      {
29         E_Comp_Wl_Video_Buf *vbuf;
30         E_Client_Video_Info info;
31      } pending;
32
33    struct
34      {
35         Eina_Bool commit;
36         Eina_Bool vblank;
37      } wait_flag;
38 };
39
40 typedef struct _Tdm_Prop_Value
41 {
42    unsigned int id;
43    char name[TDM_NAME_LEN];
44    tdm_value value;
45 } Tdm_Prop_Value;
46
47 static Eina_List *video_layers = NULL;
48
49 static Eina_Bool  _e_video_hwc_planes_buffer_commit(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Video_Buf *vbuf, E_Client_Video_Info *info);
50
51 static void
52 _e_video_hwc_planes_pending_buffer_commit(E_Video_Hwc_Planes *evhp)
53 {
54    if (evhp->pending.vbuf)
55      {
56         _e_video_hwc_planes_buffer_commit(evhp,
57                                           evhp->pending.vbuf,
58                                           &evhp->pending.info);
59         evhp->pending.vbuf = NULL;
60      }
61    else
62      e_video_hwc_wait_buffer_commit((E_Video_Hwc *)evhp);
63 }
64
65 static Eina_Bool
66 _e_video_hwc_planes_prop_list_update(Eina_List *prop_list, const char *name, tdm_value value)
67 {
68    Tdm_Prop_Value *prop;
69    Eina_List *l;
70
71    EINA_LIST_FOREACH(prop_list, l, prop)
72      {
73         if (strncmp(name, prop->name, TDM_NAME_LEN))
74           continue;
75
76         VDB("update property(%s) value(%d -> %d)",
77             NULL, name, prop->value.u32, value.u32);
78
79         prop->value.u32 = value.u32;
80
81         return EINA_TRUE;
82      }
83
84    return EINA_FALSE;
85 }
86
87 static Eina_Bool
88 _e_video_hwc_planes_prop_list_append(Eina_List **prop_list, unsigned int id, const char *name, tdm_value value)
89 {
90    Tdm_Prop_Value *prop;
91
92    prop = calloc(1, sizeof(Tdm_Prop_Value));
93    if (!prop)
94      {
95         VER("failed to alloc memory: property(%s) value(%d)",
96             NULL, name, value.u32);
97         return EINA_FALSE;
98      }
99
100    prop->value.u32 = value.u32;
101    prop->id = id;
102    memcpy(prop->name, name, sizeof(TDM_NAME_LEN));
103
104    VIN("Add property(%s) value(%d)", NULL, name, value.u32);
105
106    *prop_list = eina_list_append(*prop_list, prop);
107
108    return EINA_TRUE;
109 }
110
111 static tdm_layer *
112 _tdm_output_video_layer_get(tdm_output *output)
113 {
114    tdm_layer *layer;
115    tdm_layer_capability capabilities = 0;
116    int i, count = 0;
117 #ifdef CHECKING_PRIMARY_ZPOS
118    int primary_idx = 0, primary_zpos = 0;
119    tdm_layer *primary_layer;
120 #endif
121
122    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
123
124    tdm_output_get_layer_count(output, &count);
125    for (i = 0; i < count; i++)
126      {
127         layer = tdm_output_get_layer(output, i, NULL);
128         EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
129
130         tdm_layer_get_capabilities(layer, &capabilities);
131         if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
132           return layer;
133      }
134
135 #ifdef CHECKING_PRIMARY_ZPOS
136    tdm_output_get_primary_index(output, &primary_idx);
137    primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
138    EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
139    tdm_layer_get_zpos(primary_layer, &primary_zpos);
140 #endif
141
142    for (i = 0; i < count; i++)
143      {
144         layer = tdm_output_get_layer(output, i, NULL);
145         EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
146
147         tdm_layer_get_capabilities(layer, &capabilities);
148         if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
149           {
150 #ifdef CHECKING_PRIMARY_ZPOS
151              int zpos = 0;
152              tdm_layer_get_zpos(layer, &zpos);
153              if (zpos >= primary_zpos) continue;
154 #endif
155              return layer;
156           }
157      }
158
159    return NULL;
160 }
161
162 static Eina_Bool
163 _tdm_output_video_layer_exists(tdm_output *toutput)
164 {
165    tdm_layer *layer;
166    tdm_layer_capability lyr_capabilities = 0;
167
168    EINA_SAFETY_ON_NULL_RETURN_VAL(toutput, EINA_FALSE);
169
170    /* get the first suitable layer */
171    layer = _tdm_output_video_layer_get(toutput);
172    if (!layer)
173      return EINA_FALSE;
174
175    tdm_layer_get_capabilities(layer, &lyr_capabilities);
176    if (lyr_capabilities & TDM_LAYER_CAPABILITY_VIDEO)
177      return EINA_TRUE;
178
179    return EINA_FALSE;
180 }
181
182 static tdm_error
183 _tdm_layer_info_get(tdm_layer *layer, E_Client_Video_Info *vinfo)
184 {
185    tdm_error ret = TDM_ERROR_NONE;
186    tdm_info_layer tinfo = {0};
187
188    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_INVALID_PARAMETER);
189    EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, TDM_ERROR_INVALID_PARAMETER);
190
191    ret = tdm_layer_get_info(layer, &tinfo);
192    EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
193
194    memcpy(&vinfo->src_config, &tinfo.src_config, sizeof(tdm_info_config));
195    memcpy(&vinfo->dst_pos, &tinfo.dst_pos, sizeof(tdm_pos));
196    vinfo->transform = tinfo.transform;
197
198    return ret;
199 }
200
201 static tdm_error
202 _tdm_layer_info_set(tdm_layer *layer, E_Client_Video_Info *vinfo)
203 {
204    tdm_error ret = TDM_ERROR_NONE;
205    tdm_info_layer info_layer = {0};
206
207    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_INVALID_PARAMETER);
208    EINA_SAFETY_ON_NULL_RETURN_VAL(vinfo, TDM_ERROR_INVALID_PARAMETER);
209
210    memcpy(&info_layer.src_config, &vinfo->src_config, sizeof(tdm_info_config));
211    memcpy(&info_layer.dst_pos, &vinfo->dst_pos, sizeof(tdm_pos));
212    info_layer.transform = vinfo->transform;
213
214    ret = tdm_layer_set_info(layer, &info_layer);
215
216    return ret;
217 }
218
219 static tdm_error
220 _tdm_layer_buffer_set(tdm_layer *layer, tbm_surface_h buff)
221 {
222    tdm_error ret = TDM_ERROR_NONE;
223
224    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
225    EINA_SAFETY_ON_NULL_RETURN_VAL(buff, TDM_ERROR_BAD_REQUEST);
226
227    ret = tdm_layer_set_buffer(layer, buff);
228
229    return ret;
230 }
231
232 static tdm_error
233 _tdm_layer_buffer_unset(tdm_layer *layer)
234 {
235    tdm_error ret;
236
237    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
238
239    ret = tdm_layer_unset_buffer(layer);
240
241    return ret;
242 }
243
244 /*
245  * This function checks if this layer was set
246  */
247 static tdm_error
248 _tdm_layer_usable_get(tdm_layer *layer, unsigned int *usable)
249 {
250    tdm_error ret;
251
252    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
253    EINA_SAFETY_ON_NULL_RETURN_VAL(usable, TDM_ERROR_BAD_REQUEST);
254
255    ret = tdm_layer_is_usable(layer, usable);
256    return ret;
257 }
258
259 static tdm_error
260 _tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data)
261 {
262    tdm_error ret = TDM_ERROR_NONE;
263
264    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
265
266    ret = tdm_layer_commit(layer, func, user_data);
267
268    return ret;
269 }
270
271 static tbm_surface_h
272 _tdm_layer_displaying_buffer_get(tdm_layer *layer, int *tdm_error)
273 {
274    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
275
276    return tdm_layer_get_displaying_buffer(layer, tdm_error);
277 }
278
279 static tdm_error
280 _tdm_layer_property_set(tdm_layer *layer, Tdm_Prop_Value *prop)
281 {
282    tdm_error ret;
283
284    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
285
286    ret = tdm_layer_set_property(layer, prop->id, prop->value);
287    return ret;
288 }
289
290 static tdm_error
291 _tdm_layer_property_get(tdm_layer *layer, unsigned id, tdm_value *value)
292 {
293    EINA_SAFETY_ON_NULL_RETURN_VAL(layer, TDM_ERROR_BAD_REQUEST);
294    EINA_SAFETY_ON_NULL_RETURN_VAL(value, TDM_ERROR_BAD_REQUEST);
295
296    return tdm_layer_get_property(layer, id, value);
297 }
298
299 static void
300 _tdm_layer_property_list_set(tdm_layer *layer, Eina_List **list)
301 {
302    Tdm_Prop_Value *prop;
303
304    EINA_LIST_FREE((*list), prop)
305      {
306         VIN("call property(%s), value(%d)", NULL, prop->name,
307             (unsigned int)prop->value.u32);
308         _tdm_layer_property_set(layer, prop);
309         free(prop);
310      }
311 }
312
313 static void
314 _e_video_hwc_planes_cb_eplane_video_set_hook(void *data, E_Plane *plane)
315 {
316    E_Video_Hwc_Planes *evhp;
317
318    evhp = (E_Video_Hwc_Planes *)data;
319    if (evhp->e_plane != plane) return;
320
321    E_FREE_FUNC(evhp->video_plane_ready_handler, e_plane_hook_del);
322
323    if (evhp->wait_flag.vblank) return;
324
325    _e_video_hwc_planes_pending_buffer_commit(evhp);
326 }
327
328 static void
329 _e_video_hwc_planes_tdm_layer_usable_set(tdm_layer *layer, Eina_Bool usable)
330 {
331    tdm_layer *used_layer;
332    Eina_List *l = NULL;
333
334    if (usable)
335      video_layers = eina_list_remove(video_layers, layer);
336    else
337      {
338         EINA_LIST_FOREACH(video_layers, l, used_layer)
339            if (used_layer == layer) return;
340         video_layers = eina_list_append(video_layers, layer);
341      }
342 }
343
344 static Eina_Bool
345 _e_video_hwc_planes_tdm_layer_usable_get(tdm_layer *layer)
346 {
347    tdm_layer *used_layer;
348    Eina_List *l = NULL;
349
350    EINA_LIST_FOREACH(video_layers, l, used_layer)
351       if (used_layer == layer)
352         return EINA_FALSE;
353    return EINA_TRUE;
354 }
355
356 static tdm_layer *
357 _e_video_hwc_planes_available_video_tdm_layer_get(tdm_output *output)
358 {
359    tdm_layer *layer;
360    tdm_layer_capability capabilities = 0;
361    Eina_Bool has_video_layer = EINA_FALSE;
362    int i, count = 0;
363 #ifdef CHECKING_PRIMARY_ZPOS
364    int primary_idx = 0, primary_zpos = 0;
365    tdm_layer *primary_layer;
366 #endif
367
368    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
369
370    /* check video layers first */
371    tdm_output_get_layer_count(output, &count);
372    for (i = 0; i < count; i++)
373      {
374         layer = tdm_output_get_layer(output, i, NULL);
375         EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
376
377         tdm_layer_get_capabilities(layer, &capabilities);
378         if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
379           {
380              has_video_layer = EINA_TRUE;
381              if (!_e_video_hwc_planes_tdm_layer_usable_get(layer)) continue;
382              return layer;
383           }
384      }
385
386    /* if a output has video layers, it means that there is no available video layer for video */
387    if (has_video_layer)
388      return NULL;
389
390    /* check graphic layers second */
391 #ifdef CHECKING_PRIMARY_ZPOS
392    tdm_output_get_primary_index(output, &primary_idx);
393    primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
394    EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
395    tdm_layer_get_zpos(primary_layer, &primary_zpos);
396 #endif
397
398    for (i = 0; i < count; i++)
399      {
400         layer = tdm_output_get_layer(output, i, NULL);
401         EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
402
403         tdm_layer_get_capabilities(layer, &capabilities);
404         if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
405           {
406 #ifdef CHECKING_PRIMARY_ZPOS
407              int zpos = 0;
408              tdm_layer_get_zpos(layer, &zpos);
409              if (zpos >= primary_zpos) continue;
410 #endif
411              if (!_e_video_hwc_planes_tdm_layer_usable_get(layer)) continue;
412              return layer;
413           }
414      }
415
416    return NULL;
417 }
418
419 static Eina_Bool
420 _e_video_hwc_planes_tdm_layer_set(E_Video_Hwc_Planes *evhp)
421 {
422    E_Plane *plane = NULL;
423    Eina_Bool need_wait;
424    tdm_layer *layer;
425    tdm_error ret;
426    int zpos;
427
428    if (evhp->tdm.layer)
429      return EINA_TRUE;
430
431    layer = _e_video_hwc_planes_available_video_tdm_layer_get(evhp->tdm.output);
432    if (!layer)
433      {
434         VWR("no available layer for evhp", NULL);
435         return EINA_FALSE;
436      }
437
438    _e_video_hwc_planes_tdm_layer_usable_set(layer, EINA_FALSE);
439
440    ret = tdm_layer_get_zpos(layer, &zpos);
441    if (ret == TDM_ERROR_NONE)
442      plane = e_output_plane_get_by_zpos(evhp->base.e_output, zpos);
443
444    if (!plane)
445      {
446         VWR("fail get e_plane", NULL);
447         goto err_plane;
448      }
449
450    if (!e_plane_video_set(plane, EINA_TRUE, &need_wait))
451      {
452         VWR("fail set video to e_plane", NULL);
453         goto err_plane;
454      }
455
456    if (need_wait)
457      {
458         evhp->video_plane_ready_handler =
459            e_plane_hook_add(E_PLANE_HOOK_VIDEO_SET,
460                             _e_video_hwc_planes_cb_eplane_video_set_hook, evhp);
461      }
462
463    evhp->tdm.layer = layer;
464    evhp->e_plane = plane;
465
466    VIN("assign layer: %p", NULL, evhp->tdm.layer);
467
468    return EINA_TRUE;
469
470 err_plane:
471    _e_video_hwc_planes_tdm_layer_usable_set(evhp->tdm.layer, EINA_TRUE);
472
473    return EINA_FALSE;
474 }
475
476 static void
477 _e_video_hwc_planes_tdm_layer_unset(E_Video_Hwc_Planes *evhp)
478 {
479    unsigned int usable = 1;
480
481    if (!evhp->tdm.layer) return;
482
483    _tdm_layer_usable_get(evhp->tdm.layer, &usable);
484    if (!usable && !evhp->video_plane_ready_handler)
485      {
486         VIN("stop video", evhp->base.ec);
487         _tdm_layer_buffer_unset(evhp->tdm.layer);
488         _tdm_layer_commit(evhp->tdm.layer, NULL, NULL);
489      }
490
491    VIN("release layer: %p", evhp->base.ec, evhp->tdm.layer);
492    _e_video_hwc_planes_tdm_layer_usable_set(evhp->tdm.layer, EINA_TRUE);
493    evhp->tdm.layer = NULL;
494    evhp->base.old_comp_buffer = NULL;
495
496    e_plane_video_set(evhp->e_plane, EINA_FALSE, NULL);
497    evhp->e_plane = NULL;
498
499    E_FREE_FUNC(evhp->video_plane_ready_handler, e_plane_hook_del);
500 }
501
502 static void
503 _e_video_hwc_planes_cb_commit_handler(tdm_layer *layer, unsigned int sequence,
504                                       unsigned int tv_sec, unsigned int tv_usec,
505                                       void *user_data)
506 {
507    E_Video_Hwc_Planes *evhp;
508
509    evhp = user_data;
510    if (!evhp) return;
511
512    if (!evhp->wait_flag.commit)
513      NEVER_GET_HERE();
514
515    evhp->wait_flag.commit = EINA_FALSE;
516
517    e_video_hwc_current_fb_update((E_Video_Hwc *)evhp);
518 }
519
520 static void
521 _e_video_hwc_planes_cb_vblank_handler(tdm_output *output, unsigned int sequence,
522                                       unsigned int tv_sec, unsigned int tv_usec,
523                                       void *user_data)
524 {
525    E_Video_Hwc_Planes *evhp;
526    tdm_error err;
527
528    evhp = user_data;
529    if (!evhp) return;
530
531    evhp->wait_flag.vblank = EINA_FALSE;
532
533    if (evhp->video_plane_ready_handler) return;
534
535    if (evhp->wait_flag.commit)
536      {
537         /* wait next vblank in case commit handler is not called yet. Because
538          * that means committed buffer is not on display yet. */
539         err = tdm_output_wait_vblank(evhp->tdm.output, 1, 0,
540                                      _e_video_hwc_planes_cb_vblank_handler,
541                                      evhp);
542         if (err != TDM_ERROR_NONE)
543           {
544              VER("failed to set handler for wait vblank", evhp->base.ec);
545              return;
546           }
547
548         evhp->wait_flag.vblank = EINA_TRUE;
549      }
550    else
551      _e_video_hwc_planes_pending_buffer_commit(evhp);
552 }
553
554 static Eina_Bool
555 _e_video_hwc_planes_buffer_commit(E_Video_Hwc_Planes *evhp, E_Comp_Wl_Video_Buf *vbuf, E_Client_Video_Info *info)
556 {
557    E_Client_Video_Info old_info;
558    tdm_error ret;
559
560    if (evhp->tdm.prop_list)
561      {
562         // need call tdm property in list
563         _tdm_layer_property_list_set(evhp->tdm.layer, &evhp->tdm.prop_list);
564      }
565
566    CLEAR(old_info);
567    ret = _tdm_layer_info_get(evhp->tdm.layer, &old_info);
568    EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
569
570    if (memcmp(&old_info, info, sizeof(tdm_info_layer)))
571      {
572         ret = _tdm_layer_info_set(evhp->tdm.layer, info);
573         EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
574      }
575
576    ret = _tdm_layer_buffer_set(evhp->tdm.layer, vbuf->tbm_surface);
577    EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
578
579    ret = _tdm_layer_commit(evhp->tdm.layer, _e_video_hwc_planes_cb_commit_handler, evhp);
580    EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
581
582    ret = tdm_output_wait_vblank(evhp->tdm.output, 1, 0, _e_video_hwc_planes_cb_vblank_handler, evhp);
583    EINA_SAFETY_ON_FALSE_RETURN_VAL(ret == TDM_ERROR_NONE, EINA_FALSE);
584
585    evhp->wait_flag.commit = EINA_TRUE;
586    evhp->wait_flag.vblank = EINA_TRUE;
587
588    _tdm_layer_property_list_set(evhp->tdm.layer, &evhp->tdm.late_prop_list);
589
590    e_video_hwc_client_mask_update((E_Video_Hwc *)evhp);
591
592    DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p, refcnt:%d) is shown."
593        "Geometry details are : buffer size(%dx%d) src(%d,%d, %dx%d)"
594        " dst(%d,%d, %dx%d), transform(%d)",
595        e_client_util_name_get(evhp->base.ec) ?: "No Name" , evhp->base.ec->netwm.pid,
596        wl_resource_get_id(evhp->base.ec->comp_data->surface), vbuf, vbuf->ref_cnt,
597        info->src_config.size.h, info->src_config.size.v, info->src_config.pos.x,
598        info->src_config.pos.y, info->src_config.pos.w, info->src_config.pos.h,
599        info->dst_pos.x, info->dst_pos.y, info->dst_pos.w, info->dst_pos.h, info->transform);
600
601    return EINA_TRUE;
602 }
603
604 static void
605 _e_video_hwc_planes_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
606 {
607    E_Video_Hwc_Planes *evhp = data;
608
609    if (e_object_is_del(E_OBJECT(evhp->base.ec))) return;
610
611    /* if stand_alone is true, not hide */
612    if (evhp->base.ec->comp_data->sub.data && evhp->base.ec->comp_data->sub.data->stand_alone)
613      return;
614
615    VIN("evas hide", evhp->base.ec);
616    if (evhp->tdm.layer)
617      {
618         VIN("unset layer: hide", evhp->base.ec);
619         _e_video_hwc_planes_tdm_layer_unset(evhp);
620      }
621 }
622
623 static tdm_error
624 _e_video_hwc_planes_available_properties_get(E_Video_Hwc_Planes *evhp,
625                                              const tdm_prop **props,
626                                              int *count)
627 {
628    tdm_layer *tlayer;
629    tdm_error ret = TDM_ERROR_OPERATION_FAILED;
630
631    EINA_SAFETY_ON_NULL_RETURN_VAL(evhp, TDM_ERROR_BAD_REQUEST);
632    EINA_SAFETY_ON_NULL_RETURN_VAL(props, TDM_ERROR_BAD_REQUEST);
633    EINA_SAFETY_ON_NULL_RETURN_VAL(count, TDM_ERROR_BAD_REQUEST);
634
635    tlayer = evhp->tdm.layer;
636    /* if layer wasn't set then get an any available tdm_layer */
637    if (tlayer == NULL)
638      tlayer = _e_video_hwc_planes_available_video_tdm_layer_get(evhp->tdm.output);
639    ret = tdm_layer_get_available_properties(tlayer, props, count);
640
641    return ret;
642 }
643
644 static Eina_Bool
645 _e_video_hwc_planes_init(E_Video_Hwc_Planes *evhp, E_Output *output)
646 {
647    /* If tdm offers video layers, we will assign a tdm layer when showing */
648    if (!_tdm_output_video_layer_exists(output->toutput))
649      {
650         /* If tdm doesn't offer video layers, we assign a tdm layer now. If
651          * failed, video will be displayed via the UI rendering path. */
652         if (!_e_video_hwc_planes_tdm_layer_set(evhp))
653           return EINA_FALSE;
654      }
655
656    return EINA_TRUE;
657 }
658
659 static void
660 _e_video_hwc_planes_destroy(E_Video_Hwc_Planes *evhp)
661 {
662    Tdm_Prop_Value *tdm_prop;
663
664    if (!evhp)
665      return;
666
667    VIN("destroy", evhp->base.ec);
668
669    if (evhp->tdm.prop_list)
670      {
671         EINA_LIST_FREE(evhp->tdm.prop_list, tdm_prop)
672            free(tdm_prop);
673      }
674    if (evhp->tdm.late_prop_list)
675      {
676         EINA_LIST_FREE(evhp->tdm.late_prop_list, tdm_prop)
677            free(tdm_prop);
678      }
679
680    if (evhp->tdm.prop_list)
681      NEVER_GET_HERE();
682    if (evhp->tdm.late_prop_list)
683      NEVER_GET_HERE();
684
685    if (evhp->tdm.layer)
686      {
687         VIN("unset layer: destroy", evhp->base.ec);
688         _e_video_hwc_planes_tdm_layer_unset(evhp);
689      }
690
691    free(evhp);
692 }
693
694 static void
695 _e_video_hwc_planes_ec_event_deinit(E_Video_Hwc_Planes *evhp)
696 {
697    E_Client *ec;
698
699    ec = evhp->base.ec;
700
701    evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_HIDE,
702                                        _e_video_hwc_planes_cb_evas_hide, evhp);
703 }
704
705 const char *
706 _e_video_hwc_planes_prop_name_get_by_id(E_Video_Hwc_Planes *evhp, unsigned int id)
707 {
708    tdm_layer *layer;
709    const tdm_prop *props;
710    int i, count = 0;
711
712    layer = _tdm_output_video_layer_get(evhp->tdm.output);
713    tdm_layer_get_available_properties(layer, &props, &count);
714    for (i = 0; i < count; i++)
715      {
716         if (props[i].id == id)
717           {
718              VDB("check property(%s)", evhp->base.ec, props[i].name);
719              return props[i].name;
720           }
721      }
722
723    return NULL;
724 }
725
726 static void
727 _e_video_hwc_planes_property_post_set(E_Video_Hwc_Planes *evhp,
728                                       unsigned int id,
729                                       const char *name,
730                                       tdm_value value)
731 {
732    Eina_Bool res;
733
734    VDB("property_post_set: property(%s) value(%d)",
735        evhp->base.ec, name, value.u32);
736
737    res = _e_video_hwc_planes_prop_list_update(evhp->tdm.late_prop_list,
738                                               name,
739                                               value);
740    if (res)
741      return;
742
743    _e_video_hwc_planes_prop_list_append(&evhp->tdm.late_prop_list,
744                                         id, name, value);
745 }
746
747 static Eina_Bool
748 _e_video_hwc_planes_property_pre_set(E_Video_Hwc_Planes *evhp,
749                                      unsigned int id,
750                                      const char *name,
751                                      tdm_value value)
752 {
753    Eina_Bool res;
754
755    VDB("property_pre_set: property(%s) value(%d)",
756        evhp->base.ec, name, value.u32);
757
758    res = _e_video_hwc_planes_prop_list_update(evhp->tdm.prop_list,
759                                               name,
760                                               value);
761    if (res)
762      return EINA_TRUE;
763
764    res = _e_video_hwc_planes_prop_list_update(evhp->tdm.late_prop_list,
765                                               name,
766                                               value);
767    if (res)
768      return EINA_TRUE;
769
770    res = _e_video_hwc_planes_prop_list_append(&evhp->tdm.prop_list,
771                                               id, name, value);
772
773    return res;
774 }
775
776 static Eina_Bool
777 _e_video_hwc_planes_property_save(E_Video_Hwc_Planes *evhp, unsigned int id, const char *name, tdm_value value)
778 {
779    return _e_video_hwc_planes_property_pre_set(evhp, id, name, value);
780 }
781
782 static void
783 _e_video_hwc_planes_ec_event_init(E_Video_Hwc_Planes *evhp, E_Client *ec)
784 {
785    evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE,
786                                   _e_video_hwc_planes_cb_evas_hide, evhp);
787 }
788
789 static void
790 _e_video_hwc_planes_iface_destroy(E_Video_Hwc *evh)
791 {
792    E_Video_Hwc_Planes *evhp;
793
794    evhp = (E_Video_Hwc_Planes *)evh;
795    _e_video_hwc_planes_ec_event_deinit(evhp);
796    _e_video_hwc_planes_destroy(evhp);
797 }
798
799 static Eina_Bool
800 _e_video_hwc_planes_iface_property_get(E_Video_Hwc *evh, unsigned int id, tdm_value *value)
801 {
802    E_Video_Hwc_Planes *evhp;
803    tdm_error ret;
804
805    evhp = (E_Video_Hwc_Planes *)evh;
806    ret = _tdm_layer_property_get(evhp->tdm.layer, id, value);
807    if (ret != TDM_ERROR_NONE)
808      return EINA_FALSE;
809
810    return EINA_TRUE;
811 }
812
813 static Eina_Bool
814 _e_video_hwc_planes_iface_property_set(E_Video_Hwc *evh, unsigned int id, tdm_value value, Eina_Bool sync)
815 {
816    E_Video_Hwc_Planes *evhp;
817    Tdm_Prop_Value prop;
818    const char *name;
819
820    evhp = (E_Video_Hwc_Planes *)evh;
821    VIN("set layer: set_attribute", evhp->base.ec);
822
823    name = _e_video_hwc_planes_prop_name_get_by_id(evhp, id);
824
825    if (!evhp->tdm.layer)
826      {
827         /* FIXME
828          * Set property with assigning layer right away if allowed_attribute
829          * flag is set. The reason why we have to do like this isn't figured
830          * yet. It's for backward compatibility. */
831         if ((e_client_video_property_allow_get(evhp->base.ecv)) ||
832             (sync == EINA_TRUE))
833           {
834              if (!_e_video_hwc_planes_tdm_layer_set(evhp))
835                {
836                   VER("set layer failed", evhp->base.ec);
837                   return EINA_FALSE;
838                }
839
840              if (evhp->video_plane_ready_handler)
841                {
842                   VIN("wait for video plane ready", evhp->base.ec);
843                   goto save;
844                }
845           }
846         else
847           {
848              VIN("layer is not yet assigned", evhp->base.ec);
849              goto save;
850           }
851      }
852
853    VIN("set layer: call property(%s), value(%d)", evhp->base.ec, name, value.u32);
854
855    prop.id = id;
856    prop.value = value;
857    _tdm_layer_property_set(evhp->tdm.layer, &prop);
858
859    return EINA_TRUE;
860
861 save:
862    VIN("save property value", evhp->base.ec);
863    if (!_e_video_hwc_planes_property_save(evhp, id, name, value))
864      {
865         VER("save property failed", evhp->base.ec);
866         return EINA_FALSE;
867      }
868
869    return EINA_TRUE;
870 }
871
872 static Eina_Bool
873 _e_video_hwc_planes_iface_available_properties_get(E_Video_Hwc *evh, const tdm_prop **props, int *count)
874 {
875    E_Video_Hwc_Planes *evhp;
876    tdm_error ret;
877
878    evhp = (E_Video_Hwc_Planes *)evh;
879    ret = _e_video_hwc_planes_available_properties_get(evhp, props, count);
880    if (ret != TDM_ERROR_NONE)
881      return EINA_FALSE;
882
883    return EINA_TRUE;
884 }
885
886 static Eina_Bool
887 _e_video_hwc_planes_iface_buffer_commit(E_Video_Hwc *evh, E_Comp_Wl_Video_Buf *vbuf)
888 {
889    E_Video_Hwc_Planes *evhp;
890    E_Client_Video_Info info;
891    Eina_Bool ret = EINA_TRUE;
892
893    evhp = (E_Video_Hwc_Planes *)evh;
894    if (!vbuf)
895      {
896         if (evhp->tdm.layer)
897           {
898              VIN("unset layer: hide", evhp->base.ec);
899              _e_video_hwc_planes_tdm_layer_unset(evhp);
900           }
901      }
902    else
903      {
904         CLEAR(info);
905         info.src_config.size.h = vbuf->width_from_pitch;
906         info.src_config.size.v = vbuf->height_from_size;
907         info.src_config.pos.x = vbuf->content_r.x;
908         info.src_config.pos.y = vbuf->content_r.y;
909         info.src_config.pos.w = vbuf->content_r.w;
910         info.src_config.pos.h = vbuf->content_r.h;
911         info.src_config.format = vbuf->tbmfmt;
912         info.dst_pos.x = evhp->base.geo.tdm.output_r.x;
913         info.dst_pos.y = evhp->base.geo.tdm.output_r.y;
914         info.dst_pos.w = evhp->base.geo.tdm.output_r.w;
915         info.dst_pos.h = evhp->base.geo.tdm.output_r.h;
916         info.transform = vbuf->content_t;
917
918         if (!evhp->tdm.layer)
919           {
920              VIN("set layer: show", evhp->base.ec);
921              if (!_e_video_hwc_planes_tdm_layer_set(evhp))
922                {
923                   VER("set layer failed", evhp->base.ec);
924                   return EINA_FALSE;
925                }
926           }
927
928         if (evhp->video_plane_ready_handler)
929           {
930              VIN("wait for video plane ready: Pending commit vbuf(%p)",
931                  evhp->base.ec, vbuf);
932
933              if (evhp->pending.vbuf)
934                {
935                   /* Cannot reach here because following buffers are supposed
936                    * to be queued by 'e_video_hwc' until calling fb_update by
937                    * this child module. */
938                   NEVER_GET_HERE();
939
940                   return EINA_FALSE;
941                }
942
943              evhp->pending.vbuf = vbuf;
944              memcpy(&evhp->pending.info, &info, sizeof(E_Client_Video_Info));
945
946              return EINA_TRUE;
947           }
948
949         ret = _e_video_hwc_planes_buffer_commit(evhp, vbuf, &info);
950      }
951
952    return ret;
953 }
954
955 static Eina_Bool
956 _e_video_hwc_planes_iface_check_if_pp_needed(E_Video_Hwc *evh)
957 {
958    E_Video_Hwc_Planes *evhp;
959    int i, count = 0;
960    const tbm_format *formats;
961    Eina_Bool found = EINA_FALSE;
962    tdm_layer_capability capabilities = 0;
963
964    evhp = (E_Video_Hwc_Planes *)evh;
965
966    tdm_layer *layer = _tdm_output_video_layer_get(evhp->tdm.output);
967
968    tdm_layer_get_capabilities(layer, &capabilities);
969
970    /* don't need pp if a layer has TDM_LAYER_CAPABILITY_VIDEO capability*/
971    if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
972      return EINA_FALSE;
973
974    /* check formats */
975    tdm_layer_get_available_formats(layer, &formats, &count);
976    for (i = 0; i < count; i++)
977      if (formats[i] == evhp->base.tbmfmt)
978        {
979           found = EINA_TRUE;
980           break;
981        }
982
983    if (!found)
984      {
985         if (formats && count > 0)
986           evhp->base.pp_tbmfmt = formats[0];
987         else
988           {
989              WRN("No layer format information!!!");
990              evhp->base.pp_tbmfmt = TBM_FORMAT_ARGB8888;
991           }
992         return EINA_TRUE;
993      }
994
995    if (capabilities & TDM_LAYER_CAPABILITY_SCANOUT)
996      goto need_pp;
997
998    /* check size */
999    if (evhp->base.geo.input_r.w != evhp->base.geo.output_r.w || evhp->base.geo.input_r.h != evhp->base.geo.output_r.h)
1000      if (!(capabilities & TDM_LAYER_CAPABILITY_SCALE))
1001        goto need_pp;
1002
1003    /* check rotate */
1004    if (evhp->base.geo.transform || e_comp->e_comp_screen->rotation > 0)
1005      if (!(capabilities & TDM_LAYER_CAPABILITY_TRANSFORM))
1006        goto need_pp;
1007
1008    return EINA_FALSE;
1009
1010 need_pp:
1011    evhp->base.pp_tbmfmt = evhp->base.tbmfmt;
1012    return EINA_TRUE;
1013 }
1014
1015 static tbm_surface_h
1016 _e_video_hwc_planes_iface_displaying_buffer_get(E_Video_Hwc *evh)
1017 {
1018    E_Video_Hwc_Planes *evhp;
1019
1020    evhp = (E_Video_Hwc_Planes *)evh;
1021    return _tdm_layer_displaying_buffer_get(evhp->tdm.layer, NULL);
1022 }
1023
1024 static void
1025 _e_video_hwc_planes_iface_set(E_Video_Hwc_Iface *iface)
1026 {
1027    iface->destroy = _e_video_hwc_planes_iface_destroy;
1028    iface->property_get = _e_video_hwc_planes_iface_property_get;
1029    iface->property_set = _e_video_hwc_planes_iface_property_set;
1030    iface->available_properties_get = _e_video_hwc_planes_iface_available_properties_get;
1031    iface->buffer_commit = _e_video_hwc_planes_iface_buffer_commit;
1032    iface->check_if_pp_needed = _e_video_hwc_planes_iface_check_if_pp_needed;
1033    iface->displaying_buffer_get = _e_video_hwc_planes_iface_displaying_buffer_get;
1034 }
1035
1036 EINTERN E_Video_Hwc *
1037 e_video_hwc_planes_create(E_Output *output, E_Client *ec)
1038 {
1039    E_Video_Hwc_Planes *evhp;
1040
1041    EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
1042    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, NULL);
1043
1044    VIN("Create HWC Planes backend", ec);
1045
1046    evhp = E_NEW(E_Video_Hwc_Planes, 1);
1047    EINA_SAFETY_ON_NULL_RETURN_VAL(evhp, NULL);
1048
1049    evhp->base.e_output = output;
1050    evhp->tdm.output = output->toutput;
1051
1052    if (!_e_video_hwc_planes_init(evhp, output))
1053      {
1054         ERR("Failed to init 'E_Video_Hwc_Planes'");
1055         free(evhp);
1056         return NULL;
1057      }
1058
1059    _e_video_hwc_planes_ec_event_init(evhp, ec);
1060    _e_video_hwc_planes_iface_set(&evhp->base.backend);
1061
1062    return (E_Video_Hwc *)evhp;
1063 }
1064
1065 EINTERN Eina_Bool
1066 e_video_hwc_planes_property_delay_set(E_Video_Hwc *evh, unsigned int id, tdm_value value)
1067 {
1068    E_Video_Hwc_Planes *evhp;
1069    const char *name;
1070
1071    evhp = (E_Video_Hwc_Planes *)evh;
1072    name = _e_video_hwc_planes_prop_name_get_by_id(evhp, id);
1073
1074    _e_video_hwc_planes_property_post_set(evhp, id, name, value);
1075
1076    return EINA_TRUE;
1077 }