e_video_hwc_windows: add the first implementation
authorSooChan Lim <sc1.lim@samsung.com>
Sun, 16 Dec 2018 07:31:46 +0000 (16:31 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Fri, 21 Dec 2018 10:27:44 +0000 (19:27 +0900)
Change-Id: Ib8eccf5eeec3e51b94c3f02c4a9e6c3e98de46fb

12 files changed:
src/bin/Makefile.mk
src/bin/e_hwc.h
src/bin/e_hwc_window.c
src/bin/e_hwc_window.h
src/bin/e_hwc_windows.c
src/bin/e_hwc_windows.h
src/bin/video/e_client_video.c
src/bin/video/e_comp_wl_video.c
src/bin/video/e_comp_wl_video.h
src/bin/video/e_video_internal.h
src/bin/video/iface/e_video_hwc_planes.c
src/bin/video/iface/e_video_hwc_windows.c [new file with mode: 0644]

index 66f9fad..6177c9d 100644 (file)
@@ -222,6 +222,7 @@ src/bin/video/e_client_video.c \
 src/bin/video/e_zone_video.c \
 src/bin/video/e_video_debug.c \
 src/bin/video/iface/e_video_hwc_planes.c \
+src/bin/video/iface/e_video_hwc_windows.c \
 src/bin/video/iface/e_video_fallback.c \
 src/bin/e_comp_wl_viewport.c \
 src/bin/e_comp_wl_screenshooter.c \
index c165b3a..4cd1d6e 100644 (file)
@@ -62,6 +62,12 @@ struct _E_Hwc
    Eina_List           *visible_windows;
    int                  num_visible_windows;
 
+   /* capabilities */
+   Eina_Bool     tdm_hwc_video_stream;
+   Eina_Bool     tdm_hwc_video_scale;
+   Eina_Bool     tdm_hwc_video_transform;
+   Eina_Bool     tdm_hwc_video_scanout;
+
    Eina_Bool            intercept_pol;
 
    /* variables for pp at hwc_windows policy */
index 8947ed2..7aa561d 100644 (file)
@@ -45,6 +45,13 @@ static Eina_List *hwc_window_event_hdlrs = NULL;
 static int _e_hwc_window_hooks_delete = 0;
 static int _e_hwc_window_hooks_walking = 0;
 
+typedef struct _Hwc_Window_Prop
+{
+   unsigned int id;
+   char name[TDM_NAME_LEN];
+   tdm_value value;
+} Hwc_Window_Prop;
+
 static Eina_Inlist *_e_hwc_window_hooks[] =
 {
    [E_HWC_WINDOW_HOOK_ACCEPTED_STATE_CHANGE] = NULL,
@@ -274,12 +281,16 @@ _e_hwc_window_client_cb_new(void *data EINA_UNUSED, E_Client *ec)
    if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
      return;
 
+   if (ec->hwc_window && e_hwc_window_is_video(ec->hwc_window))
+     {
+        EHWINF("is already created on eout:%p, zone_id:%d. VIDEO STATE.",
+          ec, ec->hwc_window, output, zone->id);
+        return;
+     }
+
    hwc_window = e_hwc_window_new(output->hwc, ec, E_HWC_WINDOW_STATE_NONE);
    EINA_SAFETY_ON_NULL_RETURN(hwc_window);
 
-   /* set the hwc window to the e client */
-   ec->hwc_window = hwc_window;
-
    return;
 }
 
@@ -304,11 +315,11 @@ _e_hwc_window_client_cb_del(void *data EINA_UNUSED, E_Client *ec)
      return;
 
    if (!ec->hwc_window) return;
+   if (e_hwc_window_is_video(ec->hwc_window)) return;
 
    _e_hwc_window_constraints_reset(ec->hwc_window);
 
    e_hwc_window_free(ec->hwc_window);
-   ec->hwc_window = NULL;
 }
 
 static Eina_Bool
@@ -345,15 +356,11 @@ _e_hwc_window_client_cb_zone_set(void *data, int type, void *event)
         if (ec->hwc_window->hwc == output->hwc) goto end;
 
         e_hwc_window_free(ec->hwc_window);
-        ec->hwc_window = NULL;
      }
 
    hwc_window = e_hwc_window_new(output->hwc, ec, E_HWC_WINDOW_STATE_NONE);
    EINA_SAFETY_ON_NULL_GOTO(hwc_window, end);
 
-   /* set the hwc window to the e client */
-   ec->hwc_window = hwc_window;
-
    EHWINF("set on eout:%p, zone_id:%d.",
           ec, hwc_window, output, zone->id);
 
@@ -484,6 +491,7 @@ static void
 _e_hwc_window_free(E_Hwc_Window *hwc_window)
 {
    E_Hwc *hwc = NULL;
+   Hwc_Window_Prop *prop;
    E_Output *output = NULL;
    tdm_output *toutput = NULL;
 
@@ -498,6 +506,14 @@ _e_hwc_window_free(E_Hwc_Window *hwc_window)
    toutput = output->toutput;
    EINA_SAFETY_ON_NULL_GOTO(toutput, done);
 
+   if(hwc_window->prop_list)
+     {
+        EINA_LIST_FREE(hwc_window->prop_list, prop)
+          {
+             free(prop);
+          }
+     }
+
    if (hwc_window->thwc_window)
      tdm_hwc_window_destroy(hwc_window->thwc_window);
 
@@ -549,10 +565,15 @@ e_hwc_window_deinit(E_Hwc *hwc)
 EINTERN void
 e_hwc_window_free(E_Hwc_Window *hwc_window)
 {
+   E_Client *ec = NULL;
+
    EINA_SAFETY_ON_NULL_RETURN(hwc_window);
 
    EHWINF("Del", hwc_window->ec, hwc_window);
 
+   ec = hwc_window->ec;
+
+   ec->hwc_window = NULL;
    hwc_window->ec = NULL;
    hwc_window->is_deleted = EINA_TRUE;
 
@@ -604,10 +625,15 @@ e_hwc_window_new(E_Hwc *hwc, E_Client *ec, E_Hwc_Window_State state)
    if (state == E_HWC_WINDOW_STATE_VIDEO)
      hwc_window->is_video = EINA_TRUE;
 
+   /* set the hwc window to the e client */
+   ec->hwc_window = hwc_window;
+
    hwc->hwc_windows = eina_list_append(hwc->hwc_windows, hwc_window);
 
-   EHWINF("is created on eout:%p, zone_id:%d",
-          hwc_window->ec, hwc_window, hwc->output, ec->zone->id);
+   EHWINF("is created on eout:%p, zone_id:%d video:%d cursor:%d",
+          hwc_window->ec, hwc_window, hwc->output, ec->zone->id,
+          hwc_window->is_video, hwc_window->is_cursor);
+
    return hwc_window;
 }
 
@@ -691,6 +717,7 @@ e_hwc_window_info_update(E_Hwc_Window *hwc_window)
    tbm_surface_h tsurface = NULL;
    tbm_surface_info_s surf_info = {0};
    tdm_hwc_window_info hwc_win_info = {0};
+   E_Client_Video_Info vinfo;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
 
@@ -755,11 +782,15 @@ e_hwc_window_info_update(E_Hwc_Window *hwc_window)
      }
    else if (e_hwc_window_is_video(hwc_window))
      {
-        if (!e_comp_wl_video_hwc_window_info_get(hwc_window, &hwc_win_info))
+        if (!e_client_video_info_get(ec, &vinfo))
           {
-             ERR("Video window does not get the hwc_win_info.");
+             ERR("Video window does not get the video info.");
              return EINA_FALSE;
           }
+
+        memcpy(&hwc_win_info.src_config, &vinfo.src_config, sizeof(tdm_info_config));
+        memcpy(&hwc_win_info.dst_pos, &vinfo.dst_pos, sizeof(tdm_pos));
+        hwc_win_info.transform = vinfo.transform;
      }
    else if (tsurface)
      {
@@ -858,7 +889,8 @@ e_hwc_window_buffer_fetch(E_Hwc_Window *hwc_window)
    /* for video we set buffer in the video module */
    else if (e_hwc_window_is_video(hwc_window))
      {
-        tsurface = e_comp_wl_video_hwc_widow_surface_get(hwc_window);
+        tsurface = e_client_video_tbm_surface_get(hwc_window->ec);
+
         if (tsurface == hwc_window->buffer.tsurface) return EINA_FALSE;
      }
    else
@@ -917,6 +949,25 @@ e_hwc_window_buffer_fetch(E_Hwc_Window *hwc_window)
 }
 
 EINTERN Eina_Bool
+e_hwc_window_prop_update(E_Hwc_Window *hwc_window)
+{
+   Hwc_Window_Prop *prop;
+   Eina_Bool ret = EINA_FALSE;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
+
+   EINA_LIST_FREE(hwc_window->prop_list, prop)
+     {
+        if (!e_hwc_window_set_property(hwc_window, prop->id, prop->name, prop->value, EINA_TRUE))
+          ERR("HWC-WIN: cannot update prop E_Hwc_Window(%p)", hwc_window);
+        free(prop);
+        ret = EINA_TRUE;
+     }
+
+   return ret;
+}
+
+EINTERN Eina_Bool
 e_hwc_window_commit_data_acquire(E_Hwc_Window *hwc_window)
 {
    E_Hwc_Window_Commit_Data *commit_data = NULL;
@@ -1547,6 +1598,64 @@ e_hwc_window_name_get(E_Hwc_Window *hwc_window)
    return name;
 }
 
+EINTERN Eina_Bool
+e_hwc_window_set_property(E_Hwc_Window *hwc_window, unsigned int id, const char *name, tdm_value value, Eina_Bool force)
+{
+   E_Client *ec = NULL;
+   const Eina_List *l = NULL;
+   Hwc_Window_Prop *prop = NULL;
+   tdm_error ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
+
+   ec = hwc_window->ec;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+   if (force)
+     {
+        /* set the property on the fly */
+        ret = tdm_hwc_window_set_property(hwc_window, id, value);
+        EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
+
+        EHWTRACE("Set Property: property(%s) value(%d)) -- {%s}",
+                  hwc_window->ec, hwc_window,
+                  prop->name, (unsigned int)value.u32,
+                  e_hwc_window_name_get(hwc_window));
+     }
+   else
+     {
+        /* change the vaule of the property if prop_list already has the property */
+        EINA_LIST_FOREACH(hwc_window->prop_list, l, prop)
+          {
+             if (!strncmp(name, prop->name, TDM_NAME_LEN))
+               {
+                 EHWTRACE("Change Property: property(%s) update value(%d -> %d) -- {%s}",
+                           hwc_window->ec, hwc_window,
+                           prop->name, (unsigned int)prop->value.u32, (unsigned int)value.u32,
+                           e_hwc_window_name_get(hwc_window));
+                  prop->value.u32 = value.u32;
+                  return EINA_TRUE;
+               }
+          }
+
+        /* store the properties and commit at the hwc_commit time */
+        prop = calloc(1, sizeof(Hwc_Window_Prop));
+        EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
+        prop->value.u32 = value.u32;
+        prop->id = id;
+        memcpy(prop->name, name, sizeof(TDM_NAME_LEN));
+        hwc_window->prop_list = eina_list_append(hwc_window->prop_list, prop);
+
+        EHWTRACE("Set Property: property(%s) value(%d)) -- {%s}",
+                  hwc_window->ec, hwc_window,
+                  prop->name, (unsigned int)value.u32,
+                  e_hwc_window_name_get(hwc_window));
+     }
+
+   return EINA_TRUE;
+}
+
+
 EINTERN E_Hwc_Window_Hook *
 e_hwc_window_hook_add(E_Hwc_Window_Hook_Point hookpoint, E_Hwc_Window_Hook_Cb func, const void *data)
 {
index 0751bdd..8a4a595 100644 (file)
@@ -91,7 +91,9 @@ struct _E_Hwc_Window
    E_Hwc_Window_Buffer            buffer;
 
    tdm_hwc_window_info            info;
+   Eina_List                     *prop_list;
    E_Hwc_Window_Commit_Data      *commit_data;
+
    /* current display information */
    struct
    {
@@ -152,6 +154,7 @@ EINTERN int                e_hwc_window_zpos_get(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool          e_hwc_window_composition_update(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool          e_hwc_window_info_update(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool          e_hwc_window_buffer_fetch(E_Hwc_Window *hwc_window);
+EINTERN Eina_Bool          e_hwc_window_prop_update(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool          e_hwc_window_is_target(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool          e_hwc_window_is_video(E_Hwc_Window *hwc_window);
 EINTERN Eina_Bool          e_hwc_window_is_cursor(E_Hwc_Window *hwc_window);
@@ -175,6 +178,7 @@ EINTERN Eina_Bool          e_hwc_window_rendered_window_update(E_Hwc_Window *hwc
 EINTERN void               e_hwc_window_buffer_set(E_Hwc_Window *hwc_window, tbm_surface_h tsurface, E_Hwc_Window_Queue *queue);
 EINTERN const char        *e_hwc_window_state_string_get(E_Hwc_Window_State hwc_window_state);
 EINTERN const char        *e_hwc_window_name_get(E_Hwc_Window *hwc_window);
+EINTERN Eina_Bool          e_hwc_window_set_property(E_Hwc_Window *hwc_window, unsigned int id, const char *name, tdm_value value, Eina_Bool force);
 
 EINTERN E_Hwc_Window_Hook *e_hwc_window_hook_add(E_Hwc_Window_Hook_Point hookpoint, E_Hwc_Window_Hook_Cb func, const void *data);
 EINTERN void               e_hwc_window_hook_del(E_Hwc_Window_Hook *ch);
index 4873c89..b4bf926 100644 (file)
@@ -150,7 +150,7 @@ _e_hwc_windows_commit_data_release(E_Hwc *hwc, int sequence,
      {
          if (!hwc_window->commit_data) continue;
          if (e_hwc_window_is_video(hwc_window))
-           e_comp_wl_video_hwc_window_commit_data_release(hwc_window, sequence, tv_sec, tv_usec);
+           e_client_video_commit_data_release(hwc_window->ec, sequence, tv_sec, tv_usec);
 
          if (!e_hwc_window_commit_data_release(hwc_window)) continue;
      }
@@ -1502,7 +1502,7 @@ _e_hwc_windows_visible_windows_list_get(E_Hwc *hwc)
 
         if (e_hwc_window_is_video(hwc_window))
           {
-            if (!e_comp_wl_video_hwc_widow_surface_get(hwc_window))
+            if (!e_client_video_tbm_surface_get(ec))
               continue;
 
             e_hwc_window_state_set(hwc_window, E_HWC_WINDOW_STATE_VIDEO, EINA_TRUE);
@@ -1719,6 +1719,10 @@ _e_hwc_windows_changes_update(E_Hwc *hwc)
         /* update the window's info */
         if (e_hwc_window_info_update(hwc_window))
           update_changes = EINA_TRUE;
+
+        /* update the window's props */
+        if (e_hwc_window_prop_update(hwc_window))
+          update_changes = EINA_TRUE;
      }
 
    /* update the states of the visible windows when there is something to update */
@@ -1803,6 +1807,8 @@ _e_hwc_windows_evaluate(E_Hwc *hwc)
         _e_hwc_windows_target_state_set(hwc->target_hwc_window, E_HWC_WINDOW_STATE_NONE);
      }
 
+   if (hwc_mode != E_HWC_MODE_FULL && num_video > 0)
+
    /* skip the target_buffer when the window is on trainsition of the composition */
    if (hwc_mode != E_HWC_MODE_FULL && _e_hwc_windows_transition_check(hwc))
      {
@@ -1841,9 +1847,12 @@ _e_hwc_windows_target_buffer_prepared(E_Hwc *hwc)
 EINTERN Eina_Bool
 e_hwc_windows_init(E_Hwc *hwc)
 {
+   tdm_error error;
+   tdm_hwc_capability hwc_caps = 0;
    E_Hwc_Window_Target *target_hwc_window;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc->thwc, EINA_FALSE);
 
    if (e_hwc_policy_get(hwc) == E_HWC_POLICY_PLANES)
      return EINA_FALSE;
@@ -1852,6 +1861,23 @@ e_hwc_windows_init(E_Hwc *hwc)
    EINA_SAFETY_ON_NULL_RETURN_VAL(target_hwc_window, EINA_FALSE);
    target_hwc_window->hwc = hwc;
 
+   error = tdm_hwc_get_capabilities(hwc->thwc, &hwc_caps);
+   if (error != TDM_ERROR_NONE)
+     {
+        ERR("fail to tdm_hwc_get_capabilities");
+        return EINA_FALSE;
+     }
+
+   /* hwc video capabilities */
+   if (hwc_caps & TDM_HWC_CAPABILITY_VIDEO_STREAM)
+     hwc->tdm_hwc_video_stream = EINA_TRUE;
+   if (hwc_caps & TDM_HWC_CAPABILITY_VIDEO_SCALE)
+     hwc->tdm_hwc_video_scale = EINA_TRUE;
+   if (hwc_caps & TDM_HWC_CAPABILITY_VIDEO_TRANSFORM)
+     hwc->tdm_hwc_video_transform = EINA_TRUE;
+   if (hwc_caps & TDM_HWC_CAPABILITY_VIDEO_SCANOUT)
+     hwc->tdm_hwc_video_scanout = EINA_TRUE;
+
    /* set the target_window to the hwc */
    hwc->target_hwc_window = target_hwc_window;
 
@@ -2151,3 +2177,41 @@ e_hwc_windows_fps_get(E_Hwc *hwc, double *fps)
 
    return EINA_FALSE;
 }
+
+EINTERN Eina_Bool
+e_hwc_windows_get_available_properties(E_Hwc *hwc, const tdm_prop **props, int *count)
+{
+   tdm_hwc *thwc;
+   tdm_error ret = TDM_ERROR_OPERATION_FAILED;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(props, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+
+   thwc = hwc->thwc;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(thwc, EINA_FALSE);
+
+   ret = tdm_hwc_get_available_properties(thwc, props, count);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
+
+   return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_hwc_windows_get_video_available_properties(E_Hwc *hwc, const tdm_prop **props, int *count)
+{
+   tdm_hwc *thwc;
+   tdm_error ret = TDM_ERROR_OPERATION_FAILED;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(props, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
+
+   thwc = hwc->thwc;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(thwc, EINA_FALSE);
+
+   ret = tdm_hwc_get_video_available_properties(thwc, props, count);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(ret != TDM_ERROR_NONE, ret);
+
+   return EINA_TRUE;
+}
index 6c18fc2..c7fae22 100644 (file)
@@ -8,6 +8,9 @@ EINTERN void                 e_hwc_windows_deinit(E_Hwc *hwc);
 EINTERN Eina_Bool            e_hwc_windows_render(E_Hwc *hwc);
 EINTERN Eina_Bool            e_hwc_windows_commit(E_Hwc *hwc);
 EINTERN void                 e_hwc_windows_rendered_window_add(E_Hwc_Window *hwc_window);
+EINTERN Eina_Bool            e_hwc_windows_get_available_properties(E_Hwc *hwc, const tdm_prop **props, int *count);
+EINTERN Eina_Bool            e_hwc_windows_get_video_available_properties(E_Hwc *hwc, const tdm_prop **props, int *count);
+
 EINTERN Eina_Bool            e_hwc_windows_pp_commit_possible_check(E_Hwc *hwc);
 EINTERN Eina_Bool            e_hwc_windows_zoom_set(E_Hwc *hwc, Eina_Rectangle *rect);
 EINTERN void                 e_hwc_windows_zoom_unset(E_Hwc *hwc);
index 04f1586..9c9301f 100644 (file)
@@ -65,13 +65,14 @@ _e_client_video_comp_iface_init(E_Client_Video *ecv, E_Client *ec)
    hwc_pol = e_hwc_policy_get(eout->hwc);
    if (hwc_pol == E_HWC_POLICY_WINDOWS)
      {
-        /* TODO */
-        INF("Try to initialize the interface for HWC WINDOWS mode");
-        WRN("* Not Implemented *");
-        iface = NULL;
+        INF("Initialize the interface of the client_video for HWC WINDOWS mode");
+        iface = e_video_hwc_windows_iface_create(ec);;
      }
    else if (hwc_pol == E_HWC_POLICY_PLANES)
-     iface = e_video_hwc_planes_iface_create(ec);
+     {
+        INF("Initialize the interface of the client_video for HWC PLANES mode");
+        iface = e_video_hwc_planes_iface_create(ec);
+     }
 
 end:
    if (!iface)
index 0b41653..29ab0d4 100644 (file)
@@ -128,66 +128,6 @@ _e_video_is_visible(E_Video *video)
    return EINA_TRUE;
 }
 
-EINTERN void
-e_comp_wl_video_hwc_window_commit_data_release(E_Hwc_Window *hwc_window, unsigned int sequence,
-                            unsigned int tv_sec, unsigned int tv_usec)
-{
-   E_Client *ec = NULL;
-
-   EINA_SAFETY_ON_NULL_RETURN(hwc_window);
-
-   ec = hwc_window->ec;
-   EINA_SAFETY_ON_NULL_RETURN(ec);
-
-   e_client_video_commit_data_release(ec, sequence, tv_sec, tv_usec);
-}
-
-EINTERN tbm_surface_h
-e_comp_wl_video_hwc_widow_surface_get(E_Hwc_Window *hwc_window)
-{
-   E_Client *ec = NULL;
-
-   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, NULL);
-
-   if (!e_hwc_window_is_video(hwc_window))
-     {
-       ERR("ehw:%p is NOT Video HWC window.", hwc_window);
-       return NULL;
-     }
-
-   ec = hwc_window->ec;
-   if (!ec) return NULL;
-
-   return e_client_video_tbm_surface_get(ec);
-}
-
-EINTERN Eina_Bool
-e_comp_wl_video_hwc_window_info_get(E_Hwc_Window *hwc_window, tdm_hwc_window_info *hwc_win_info)
-{
-   E_Client *ec = NULL;
-   E_Client_Video_Info vinfo;
-
-   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
-
-   if (!e_hwc_window_is_video(hwc_window))
-     {
-       ERR("ehw:%p is NOT Video HWC window.", hwc_window);
-       return EINA_FALSE;
-     }
-
-   ec = hwc_window->ec;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
-
-   if (!e_client_video_info_get(ec, &vinfo))
-     return EINA_FALSE;
-
-   memcpy(&hwc_win_info->src_config, &vinfo.src_config, sizeof(tdm_info_config));
-   memcpy(&hwc_win_info->dst_pos, &vinfo.dst_pos, sizeof(tdm_pos));
-   hwc_win_info->transform = vinfo.transform;
-
-   return EINA_TRUE;
-}
-
 static E_Video *
 _e_video_create(struct wl_resource *video_object, struct wl_resource *surface)
 {
index fc9bac3..ce93c4f 100644 (file)
@@ -9,10 +9,6 @@
 EINTERN int e_comp_wl_video_init(void);
 EINTERN void e_comp_wl_video_shutdown(void);
 
-EINTERN void          e_comp_wl_video_hwc_window_commit_data_release(E_Hwc_Window *hwc_window, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec);
-EINTERN tbm_surface_h e_comp_wl_video_hwc_widow_surface_get(E_Hwc_Window *hwc_window);
-EINTERN Eina_Bool     e_comp_wl_video_hwc_window_info_get(E_Hwc_Window *hwc_window, tdm_hwc_window_info *hwc_win_info);
-
 #define C(b,m)              (((b) >> (m)) & 0xFF)
 #define FOURCC_STR(id)      C(id,0), C(id,8), C(id,16), C(id,24)
 #define IS_RGB(f)           ((f) == TBM_FORMAT_XRGB8888 || (f) == TBM_FORMAT_ARGB8888)
index c5097c2..3ae3195 100644 (file)
@@ -9,38 +9,6 @@
 #include <tbm_surface.h>
 #include <wayland-tbm-server.h>
 
-#ifdef VER
-# undef VER
-#endif
-
-#ifdef VWR
-# undef VWR
-#endif
-
-#ifdef VIN
-# undef VIN
-#endif
-
-#ifdef VDB
-# undef VDB
-#endif
-
-#ifdef DET
-# undef DET
-#endif
-
-#ifdef VDT
-# undef VDT
-#endif
-
-#define VER(fmt, arg...)   ELOGF("VIDEO", "<ERR> window(0x%08"PRIxPTR"): "fmt, \
-                                 evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
-#define VWR(fmt, arg...)   ELOGF("VIDEO", "<WRN> window(0x%08"PRIxPTR"): "fmt, \
-                                 evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
-#define VIN(fmt, arg...)   ELOGF("VIDEO", "<INF> window(0x%08"PRIxPTR"): "fmt, \
-                                 evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
-#define VDB(fmt, arg...)   DBG("window(0x%08"PRIxPTR") ec(%p): "fmt, evhp->window, evhp->ec, ##arg)
-
 #define GEO_FMT   "%dx%d(%dx%d+%d+%d) -> (%dx%d+%d+%d) transform(%d)"
 #define GEO_ARG(g) \
    (g)->input_w, (g)->input_h, \
@@ -68,6 +36,7 @@ struct _E_Video_Comp_Iface
 };
 
 EINTERN E_Video_Comp_Iface  *e_video_hwc_planes_iface_create(E_Client *ec);
+EINTERN E_Video_Comp_Iface  *e_video_hwc_windows_iface_create(E_Client *ec);
 EINTERN E_Video_Comp_Iface  *e_video_fallback_iface_create(E_Client *ec);
 
 #endif
index 0a21e15..d714173 100644 (file)
@@ -4,6 +4,14 @@
 
 #include "../e_video_internal.h"
 
+#define VER(fmt, arg...)   ELOGF("VIDEO", "<ERR> window(0x%08"PRIxPTR"): "fmt, \
+                                 evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
+#define VWR(fmt, arg...)   ELOGF("VIDEO", "<WRN> window(0x%08"PRIxPTR"): "fmt, \
+                                 evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
+#define VIN(fmt, arg...)   ELOGF("VIDEO", "<INF> window(0x%08"PRIxPTR"): "fmt, \
+                                 evhp->ec->pixmap, evhp->ec, evhp->window, ##arg)
+#define VDB(fmt, arg...)   DBG("window(0x%08"PRIxPTR") ec(%p): "fmt, evhp->window, evhp->ec, ##arg)
+
 //#define DUMP_BUFFER
 #define CHECKING_PRIMARY_ZPOS
 
diff --git a/src/bin/video/iface/e_video_hwc_windows.c b/src/bin/video/iface/e_video_hwc_windows.c
new file mode 100644 (file)
index 0000000..94084d8
--- /dev/null
@@ -0,0 +1,1996 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "../e_video_internal.h"
+
+#define VER(fmt, arg...)   ELOGF("VIDEO", "<ERR> window(0x%08"PRIxPTR"): "fmt, \
+                                 evhw->ec->pixmap, evhw->ec, evhw->window, ##arg)
+#define VWR(fmt, arg...)   ELOGF("VIDEO", "<WRN> window(0x%08"PRIxPTR"): "fmt, \
+                                 evhw->ec->pixmap, evhw->ec, evhw->window, ##arg)
+#define VIN(fmt, arg...)   ELOGF("VIDEO", "<INF> window(0x%08"PRIxPTR"): "fmt, \
+                                 evhw->ec->pixmap, evhw->ec, evhw->window, ##arg)
+#define VDB(fmt, arg...)   DBG("window(0x%08"PRIxPTR") ec(%p): "fmt, evhw->window, evhw->ec, ##arg)
+
+//#define DUMP_BUFFER
+#define CHECKING_PRIMARY_ZPOS
+
+#define BUFFER_MAX_COUNT   5
+#define MIN_WIDTH   32
+
+#undef NEVER_GET_HERE
+#define NEVER_GET_HERE()     CRI("** need to improve more **")
+
+#ifndef CLEAR
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+#endif
+
+#define IFACE_ENTRY                                      \
+   E_Video_Hwc_Windows *evhw;                              \
+   evhw = container_of(iface, E_Video_Hwc_Windows, base)
+
+typedef struct _E_Video_Hwc_Windows E_Video_Hwc_Windows;
+
+struct _E_Video_Hwc_Windows
+{
+   E_Video_Comp_Iface base;
+
+   E_Client *ec;
+   Ecore_Window window;
+   tdm_output *output;
+   E_Output *e_output;
+   E_Hwc_Window *hwc_window;
+   E_Hwc *hwc;
+   E_Client_Video_Info info;
+   tbm_surface_h cur_tsurface; // tsurface to be set this layer.
+   E_Client *e_client;
+   Eina_List *ec_event_handler;
+
+   /* input info */
+   tbm_format tbmfmt;
+   Eina_List *input_buffer_list;
+
+   /* in screen coordinates */
+   struct
+     {
+        int input_w, input_h;    /* input buffer's size */
+        Eina_Rectangle input_r;  /* input buffer's content rect */
+        Eina_Rectangle output_r; /* video plane rect */
+        uint transform;          /* rotate, flip */
+
+        Eina_Rectangle tdm_output_r; /* video plane rect in physical output coordinates */
+        uint tdm_transform;          /* rotate, flip in physical output coordinates */
+     } geo, old_geo;
+
+   E_Comp_Wl_Buffer *old_comp_buffer;
+
+   /* converter info */
+   tbm_format pp_tbmfmt;
+   tdm_pp *pp;
+   Eina_Rectangle pp_r;    /* converter dst content rect */
+   Eina_List *pp_buffer_list;
+   Eina_List *next_buffer;
+   Eina_Bool pp_scanout;
+
+   int pp_align;
+   int pp_minw, pp_minh, pp_maxw, pp_maxh;
+   int video_align;
+
+   /* When a video buffer be attached, it will be appended to the end of waiting_list .
+    * And when it's committed, it will be moved to committed_list.
+    * Finally when the commit handler is called, it will become current_fb.
+    */
+   Eina_List    *waiting_list;   /* buffers which are not committed yet */
+   Eina_List    *committed_list; /* buffers which are committed, but not shown on screen yet */
+   E_Comp_Wl_Video_Buf *current_fb;     /* buffer which is showing on screen currently */
+   Eina_Bool     waiting_vblank;
+
+   /* attributes */
+   int tdm_mute_id;
+
+   Eina_Bool  cb_registered;
+   Eina_Bool  need_force_render;
+   Eina_Bool  follow_topmost_visibility;
+   Eina_Bool  allowed_attribute;
+};
+
+static Eina_List *video_list = NULL;
+
+static void      _e_video_destroy(E_Video_Hwc_Windows *evhw);
+static void      _e_video_render(E_Video_Hwc_Windows *evhw, const char *func);
+static Eina_Bool _e_video_frame_buffer_show(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Video_Buf *vbuf);
+static void      _e_video_vblank_handler(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+
+static void
+buffer_transform(int width, int height, uint32_t transform, int32_t scale,
+                 int sx, int sy, int *dx, int *dy)
+{
+   switch (transform)
+     {
+      case WL_OUTPUT_TRANSFORM_NORMAL:
+      default:
+         *dx = sx, *dy = sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED:
+         *dx = width - sx, *dy = sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_90:
+         *dx = height - sy, *dy = sx;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+         *dx = height - sy, *dy = width - sx;
+         break;
+      case WL_OUTPUT_TRANSFORM_180:
+         *dx = width - sx, *dy = height - sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+         *dx = sx, *dy = height - sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_270:
+         *dx = sy, *dy = width - sx;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         *dx = sy, *dy = sx;
+         break;
+     }
+
+   *dx *= scale;
+   *dy *= scale;
+}
+
+static E_Client *
+find_video_child_get(E_Client *ec)
+{
+   E_Client *subc = NULL;
+   Eina_List *l;
+   if (!ec) return NULL;
+   if (e_object_is_del(E_OBJECT(ec))) return NULL;
+   if (!ec->comp_data) return NULL;
+
+   if (ec->comp_data->video_client) return ec;
+
+   EINA_LIST_FOREACH(ec->comp_data->sub.below_list, l, subc)
+     {
+        E_Client *temp= NULL;
+        if (!subc->comp_data || e_object_is_del(E_OBJECT(subc))) continue;
+        temp = find_video_child_get(subc);
+        if(temp) return temp;
+     }
+
+   return NULL;
+}
+
+static E_Client *
+find_offscreen_parent_get(E_Client *ec)
+{
+   E_Client *parent = NULL;
+
+   if (!ec->comp_data || !ec->comp_data->sub.data)
+     return NULL;
+
+   parent = ec->comp_data->sub.data->parent;
+   while (parent)
+     {
+        if (!parent->comp_data || !parent->comp_data->sub.data)
+          return NULL;
+
+        if (parent->comp_data->sub.data->remote_surface.offscreen_parent)
+          return parent->comp_data->sub.data->remote_surface.offscreen_parent;
+
+        parent = parent->comp_data->sub.data->parent;
+     }
+
+   return NULL;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_vbuf_find(Eina_List *list, tbm_surface_h buffer)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+   Eina_List *l = NULL;
+
+   EINA_LIST_FOREACH(list, l, vbuf)
+     {
+        if (vbuf->tbm_surface == buffer)
+          return vbuf;
+     }
+
+   return NULL;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_vbuf_find_with_comp_buffer(Eina_List *list, E_Comp_Wl_Buffer *comp_buffer)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+   Eina_List *l = NULL;
+
+   EINA_LIST_FOREACH(list, l, vbuf)
+     {
+        if (vbuf->comp_buffer == comp_buffer)
+          return vbuf;
+     }
+
+   return NULL;
+}
+
+static Eina_Bool
+_e_video_is_visible(E_Video_Hwc_Windows *evhw)
+{
+   E_Client *offscreen_parent;
+
+   if (e_object_is_del(E_OBJECT(evhw->ec))) return EINA_FALSE;
+
+   if (!e_pixmap_resource_get(evhw->ec->pixmap))
+     {
+        VDB("no comp buffer");
+        return EINA_FALSE;
+     }
+
+   if (evhw->ec->comp_data->sub.data && evhw->ec->comp_data->sub.data->stand_alone)
+     return EINA_TRUE;
+
+   offscreen_parent = find_offscreen_parent_get(evhw->ec);
+   if (offscreen_parent && offscreen_parent->visibility.obscured == E_VISIBILITY_FULLY_OBSCURED)
+     {
+        VDB("video surface invisible: offscreen fully obscured");
+        return EINA_FALSE;
+     }
+
+   if (!evas_object_visible_get(evhw->ec->frame))
+     {
+        VDB("evas obj invisible");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_parent_is_viewable(E_Video_Hwc_Windows *evhw)
+{
+   E_Client *topmost_parent;
+
+   if (e_object_is_del(E_OBJECT(evhw->ec))) return EINA_FALSE;
+
+   topmost_parent = e_comp_wl_topmost_parent_get(evhw->ec);
+
+   if (!topmost_parent)
+     return EINA_FALSE;
+
+   if (topmost_parent == evhw->ec)
+     {
+        VDB("There is no video parent surface");
+        return EINA_FALSE;
+     }
+
+   if (!topmost_parent->visible)
+     {
+        VDB("parent(0x%08"PRIxPTR") not viewable", (Ecore_Window)e_client_util_win_get(topmost_parent));
+        return EINA_FALSE;
+     }
+
+   if (!e_pixmap_resource_get(topmost_parent->pixmap))
+     {
+        VDB("parent(0x%08"PRIxPTR") no comp buffer", (Ecore_Window)e_client_util_win_get(topmost_parent));
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_e_video_input_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
+{
+   E_Video_Hwc_Windows *evhw = data;
+   Eina_Bool need_hide = EINA_FALSE;
+
+   DBG("Buffer(%p) to be free, refcnt(%d)", vbuf, vbuf->ref_cnt);
+
+   evhw->input_buffer_list = eina_list_remove(evhw->input_buffer_list, vbuf);
+
+   if (vbuf->comp_buffer)
+     e_comp_wl_buffer_reference(&vbuf->buffer_ref, NULL);
+
+   if (evhw->current_fb == vbuf)
+     {
+        VIN("current fb destroyed");
+        e_comp_wl_video_buffer_set_use(evhw->current_fb, EINA_FALSE);
+        evhw->current_fb = NULL;
+        need_hide = EINA_TRUE;
+     }
+
+   if (eina_list_data_find(evhw->committed_list, vbuf))
+     {
+        VIN("committed fb destroyed");
+        evhw->committed_list = eina_list_remove(evhw->committed_list, vbuf);
+        e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+        need_hide = EINA_TRUE;
+     }
+
+   if (eina_list_data_find(evhw->waiting_list, vbuf))
+     {
+        VIN("waiting fb destroyed");
+        evhw->waiting_list = eina_list_remove(evhw->waiting_list, vbuf);
+     }
+
+   if (need_hide)
+     _e_video_frame_buffer_show(evhw, NULL);
+}
+
+static Eina_Bool
+_e_video_input_buffer_scanout_check(E_Comp_Wl_Video_Buf *vbuf)
+{
+   tbm_surface_h tbm_surface = NULL;
+   tbm_bo bo = NULL;
+   int flag;
+
+   tbm_surface = vbuf->tbm_surface;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, EINA_FALSE);
+
+   bo = tbm_surface_internal_get_bo(tbm_surface, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(bo, EINA_FALSE);
+
+   flag = tbm_bo_get_flags(bo);
+   if (flag == TBM_BO_SCANOUT)
+      return EINA_TRUE;
+
+   return EINA_FALSE;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_input_buffer_copy(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Buffer *comp_buf, E_Comp_Wl_Video_Buf *vbuf, Eina_Bool scanout)
+{
+   E_Comp_Wl_Video_Buf *temp = NULL;
+   int aligned_width = ROUNDUP(vbuf->width_from_pitch, evhw->pp_align);
+
+   temp = e_comp_wl_video_buffer_alloc(aligned_width, vbuf->height, vbuf->tbmfmt, scanout);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(temp, NULL);
+
+   temp->comp_buffer = comp_buf;
+
+   VDB("copy vbuf(%d,%dx%d) => vbuf(%d,%dx%d)",
+       MSTAMP(vbuf), vbuf->width_from_pitch, vbuf->height,
+       MSTAMP(temp), temp->width_from_pitch, temp->height);
+
+   e_comp_wl_video_buffer_copy(vbuf, temp);
+   e_comp_wl_video_buffer_unref(vbuf);
+
+   evhw->geo.input_w = vbuf->width_from_pitch;
+#ifdef DUMP_BUFFER
+   char file[256];
+   static int i;
+   snprintf(file, sizeof file, "/tmp/dump/%s_%d.png", "cpy", i++);
+   tdm_helper_dump_buffer(temp->tbm_surface, file);
+#endif
+
+   return temp;
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_input_buffer_get(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Buffer *comp_buffer, Eina_Bool scanout)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+   Eina_Bool need_pp_scanout = EINA_FALSE;
+
+   vbuf = _e_video_vbuf_find_with_comp_buffer(evhw->input_buffer_list, comp_buffer);
+   if (vbuf)
+     {
+        vbuf->content_r = evhw->geo.input_r;
+        return vbuf;
+     }
+
+   vbuf = e_comp_wl_video_buffer_create_comp(comp_buffer);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+   if (evhw->pp_scanout)
+     {
+        Eina_Bool input_buffer_scanout = EINA_FALSE;
+        input_buffer_scanout = _e_video_input_buffer_scanout_check(vbuf);
+        if (!input_buffer_scanout) need_pp_scanout = EINA_TRUE;
+     }
+
+   if (evhw->pp)
+     {
+        if ((evhw->pp_align != -1 && (vbuf->width_from_pitch % evhw->pp_align)) ||
+            need_pp_scanout)
+          {
+             E_Comp_Wl_Video_Buf *temp;
+
+             if (need_pp_scanout)
+               temp = _e_video_input_buffer_copy(evhw, comp_buffer, vbuf, EINA_TRUE);
+             else
+               temp = _e_video_input_buffer_copy(evhw, comp_buffer, vbuf, scanout);
+             if (!temp)
+               {
+                  e_comp_wl_video_buffer_unref(vbuf);
+                  return NULL;
+               }
+             vbuf = temp;
+          }
+     }
+
+   vbuf->content_r = evhw->geo.input_r;
+
+   evhw->input_buffer_list = eina_list_append(evhw->input_buffer_list, vbuf);
+   e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_input_buffer_cb_free, evhw);
+
+   DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p) created, refcnt:%d"
+       " scanout=%d", e_client_util_name_get(evhw->ec) ?: "No Name" ,
+       evhw->ec->netwm.pid, wl_resource_get_id(evhw->ec->comp_data->surface), vbuf,
+       vbuf->ref_cnt, scanout);
+
+   return vbuf;
+}
+
+static void
+_e_video_input_buffer_valid(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Buffer *comp_buffer)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(evhw->input_buffer_list, l, vbuf)
+     {
+        tbm_surface_h tbm_surf;
+        tbm_bo bo;
+        uint32_t size = 0, offset = 0, pitch = 0;
+
+        if (!vbuf->comp_buffer) continue;
+        if (vbuf->resource == comp_buffer->resource)
+          {
+             WRN("got wl_buffer@%d twice", wl_resource_get_id(comp_buffer->resource));
+             return;
+          }
+
+        tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
+        bo = tbm_surface_internal_get_bo(tbm_surf, 0);
+        tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
+
+        if (vbuf->names[0] == tbm_bo_export(bo) && vbuf->offsets[0] == offset)
+          {
+             WRN("can tearing: wl_buffer@%d, wl_buffer@%d are same. gem_name(%d)",
+                 wl_resource_get_id(vbuf->resource),
+                 wl_resource_get_id(comp_buffer->resource), vbuf->names[0]);
+             return;
+          }
+     }
+}
+
+static void
+_e_video_pp_buffer_cb_free(E_Comp_Wl_Video_Buf *vbuf, void *data)
+{
+   E_Video_Hwc_Windows *evhw = data;
+
+   e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+
+   if (evhw->current_fb == vbuf)
+     evhw->current_fb = NULL;
+
+   evhw->committed_list = eina_list_remove(evhw->committed_list, vbuf);
+
+   evhw->waiting_list = eina_list_remove(evhw->waiting_list, vbuf);
+
+   evhw->pp_buffer_list = eina_list_remove(evhw->pp_buffer_list, vbuf);
+}
+
+static E_Comp_Wl_Video_Buf *
+_e_video_pp_buffer_get(E_Video_Hwc_Windows *evhw, int width, int height)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+   Eina_List *l;
+   int i = 0;
+   int aligned_width;
+
+   if (evhw->video_align != -1)
+     aligned_width = ROUNDUP(width, evhw->video_align);
+   else
+     aligned_width = width;
+
+   if (evhw->pp_buffer_list)
+     {
+        vbuf = eina_list_data_get(evhw->pp_buffer_list);
+        EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+        /* if we need bigger pp_buffers, destroy all pp_buffers and create */
+        if (aligned_width > vbuf->width_from_pitch || height != vbuf->height)
+          {
+             Eina_List *ll;
+
+             VIN("pp buffer changed: %dx%d => %dx%d",
+                 vbuf->width_from_pitch, vbuf->height,
+                 aligned_width, height);
+
+             EINA_LIST_FOREACH_SAFE(evhw->pp_buffer_list, l, ll, vbuf)
+               {
+                  /* free forcely */
+                  e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+                  e_comp_wl_video_buffer_unref(vbuf);
+               }
+             if (evhw->pp_buffer_list)
+               NEVER_GET_HERE();
+
+             if (evhw->waiting_list)
+               NEVER_GET_HERE();
+          }
+     }
+
+   if (!evhw->pp_buffer_list)
+     {
+        for (i = 0; i < BUFFER_MAX_COUNT; i++)
+          {
+             vbuf = e_comp_wl_video_buffer_alloc(aligned_width, height, evhw->pp_tbmfmt, EINA_TRUE);
+             EINA_SAFETY_ON_NULL_RETURN_VAL(vbuf, NULL);
+
+             e_comp_wl_video_buffer_free_func_add(vbuf, _e_video_pp_buffer_cb_free, evhw);
+             evhw->pp_buffer_list = eina_list_append(evhw->pp_buffer_list, vbuf);
+
+          }
+
+        VIN("pp buffer created: %dx%d, %c%c%c%c",
+            vbuf->width_from_pitch, height, FOURCC_STR(evhw->pp_tbmfmt));
+
+        evhw->next_buffer = evhw->pp_buffer_list;
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evhw->pp_buffer_list, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evhw->next_buffer, NULL);
+
+   l = evhw->next_buffer;
+   while ((vbuf = evhw->next_buffer->data))
+     {
+        evhw->next_buffer = (evhw->next_buffer->next) ? evhw->next_buffer->next : evhw->pp_buffer_list;
+
+        if (!vbuf->in_use)
+          return vbuf;
+
+        if (l == evhw->next_buffer)
+          {
+             VWR("all video framebuffers in use (max:%d)", BUFFER_MAX_COUNT);
+             return NULL;
+          }
+     }
+
+   return NULL;
+}
+
+/* convert from logical screen to physical output */
+static void
+_e_video_geometry_cal_physical(E_Video_Hwc_Windows *evhw)
+{
+   E_Zone *zone;
+   E_Comp_Wl_Output *output;
+   E_Client *topmost;
+   int tran, flip;
+   int transform;
+
+   topmost = e_comp_wl_topmost_parent_get(evhw->ec);
+   EINA_SAFETY_ON_NULL_GOTO(topmost, normal);
+
+   output = e_comp_wl_output_find(topmost);
+   EINA_SAFETY_ON_NULL_GOTO(output, normal);
+
+   zone = e_comp_zone_xy_get(topmost->x, topmost->y);
+   EINA_SAFETY_ON_NULL_GOTO(zone, normal);
+
+   tran = evhw->geo.transform & 0x3;
+   flip = evhw->geo.transform & 0x4;
+   transform = flip + (tran + output->transform) % 4;
+   switch(transform)
+     {
+      case WL_OUTPUT_TRANSFORM_90:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_270;
+         break;
+      case WL_OUTPUT_TRANSFORM_180:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_180;
+         break;
+      case WL_OUTPUT_TRANSFORM_270:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_90;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_270;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_180;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_90;
+         break;
+      case WL_OUTPUT_TRANSFORM_NORMAL:
+      default:
+         evhw->geo.tdm_transform = TDM_TRANSFORM_NORMAL;
+         break;
+     }
+
+   if (output->transform % 2)
+     {
+        if (evhw->geo.tdm_transform == TDM_TRANSFORM_FLIPPED)
+          evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_180;
+        else if (evhw->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_90)
+          evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_270;
+        else if (evhw->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_180)
+          evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED;
+        else if (evhw->geo.tdm_transform == TDM_TRANSFORM_FLIPPED_270)
+          evhw->geo.tdm_transform = TDM_TRANSFORM_FLIPPED_90;
+     }
+
+   if (output->transform == 0)
+     evhw->geo.tdm_output_r = evhw->geo.output_r;
+   else
+     e_comp_wl_rect_convert(zone->w, zone->h, output->transform, 1,
+                            evhw->geo.output_r.x, evhw->geo.output_r.y,
+                            evhw->geo.output_r.w, evhw->geo.output_r.h,
+                            &evhw->geo.tdm_output_r.x, &evhw->geo.tdm_output_r.y,
+                            &evhw->geo.tdm_output_r.w, &evhw->geo.tdm_output_r.h);
+
+   VDB("geomtry: screen(%d,%d %dx%d | %d) => %d => physical(%d,%d %dx%d | %d)",
+       EINA_RECTANGLE_ARGS(&evhw->geo.output_r), evhw->geo.transform, transform,
+       EINA_RECTANGLE_ARGS(&evhw->geo.tdm_output_r), evhw->geo.tdm_transform);
+
+   return;
+normal:
+   evhw->geo.tdm_output_r = evhw->geo.output_r;
+   evhw->geo.tdm_transform = evhw->geo.transform;
+}
+
+static Eina_Bool
+_e_video_geometry_cal_viewport(E_Video_Hwc_Windows *evhw)
+{
+   E_Client *ec = evhw->ec;
+   E_Comp_Wl_Buffer_Viewport *vp = &ec->comp_data->scaler.buffer_viewport;
+   E_Comp_Wl_Subsurf_Data *sdata;
+   int x1, y1, x2, y2;
+   int tx1, ty1, tx2, ty2;
+   E_Comp_Wl_Buffer *comp_buffer;
+   tbm_surface_h tbm_surf;
+   uint32_t size = 0, offset = 0, pitch = 0;
+   int bw, bh;
+   int width_from_buffer, height_from_buffer;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+   comp_buffer = e_pixmap_resource_get(evhw->ec->pixmap);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(comp_buffer, EINA_FALSE);
+
+   tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surf, EINA_FALSE);
+
+   tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &pitch);
+
+   /* input geometry */
+   if (IS_RGB(evhw->tbmfmt))
+     evhw->geo.input_w = pitch / 4;
+   else
+     evhw->geo.input_w = pitch;
+
+   evhw->geo.input_h = tbm_surface_get_height(tbm_surf);
+
+   bw = tbm_surface_get_width(tbm_surf);
+   bh = tbm_surface_get_height(tbm_surf);
+   VDB("TBM buffer size %d %d", bw, bh);
+
+   switch (vp->buffer.transform)
+     {
+      case WL_OUTPUT_TRANSFORM_90:
+      case WL_OUTPUT_TRANSFORM_270:
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         width_from_buffer = bh / vp->buffer.scale;
+         height_from_buffer = bw / vp->buffer.scale;
+         break;
+      default:
+         width_from_buffer = bw / vp->buffer.scale;
+         height_from_buffer = bh / vp->buffer.scale;
+         break;
+     }
+
+
+   if (vp->buffer.src_width == wl_fixed_from_int(-1))
+     {
+        x1 = 0.0;
+        y1 = 0.0;
+        x2 = width_from_buffer;
+        y2 = height_from_buffer;
+     }
+   else
+     {
+        x1 = wl_fixed_to_int(vp->buffer.src_x);
+        y1 = wl_fixed_to_int(vp->buffer.src_y);
+        x2 = wl_fixed_to_int(vp->buffer.src_x + vp->buffer.src_width);
+        y2 = wl_fixed_to_int(vp->buffer.src_y + vp->buffer.src_height);
+     }
+
+   VDB("transform(%d) scale(%d) buffer(%dx%d) src(%d,%d %d,%d) viewport(%dx%d)",
+       vp->buffer.transform, vp->buffer.scale,
+       width_from_buffer, height_from_buffer,
+       x1, y1, x2 - x1, y2 - y1,
+       ec->comp_data->width_from_viewport, ec->comp_data->height_from_viewport);
+
+   buffer_transform(width_from_buffer, height_from_buffer,
+                    vp->buffer.transform, vp->buffer.scale, x1, y1, &tx1, &ty1);
+   buffer_transform(width_from_buffer, height_from_buffer,
+                    vp->buffer.transform, vp->buffer.scale, x2, y2, &tx2, &ty2);
+
+   evhw->geo.input_r.x = (tx1 <= tx2) ? tx1 : tx2;
+   evhw->geo.input_r.y = (ty1 <= ty2) ? ty1 : ty2;
+   evhw->geo.input_r.w = (tx1 <= tx2) ? tx2 - tx1 : tx1 - tx2;
+   evhw->geo.input_r.h = (ty1 <= ty2) ? ty2 - ty1 : ty1 - ty2;
+
+   /* output geometry */
+   if ((sdata = ec->comp_data->sub.data))
+     {
+        if (sdata->parent)
+          {
+             evhw->geo.output_r.x = sdata->parent->x + sdata->position.x;
+             evhw->geo.output_r.y = sdata->parent->y + sdata->position.y;
+          }
+        else
+          {
+             evhw->geo.output_r.x = sdata->position.x;
+             evhw->geo.output_r.y = sdata->position.y;
+          }
+     }
+   else
+     {
+        evhw->geo.output_r.x = ec->x;
+        evhw->geo.output_r.y = ec->y;
+     }
+
+   evhw->geo.output_r.w = ec->comp_data->width_from_viewport;
+   evhw->geo.output_r.w = (evhw->geo.output_r.w + 1) & ~1;
+   evhw->geo.output_r.h = ec->comp_data->height_from_viewport;
+
+   e_comp_object_frame_xy_unadjust(ec->frame,
+                                   evhw->geo.output_r.x, evhw->geo.output_r.y,
+                                   &evhw->geo.output_r.x, &evhw->geo.output_r.y);
+   e_comp_object_frame_wh_unadjust(ec->frame,
+                                   evhw->geo.output_r.w, evhw->geo.output_r.h,
+                                   &evhw->geo.output_r.w, &evhw->geo.output_r.h);
+
+   evhw->geo.transform = vp->buffer.transform;
+
+   _e_video_geometry_cal_physical(evhw);
+
+   VDB("geometry(%dx%d  %d,%d %dx%d  %d,%d %dx%d  %d)",
+       evhw->geo.input_w, evhw->geo.input_h,
+       EINA_RECTANGLE_ARGS(&evhw->geo.input_r),
+       EINA_RECTANGLE_ARGS(&evhw->geo.output_r),
+       evhw->geo.transform);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_geometry_cal_map(E_Video_Hwc_Windows *evhw)
+{
+   E_Client *ec;
+   const Evas_Map *m;
+   Evas_Coord x1, x2, y1, y2;
+   Eina_Rectangle output_r;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evhw, EINA_FALSE);
+
+   ec = evhw->ec;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec->frame, EINA_FALSE);
+
+   m = evas_object_map_get(ec->frame);
+   if (!m) return EINA_TRUE;
+
+   /* If frame has map, it means that ec's geometry is decided by map's geometry.
+    * ec->x,y,w,h and ec->client.x,y,w,h is not useful.
+    */
+
+   evas_map_point_coord_get(m, 0, &x1, &y1, NULL);
+   evas_map_point_coord_get(m, 2, &x2, &y2, NULL);
+
+   output_r.x = x1;
+   output_r.y = y1;
+   output_r.w = x2 - x1;
+   output_r.w = (output_r.w + 1) & ~1;
+   output_r.h = y2 - y1;
+   output_r.h = (output_r.h + 1) & ~1;
+
+   if (!memcmp(&evhw->geo.output_r, &output_r, sizeof(Eina_Rectangle)))
+     return EINA_FALSE;
+
+   VDB("frame(%p) m(%p) output(%d,%d %dx%d) => (%d,%d %dx%d)", ec->frame, m,
+       EINA_RECTANGLE_ARGS(&evhw->geo.output_r), EINA_RECTANGLE_ARGS(&output_r));
+
+   evhw->geo.output_r = output_r;
+
+   _e_video_geometry_cal_physical(evhw);
+
+   return EINA_TRUE;
+}
+
+static void
+_e_video_geometry_cal_to_input(int output_w, int output_h, int input_w, int input_h,
+                               uint32_t trasnform, int ox, int oy, int *ix, int *iy)
+{
+   float ratio_w, ratio_h;
+
+   switch(trasnform)
+     {
+      case WL_OUTPUT_TRANSFORM_NORMAL:
+      default:
+         *ix = ox, *iy = oy;
+         break;
+      case WL_OUTPUT_TRANSFORM_270:
+         *ix = oy, *iy = output_w - ox;
+         break;
+      case WL_OUTPUT_TRANSFORM_180:
+         *ix = output_w - ox, *iy = output_h - oy;
+         break;
+      case WL_OUTPUT_TRANSFORM_90:
+         *ix = output_h - oy, *iy = ox;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED:
+         *ix = output_w - ox, *iy = oy;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         *ix = oy, *iy = ox;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+         *ix = ox, *iy = output_h - oy;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+         *ix = output_h - oy, *iy = output_w - ox;
+         break;
+     }
+   if (trasnform & 0x1)
+     {
+        ratio_w = (float)input_w / output_h;
+        ratio_h = (float)input_h / output_w;
+     }
+   else
+     {
+        ratio_w = (float)input_w / output_w;
+        ratio_h = (float)input_h / output_h;
+     }
+   *ix *= ratio_w;
+   *iy *= ratio_h;
+}
+
+static void
+_e_video_geometry_cal_to_input_rect(E_Video_Hwc_Windows * evhw, Eina_Rectangle *srect, Eina_Rectangle *drect)
+{
+   int xf1, yf1, xf2, yf2;
+
+   /* first transform box coordinates if the scaler is set */
+
+   xf1 = srect->x;
+   yf1 = srect->y;
+   xf2 = srect->x + srect->w;
+   yf2 = srect->y + srect->h;
+
+   _e_video_geometry_cal_to_input(evhw->geo.output_r.w, evhw->geo.output_r.h,
+                                  evhw->geo.input_r.w, evhw->geo.input_r.h,
+                                  evhw->geo.transform, xf1, yf1, &xf1, &yf1);
+   _e_video_geometry_cal_to_input(evhw->geo.output_r.w, evhw->geo.output_r.h,
+                                  evhw->geo.input_r.w, evhw->geo.input_r.h,
+                                  evhw->geo.transform, xf2, yf2, &xf2, &yf2);
+
+   drect->x = MIN(xf1, xf2);
+   drect->y = MIN(yf1, yf2);
+   drect->w = MAX(xf1, xf2) - drect->x;
+   drect->h = MAX(yf1, yf2) - drect->y;
+}
+
+static Eina_Bool
+_e_video_geometry_cal(E_Video_Hwc_Windows *evhw)
+{
+   Eina_Rectangle screen = {0,};
+   Eina_Rectangle output_r = {0,}, input_r = {0,};
+   E_Zone *zone;
+   E_Client *topmost;
+
+   /* get geometry information with buffer scale, transform and viewport. */
+   if (!_e_video_geometry_cal_viewport(evhw))
+     return EINA_FALSE;
+
+   _e_video_geometry_cal_map(evhw);
+
+   topmost = e_comp_wl_topmost_parent_get(evhw->ec);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(topmost, EINA_FALSE);
+
+   zone = e_comp_zone_xy_get(topmost->x, topmost->y);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
+
+   screen.w = zone->w;
+   screen.h = zone->h;
+
+   e_comp_wl_video_buffer_size_get(evhw->ec, &input_r.w, &input_r.h);
+   // when topmost is not mapped, input size can be abnormal.
+   // in this case, it will be render by topmost showing.
+   if (!eina_rectangle_intersection(&evhw->geo.input_r, &input_r) || (evhw->geo.input_r.w <= 10 || evhw->geo.input_r.h <= 10))
+     {
+        VER("input area is empty");
+        return EINA_FALSE;
+     }
+
+   if (evhw->geo.output_r.x >= 0 && evhw->geo.output_r.y >= 0 &&
+       (evhw->geo.output_r.x + evhw->geo.output_r.w) <= screen.w &&
+       (evhw->geo.output_r.y + evhw->geo.output_r.h) <= screen.h)
+     return EINA_TRUE;
+
+   /* TODO: need to improve */
+
+   output_r = evhw->geo.output_r;
+   if (!eina_rectangle_intersection(&output_r, &screen))
+     {
+        VER("output_r(%d,%d %dx%d) screen(%d,%d %dx%d) => intersect(%d,%d %dx%d)",
+            EINA_RECTANGLE_ARGS(&evhw->geo.output_r),
+            EINA_RECTANGLE_ARGS(&screen), EINA_RECTANGLE_ARGS(&output_r));
+        return EINA_TRUE;
+     }
+
+   output_r.x -= evhw->geo.output_r.x;
+   output_r.y -= evhw->geo.output_r.y;
+
+   if (output_r.w <= 0 || output_r.h <= 0)
+     {
+        VER("output area is empty");
+        return EINA_FALSE;
+     }
+
+   VDB("output(%d,%d %dx%d) input(%d,%d %dx%d)",
+       EINA_RECTANGLE_ARGS(&output_r), EINA_RECTANGLE_ARGS(&input_r));
+
+   _e_video_geometry_cal_to_input_rect(evhw, &output_r, &input_r);
+
+   VDB("output(%d,%d %dx%d) input(%d,%d %dx%d)",
+       EINA_RECTANGLE_ARGS(&output_r), EINA_RECTANGLE_ARGS(&input_r));
+
+   output_r.x += evhw->geo.output_r.x;
+   output_r.y += evhw->geo.output_r.y;
+
+   input_r.x += evhw->geo.input_r.x;
+   input_r.y += evhw->geo.input_r.y;
+
+   output_r.x = output_r.x & ~1;
+   output_r.w = (output_r.w + 1) & ~1;
+
+   input_r.x = input_r.x & ~1;
+   input_r.w = (input_r.w + 1) & ~1;
+
+   evhw->geo.output_r = output_r;
+   evhw->geo.input_r = input_r;
+
+   _e_video_geometry_cal_physical(evhw);
+
+   return EINA_TRUE;
+}
+
+static void
+_e_video_format_info_get(E_Video_Hwc_Windows *evhw)
+{
+   E_Comp_Wl_Buffer *comp_buffer;
+   tbm_surface_h tbm_surf;
+
+   comp_buffer = e_pixmap_resource_get(evhw->ec->pixmap);
+   EINA_SAFETY_ON_NULL_RETURN(comp_buffer);
+
+   tbm_surf = wayland_tbm_server_get_surface(e_comp->wl_comp_data->tbm.server, comp_buffer->resource);
+   EINA_SAFETY_ON_NULL_RETURN(tbm_surf);
+
+   evhw->tbmfmt = tbm_surface_get_format(tbm_surf);
+}
+
+static Eina_Bool
+_e_video_can_commit(E_Video_Hwc_Windows *evhw)
+{
+   if (e_output_dpms_get(evhw->e_output))
+     return EINA_FALSE;
+
+   if (!_e_video_is_visible(evhw))
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static void
+_e_video_commit_handler(tdm_layer *layer, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,
+                        void *user_data)
+{
+   E_Video_Hwc_Windows *evhw;
+   Eina_List *l;
+   E_Comp_Wl_Video_Buf *vbuf;
+
+   EINA_LIST_FOREACH(video_list, l, evhw)
+     {
+        if (evhw == user_data) break;
+     }
+
+   if (!evhw) return;
+   if (!evhw->committed_list) return;
+
+   if (_e_video_can_commit(evhw))
+     {
+        tbm_surface_h displaying_buffer = evhw->cur_tsurface;
+
+        EINA_LIST_FOREACH(evhw->committed_list, l, vbuf)
+          {
+             if (vbuf->tbm_surface == displaying_buffer) break;
+          }
+        if (!vbuf) return;
+     }
+   else
+     vbuf = eina_list_nth(evhw->committed_list, 0);
+
+   evhw->committed_list = eina_list_remove(evhw->committed_list, vbuf);
+
+   /* client can attachs the same wl_buffer twice. */
+   if (evhw->current_fb && VBUF_IS_VALID(evhw->current_fb) && vbuf != evhw->current_fb)
+     {
+        e_comp_wl_video_buffer_set_use(evhw->current_fb, EINA_FALSE);
+
+        if (evhw->current_fb->comp_buffer)
+          e_comp_wl_buffer_reference(&evhw->current_fb->buffer_ref, NULL);
+     }
+
+   evhw->current_fb = vbuf;
+
+   VDB("current_fb(%d)", MSTAMP(evhw->current_fb));
+
+   _e_video_vblank_handler(NULL, sequence, tv_sec, tv_usec, evhw);
+}
+
+static void
+_e_video_commit_buffer(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Video_Buf *vbuf)
+{
+   evhw->committed_list = eina_list_append(evhw->committed_list, vbuf);
+
+   if (!_e_video_can_commit(evhw))
+     goto no_commit;
+
+   if (!_e_video_frame_buffer_show(evhw, vbuf))
+     goto no_commit;
+
+   return;
+
+no_commit:
+   _e_video_commit_handler(NULL, 0, 0, 0, evhw);
+   _e_video_vblank_handler(NULL, 0, 0, 0, evhw);
+}
+
+static void
+_e_video_commit_from_waiting_list(E_Video_Hwc_Windows *evhw)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+
+   vbuf = eina_list_nth(evhw->waiting_list, 0);
+   evhw->waiting_list = eina_list_remove(evhw->waiting_list, vbuf);
+
+   _e_video_commit_buffer(evhw, vbuf);
+}
+
+static void
+_e_video_vblank_handler(tdm_output *output, unsigned int sequence,
+                        unsigned int tv_sec, unsigned int tv_usec,
+                        void *user_data)
+{
+   E_Video_Hwc_Windows *evhw;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(video_list, l, evhw)
+     {
+        if (evhw == user_data) break;
+     }
+
+   if (!evhw) return;
+
+   evhw->waiting_vblank = EINA_FALSE;
+
+   if (evhw->waiting_list)
+     _e_video_commit_from_waiting_list(evhw);
+}
+
+static Eina_Bool
+_e_video_frame_buffer_show(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Video_Buf *vbuf)
+{
+   /* show means that set the information of the buffer and the info of the hwc window */
+
+   if (!vbuf) return EINA_TRUE;
+
+   CLEAR(evhw->info);
+   evhw->info.src_config.size.h = vbuf->width_from_pitch;
+   evhw->info.src_config.size.v = vbuf->height_from_size;
+   evhw->info.src_config.pos.x = vbuf->content_r.x;
+   evhw->info.src_config.pos.y = vbuf->content_r.y;
+   evhw->info.src_config.pos.w = vbuf->content_r.w;
+   evhw->info.src_config.pos.h = vbuf->content_r.h;
+   evhw->info.src_config.format = vbuf->tbmfmt;
+   evhw->info.dst_pos.x = evhw->geo.tdm_output_r.x;
+   evhw->info.dst_pos.y = evhw->geo.tdm_output_r.y;
+   evhw->info.dst_pos.w = evhw->geo.tdm_output_r.w;
+   evhw->info.dst_pos.h = evhw->geo.tdm_output_r.h;
+   evhw->info.transform = vbuf->content_t;
+
+   evhw->cur_tsurface = vbuf->tbm_surface;
+
+   evhw->waiting_vblank = EINA_TRUE;
+
+   // TODO:: this logic move to the hwc windows after hwc commit
+#if 1
+   E_Client *topmost;
+
+   topmost = e_comp_wl_topmost_parent_get(evhw->ec);
+   if (topmost && topmost->argb && !e_comp_object_mask_has(evhw->ec->frame))
+     {
+        Eina_Bool do_punch = EINA_TRUE;
+
+        /* FIXME: the mask obj can be drawn at the wrong position in the beginnig
+         * time. It happens caused by window manager policy.
+         */
+        if ((topmost->fullscreen || topmost->maximized) &&
+            (evhw->geo.output_r.x == 0 || evhw->geo.output_r.y == 0))
+          {
+             int bw, bh;
+
+             e_pixmap_size_get(topmost->pixmap, &bw, &bh);
+
+             if (bw > 100 && bh > 100 &&
+                 evhw->geo.output_r.w < 100 && evhw->geo.output_r.h < 100)
+               {
+                  VIN("don't punch. (%dx%d, %dx%d)",
+                      bw, bh, evhw->geo.output_r.w, evhw->geo.output_r.h);
+                  do_punch = EINA_FALSE;
+               }
+          }
+
+        if (do_punch)
+          {
+             e_comp_object_mask_set(evhw->ec->frame, EINA_TRUE);
+             VIN("punched");
+          }
+     }
+
+   if (e_video_debug_punch_value_get())
+     {
+        e_comp_object_mask_set(evhw->ec->frame, EINA_TRUE);
+        VIN("punched");
+     }
+#endif
+
+   DBG("Client(%s):PID(%d) RscID(%d), Buffer(%p, refcnt:%d) is shown."
+       "Geometry details are : buffer size(%dx%d) src(%d,%d, %dx%d)"
+       " dst(%d,%d, %dx%d), transform(%d)",
+       e_client_util_name_get(evhw->ec) ?: "No Name" , evhw->ec->netwm.pid,
+       wl_resource_get_id(evhw->ec->comp_data->surface), vbuf, vbuf->ref_cnt,
+       evhw->info.src_config.size.h, evhw->info.src_config.size.v, evhw->info.src_config.pos.x,
+       evhw->info.src_config.pos.y, evhw->info.src_config.pos.w, evhw->info.src_config.pos.h,
+       evhw->info.dst_pos.x, evhw->info.dst_pos.y, evhw->info.dst_pos.w, evhw->info.dst_pos.h, evhw->info.transform);
+
+
+   return EINA_TRUE;
+}
+
+static void
+_e_video_buffer_show(E_Video_Hwc_Windows *evhw, E_Comp_Wl_Video_Buf *vbuf, unsigned int transform)
+{
+   vbuf->content_t = transform;
+
+   e_comp_wl_video_buffer_set_use(vbuf, EINA_TRUE);
+
+   if (vbuf->comp_buffer)
+     e_comp_wl_buffer_reference(&vbuf->buffer_ref, vbuf->comp_buffer);
+
+   if (evhw->waiting_vblank)
+     {
+        evhw->waiting_list = eina_list_append(evhw->waiting_list, vbuf);
+        VDB("There are waiting fbs more than 1");
+        return;
+     }
+
+   _e_video_commit_buffer(evhw, vbuf);
+}
+
+static void
+_e_video_cb_evas_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+   E_Video_Hwc_Windows *evhw = data;
+
+   if (_e_video_geometry_cal_map(evhw))
+     _e_video_render(evhw, __FUNCTION__);
+}
+
+static void
+_e_video_cb_evas_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   E_Video_Hwc_Windows *evhw = data;
+
+   if (_e_video_geometry_cal_map(evhw))
+     _e_video_render(evhw, __FUNCTION__);
+}
+
+static void
+_e_video_cb_evas_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   E_Video_Hwc_Windows *evhw = data;
+
+   if (e_object_is_del(E_OBJECT(evhw->ec))) return;
+
+   if (!evhw->ec->comp_data->video_client)
+     return;
+
+   if (evhw->need_force_render)
+     {
+        VIN("video forcely rendering..");
+        _e_video_render(evhw, __FUNCTION__);
+     }
+
+   /* if stand_alone is true, not show */
+   if ((evhw->ec->comp_data->sub.data && evhw->ec->comp_data->sub.data->stand_alone) ||
+       (evhw->ec->comp_data->sub.data && evhw->follow_topmost_visibility))
+     {
+        return;
+     }
+
+   VIN("evas show (ec:%p)", evhw->ec);
+   if (evhw->current_fb)
+     _e_video_buffer_show(evhw, evhw->current_fb, evhw->current_fb->content_t);
+}
+
+static void
+_e_video_cb_evas_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   E_Video_Hwc_Windows *evhw = data;
+
+   if (e_object_is_del(E_OBJECT(evhw->ec))) return;
+
+   if (!evhw->ec->comp_data->video_client)
+     return;
+
+   VIN("evas hide (ec:%p)", evhw->ec);
+
+}
+
+static E_Video_Hwc_Windows *
+_e_video_create(E_Client *ec)
+{
+   E_Video_Hwc_Windows *evhw;
+   E_Output *e_output;
+   E_Hwc *hwc;
+   E_Hwc_Window *hwc_window;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec->zone, EINA_FALSE);
+
+   e_output = e_output_find(ec->zone->output_id);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e_output, EINA_FALSE);
+   hwc = e_output->hwc;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc, EINA_FALSE);
+   hwc_window = e_hwc_window_new(hwc, ec, E_HWC_WINDOW_STATE_VIDEO);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_window, EINA_FALSE);
+
+   evhw = calloc(1, sizeof *evhw);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(evhw, NULL);
+
+   evhw->ec = ec;
+   evhw->pp_align = -1;
+   evhw->video_align = -1;
+   evhw->e_output = e_output;
+   evhw->tdm_mute_id = -1;
+   evhw->window = e_client_util_win_get(ec);
+   evhw->hwc_window = hwc_window;
+   evhw->hwc = hwc;
+
+   /* This ec is a video client now. */
+   VIN("video client");
+   ec->comp_data->video_client = 1;
+
+   //TODO: shoud this function be called here?
+   e_zone_video_available_size_get(ec->zone, NULL, NULL, NULL, NULL, &evhw->video_align);
+
+   VIN("create. ec(%p) wl_surface@%d", ec, wl_resource_get_id(evhw->ec->comp_data->surface));
+
+   video_list = eina_list_append(video_list, evhw);
+
+   return evhw;
+}
+
+static void
+_e_video_hide(E_Video_Hwc_Windows *evhw)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+
+   if (evhw->current_fb || evhw->committed_list)
+     _e_video_frame_buffer_show(evhw, NULL);
+
+   if (evhw->current_fb)
+     {
+        e_comp_wl_video_buffer_set_use(evhw->current_fb, EINA_FALSE);
+        evhw->current_fb = NULL;
+     }
+
+   if (evhw->old_comp_buffer)
+     evhw->old_comp_buffer = NULL;
+
+   EINA_LIST_FREE(evhw->committed_list, vbuf)
+      e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+
+   EINA_LIST_FREE(evhw->waiting_list, vbuf)
+      e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+}
+
+static void
+_e_video_destroy(E_Video_Hwc_Windows *evhw)
+{
+   E_Comp_Wl_Video_Buf *vbuf;
+   Eina_List *l = NULL, *ll = NULL;
+
+   if (!evhw)
+     return;
+
+   VIN("destroy");
+
+   if (evhw->cb_registered)
+     {
+        evas_object_event_callback_del_full(evhw->ec->frame, EVAS_CALLBACK_RESIZE,
+                                            _e_video_cb_evas_resize, evhw);
+        evas_object_event_callback_del_full(evhw->ec->frame, EVAS_CALLBACK_MOVE,
+                                            _e_video_cb_evas_move, evhw);
+     }
+
+   _e_video_hide(evhw);
+
+   /* others */
+   EINA_LIST_FOREACH_SAFE(evhw->input_buffer_list, l, ll, vbuf)
+     {
+        e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+        e_comp_wl_video_buffer_unref(vbuf);
+     }
+
+   EINA_LIST_FOREACH_SAFE(evhw->pp_buffer_list, l, ll, vbuf)
+     {
+        e_comp_wl_video_buffer_set_use(vbuf, EINA_FALSE);
+        e_comp_wl_video_buffer_unref(vbuf);
+     }
+
+   if (evhw->input_buffer_list)
+     NEVER_GET_HERE();
+   if (evhw->pp_buffer_list)
+     NEVER_GET_HERE();
+
+   /* destroy converter second */
+   if (evhw->pp)
+     tdm_pp_destroy(evhw->pp);
+
+   video_list = eina_list_remove(video_list, evhw);
+
+   e_hwc_window_free(evhw->hwc_window);
+
+   free(evhw);
+
+#if 0
+   if (e_comp_wl_video_buffer_list_length() > 0)
+     e_comp_wl_video_buffer_list_print(NULL);
+#endif
+}
+
+static Eina_Bool
+_e_video_check_if_pp_needed(E_Video_Hwc_Windows *evhw)
+{
+   int i, count = 0;
+   const tbm_format *formats;
+   Eina_Bool found = EINA_FALSE;
+   E_Hwc *hwc = evhw->hwc;
+
+   if (hwc->tdm_hwc_video_stream)
+     return EINA_FALSE;
+
+   if (!e_comp_screen_available_video_formats_get(&formats, &count))
+     return EINA_FALSE;
+
+   for (i = 0; i < count; i++)
+     if (formats[i] == evhw->tbmfmt)
+       {
+          found = EINA_TRUE;
+          break;
+       }
+
+   if (!found)
+     {
+        if (formats && count > 0)
+          evhw->pp_tbmfmt = formats[0];
+        else
+          {
+             WRN("No layer format information!!!");
+             evhw->pp_tbmfmt = TBM_FORMAT_ARGB8888;
+          }
+        return EINA_TRUE;
+     }
+
+   if (hwc->tdm_hwc_video_scanout)
+     goto need_pp;
+
+   /* check size */
+   if (evhw->geo.input_r.w != evhw->geo.output_r.w || evhw->geo.input_r.h != evhw->geo.output_r.h)
+     if (!hwc->tdm_hwc_video_scale)
+       goto need_pp;
+
+   /* check rotate */
+   if (evhw->geo.transform || e_comp->e_comp_screen->rotation > 0)
+     if (!hwc->tdm_hwc_video_transform)
+       goto need_pp;
+
+   return EINA_FALSE;
+
+need_pp:
+   evhw->pp_tbmfmt = evhw->tbmfmt;
+
+   return EINA_TRUE;
+}
+
+static void
+_e_video_pp_cb_done(tdm_pp *pp, tbm_surface_h sb, tbm_surface_h db, void *user_data)
+{
+   E_Video_Hwc_Windows *evhw = (E_Video_Hwc_Windows*)user_data;
+   E_Comp_Wl_Video_Buf *input_buffer, *pp_buffer;
+
+   input_buffer = _e_video_vbuf_find(evhw->input_buffer_list, sb);
+   if (input_buffer)
+     e_comp_wl_video_buffer_unref(input_buffer);
+
+   pp_buffer = _e_video_vbuf_find(evhw->pp_buffer_list, db);
+   if (pp_buffer)
+     {
+        e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
+        if (!_e_video_is_visible(evhw)) return;
+
+        _e_video_buffer_show(evhw, pp_buffer, 0);
+     }
+   else
+     {
+        VER("There is no pp_buffer");
+        // there is no way to set in_use flag.
+        // This will cause issue when server get available pp_buffer.
+     }
+}
+
+static void
+_e_video_render(E_Video_Hwc_Windows *evhw, const char *func)
+{
+   E_Comp_Wl_Buffer *comp_buffer;
+   E_Comp_Wl_Video_Buf *pp_buffer = NULL;
+   E_Comp_Wl_Video_Buf *input_buffer = NULL;
+   E_Client *topmost;
+
+   EINA_SAFETY_ON_NULL_RETURN(evhw->ec);
+
+   /* buffer can be NULL when camera/video's mode changed. Do nothing and
+    * keep previous frame in this case.
+    */
+   if (!evhw->ec->pixmap)
+     return;
+
+   if (!_e_video_is_visible(evhw))
+     {
+        _e_video_hide(evhw);
+        return;
+     }
+
+   comp_buffer = e_pixmap_resource_get(evhw->ec->pixmap);
+   if (!comp_buffer) return;
+
+   _e_video_format_info_get(evhw);
+
+   /* not interested with other buffer type */
+   if (!wayland_tbm_server_get_surface(NULL, comp_buffer->resource))
+     return;
+
+   topmost = e_comp_wl_topmost_parent_get(evhw->ec);
+   EINA_SAFETY_ON_NULL_RETURN(topmost);
+
+   if(e_comp_wl_viewport_is_changed(topmost))
+     {
+        VIN("need update viewport: apply topmost");
+        e_comp_wl_viewport_apply(topmost);
+     }
+
+   if (!_e_video_geometry_cal(evhw))
+     {
+        if(!evhw->need_force_render && !_e_video_parent_is_viewable(evhw))
+          {
+             VIN("need force render");
+             evhw->need_force_render = EINA_TRUE;
+          }
+        return;
+     }
+
+   DBG("====================================== (%s)", func);
+   VDB("old: "GEO_FMT" buf(%p)", GEO_ARG(&evhw->old_geo), evhw->old_comp_buffer);
+   VDB("new: "GEO_FMT" buf(%p) %c%c%c%c", GEO_ARG(&evhw->geo), comp_buffer, FOURCC_STR(evhw->tbmfmt));
+
+   if (!memcmp(&evhw->old_geo, &evhw->geo, sizeof evhw->geo) &&
+       evhw->old_comp_buffer == comp_buffer)
+     return;
+
+   evhw->need_force_render = EINA_FALSE;
+
+   _e_video_input_buffer_valid(evhw, comp_buffer);
+
+   if (!_e_video_check_if_pp_needed(evhw))
+     {
+        /* 1. non converting case */
+        input_buffer = _e_video_input_buffer_get(evhw, comp_buffer, EINA_TRUE);
+        EINA_SAFETY_ON_NULL_GOTO(input_buffer, render_fail);
+
+        _e_video_buffer_show(evhw, input_buffer, evhw->geo.tdm_transform);
+
+        evhw->old_geo = evhw->geo;
+        evhw->old_comp_buffer = comp_buffer;
+
+        goto done;
+     }
+
+   /* 2. converting case */
+   if (!evhw->pp)
+     {
+        tdm_pp_capability pp_cap;
+        tdm_error error = TDM_ERROR_NONE;
+
+        evhw->pp = tdm_display_create_pp(e_comp->e_comp_screen->tdisplay, NULL);
+        EINA_SAFETY_ON_NULL_GOTO(evhw->pp, render_fail);
+
+        tdm_display_get_pp_available_size(e_comp->e_comp_screen->tdisplay, &evhw->pp_minw, &evhw->pp_minh,
+                                          &evhw->pp_maxw, &evhw->pp_maxh, &evhw->pp_align);
+
+        error = tdm_display_get_pp_capabilities(e_comp->e_comp_screen->tdisplay, &pp_cap);
+        if (error == TDM_ERROR_NONE)
+          {
+             if (pp_cap & TDM_PP_CAPABILITY_SCANOUT)
+               evhw->pp_scanout = EINA_TRUE;
+          }
+     }
+
+   if ((evhw->pp_minw > 0 && (evhw->geo.input_r.w < evhw->pp_minw || evhw->geo.tdm_output_r.w < evhw->pp_minw)) ||
+       (evhw->pp_minh > 0 && (evhw->geo.input_r.h < evhw->pp_minh || evhw->geo.tdm_output_r.h < evhw->pp_minh)) ||
+       (evhw->pp_maxw > 0 && (evhw->geo.input_r.w > evhw->pp_maxw || evhw->geo.tdm_output_r.w > evhw->pp_maxw)) ||
+       (evhw->pp_maxh > 0 && (evhw->geo.input_r.h > evhw->pp_maxh || evhw->geo.tdm_output_r.h > evhw->pp_maxh)))
+     {
+        INF("size(%dx%d, %dx%d) is out of PP range",
+            evhw->geo.input_r.w, evhw->geo.input_r.h, evhw->geo.tdm_output_r.w, evhw->geo.tdm_output_r.h);
+        goto done;
+     }
+
+   input_buffer = _e_video_input_buffer_get(evhw, comp_buffer, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_GOTO(input_buffer, render_fail);
+
+   pp_buffer = _e_video_pp_buffer_get(evhw, evhw->geo.tdm_output_r.w, evhw->geo.tdm_output_r.h);
+   EINA_SAFETY_ON_NULL_GOTO(pp_buffer, render_fail);
+
+   if (memcmp(&evhw->old_geo, &evhw->geo, sizeof evhw->geo))
+     {
+        tdm_info_pp info;
+
+        CLEAR(info);
+        info.src_config.size.h = input_buffer->width_from_pitch;
+        info.src_config.size.v = input_buffer->height_from_size;
+        info.src_config.pos.x = evhw->geo.input_r.x;
+        info.src_config.pos.y = evhw->geo.input_r.y;
+        info.src_config.pos.w = evhw->geo.input_r.w;
+        info.src_config.pos.h = evhw->geo.input_r.h;
+        info.src_config.format = evhw->tbmfmt;
+        info.dst_config.size.h = pp_buffer->width_from_pitch;
+        info.dst_config.size.v = pp_buffer->height_from_size;
+        info.dst_config.pos.w = evhw->geo.tdm_output_r.w;
+        info.dst_config.pos.h = evhw->geo.tdm_output_r.h;
+        info.dst_config.format = evhw->pp_tbmfmt;
+        info.transform = evhw->geo.tdm_transform;
+
+        if (tdm_pp_set_info(evhw->pp, &info))
+          {
+             VER("tdm_pp_set_info() failed");
+             goto render_fail;
+          }
+
+        if (tdm_pp_set_done_handler(evhw->pp, _e_video_pp_cb_done, evhw))
+          {
+             VER("tdm_pp_set_done_handler() failed");
+             goto render_fail;
+          }
+
+        CLEAR(evhw->pp_r);
+        evhw->pp_r.w = info.dst_config.pos.w;
+        evhw->pp_r.h = info.dst_config.pos.h;
+     }
+
+   pp_buffer->content_r = evhw->pp_r;
+
+   if (tdm_pp_attach(evhw->pp, input_buffer->tbm_surface, pp_buffer->tbm_surface))
+     {
+        VER("tdm_pp_attach() failed");
+        goto render_fail;
+     }
+
+   e_comp_wl_video_buffer_set_use(pp_buffer, EINA_TRUE);
+
+   e_comp_wl_buffer_reference(&input_buffer->buffer_ref, comp_buffer);
+
+   if (tdm_pp_commit(evhw->pp))
+     {
+        VER("tdm_pp_commit() failed");
+        e_comp_wl_video_buffer_set_use(pp_buffer, EINA_FALSE);
+        goto render_fail;
+     }
+
+   evhw->old_geo = evhw->geo;
+   evhw->old_comp_buffer = comp_buffer;
+
+   goto done;
+
+render_fail:
+   if (input_buffer)
+     e_comp_wl_video_buffer_unref(input_buffer);
+
+done:
+   if (!evhw->cb_registered)
+     {
+        evas_object_event_callback_add(evhw->ec->frame, EVAS_CALLBACK_RESIZE,
+                                       _e_video_cb_evas_resize, evhw);
+        evas_object_event_callback_add(evhw->ec->frame, EVAS_CALLBACK_MOVE,
+                                       _e_video_cb_evas_move, evhw);
+        evhw->cb_registered = EINA_TRUE;
+     }
+   DBG("======================================.");
+}
+
+static Eina_Bool
+_e_video_cb_ec_buffer_change(void *data, int type, void *event)
+{
+   E_Client *ec;
+   E_Event_Client *ev = event;
+   E_Video_Hwc_Windows *evhw;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+   evhw = data;
+   ec = ev->ec;
+
+   if (evhw->ec != ec)
+     return ECORE_CALLBACK_PASS_ON;
+
+   if (e_object_is_del(E_OBJECT(ec)))
+     return ECORE_CALLBACK_PASS_ON;
+
+   /* not interested with non video_surface */
+   if (!evhw->ec->comp_data->video_client)
+     return ECORE_CALLBACK_PASS_ON;
+
+   _e_video_render(evhw, __FUNCTION__);
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_video_cb_ec_client_show(void *data, int type, void *event)
+{
+   E_Event_Client *ev = event;
+   E_Client *ec;
+   E_Client *video_ec = NULL;
+   E_Video_Hwc_Windows *evhw = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+   ec = ev->ec;
+   if (!ec->comp_data) return ECORE_CALLBACK_PASS_ON;
+
+   video_ec = find_video_child_get(ec);
+   if (!video_ec) return ECORE_CALLBACK_PASS_ON;
+
+   evhw = data;
+   if (!evhw) return ECORE_CALLBACK_PASS_ON;
+
+   VIN("client(0x%08"PRIxPTR") show: find video child(0x%08"PRIxPTR")", (Ecore_Window)e_client_util_win_get(ec), (Ecore_Window)e_client_util_win_get(video_ec));
+   if(evhw->old_comp_buffer)
+     {
+        VIN("video already rendering..");
+        return ECORE_CALLBACK_PASS_ON;
+     }
+
+   if (ec == e_comp_wl_topmost_parent_get(evhw->ec))
+     {
+        VIN("video need rendering..");
+        e_comp_wl_viewport_apply(ec);
+        _e_video_render(evhw, __FUNCTION__);
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_video_cb_ec_visibility_change(void *data, int type, void *event)
+{
+   E_Event_Remote_Surface_Provider *ev = event;
+   E_Client *ec = ev->ec;
+   E_Video_Hwc_Windows *evhw;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(video_list, l, evhw)
+     {
+        E_Client *offscreen_parent = find_offscreen_parent_get(evhw->ec);
+        if (!offscreen_parent) continue;
+        if (offscreen_parent != ec) continue;
+        switch (ec->visibility.obscured)
+          {
+           case E_VISIBILITY_FULLY_OBSCURED:
+              _e_video_cb_evas_hide(evhw, NULL, NULL, NULL);
+              break;
+           case E_VISIBILITY_UNOBSCURED:
+              _e_video_cb_evas_show(evhw, NULL, NULL, NULL);
+              break;
+           default:
+              VER("Not implemented");
+              return ECORE_CALLBACK_PASS_ON;
+          }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_video_cb_topmost_ec_visibility_change(void *data, int type, void *event)
+{
+   E_Event_Client *ev = event;
+   E_Client *ec = ev->ec;
+   E_Video_Hwc_Windows *evhw;
+   Eina_List *l = NULL;
+
+   EINA_LIST_FOREACH(video_list, l, evhw)
+     {
+        E_Client *topmost = e_comp_wl_topmost_parent_get(evhw->ec);
+        if (!topmost) continue;
+        if (topmost == evhw->ec) continue;
+        if (topmost != ec) continue;
+        if (evhw->follow_topmost_visibility)
+          {
+             switch (ec->visibility.obscured)
+               {
+                case E_VISIBILITY_FULLY_OBSCURED:
+                   VIN("follow_topmost_visibility: fully_obscured");
+                   _e_video_cb_evas_hide(evhw, NULL, NULL, NULL);
+                   break;
+                case E_VISIBILITY_UNOBSCURED:
+                   VIN("follow_topmost_visibility: UNOBSCURED");
+                   _e_video_cb_evas_show(evhw, NULL, NULL, NULL);
+                   break;
+                default:
+                   return ECORE_CALLBACK_PASS_ON;
+               }
+          }
+     }
+
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static void
+_e_video_hwc_windows_ec_event_deinit(E_Video_Hwc_Windows *evhw)
+{
+   E_Client *ec;
+
+   ec = evhw->ec;
+
+   evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_SHOW,
+                                       _e_video_cb_evas_show, evhw);
+   evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_HIDE,
+                                       _e_video_cb_evas_hide, evhw);
+
+   E_FREE_LIST(evhw->ec_event_handler, ecore_event_handler_del);
+}
+
+const char *
+_e_video_hwc_windows_prop_name_get_by_id(E_Video_Hwc_Windows *evhw, unsigned int id)
+{
+   const tdm_prop *props;
+   int i, count = 0;
+
+   tdm_hwc_get_video_available_properties(evhw->hwc_window, &props, &count);
+   for (i = 0; i < count; i++)
+     {
+        if (props[i].id == id)
+          {
+             VDB("check property(%s)", props[i].name);
+             return props[i].name;
+          }
+     }
+
+   return NULL;
+}
+
+static void
+_e_video_hwc_windows_ec_event_init(E_Video_Hwc_Windows *evhw)
+{
+   E_Client *ec;
+
+   ec = evhw->ec;
+
+   evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW,
+                                  _e_video_cb_evas_show, evhw);
+   evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE,
+                                  _e_video_cb_evas_hide, evhw);
+
+   E_LIST_HANDLER_APPEND(evhw->ec_event_handler, E_EVENT_CLIENT_BUFFER_CHANGE,
+                         _e_video_cb_ec_buffer_change, evhw);
+   E_LIST_HANDLER_APPEND(evhw->ec_event_handler, E_EVENT_CLIENT_SHOW,
+                         _e_video_cb_ec_client_show, evhw);
+   E_LIST_HANDLER_APPEND(evhw->ec_event_handler, E_EVENT_REMOTE_SURFACE_PROVIDER_VISIBILITY_CHANGE,
+                         _e_video_cb_ec_visibility_change, evhw);
+   E_LIST_HANDLER_APPEND(evhw->ec_event_handler, E_EVENT_CLIENT_VISIBILITY_CHANGE,
+                         _e_video_cb_topmost_ec_visibility_change, evhw);
+}
+
+static void
+_e_video_hwc_windows_iface_destroy(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   _e_video_hwc_windows_ec_event_deinit(evhw);
+   _e_video_destroy(evhw);
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_follow_topmost_visibility(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   evhw->follow_topmost_visibility = EINA_TRUE;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_unfollow_topmost_visibility(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   evhw->follow_topmost_visibility = EINA_FALSE;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_allowed_property(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   evhw->allowed_attribute = EINA_TRUE;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_disallowed_property(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   evhw->allowed_attribute = EINA_FALSE;
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_property_get(E_Video_Comp_Iface *iface, unsigned int id, tdm_value *value)
+{
+   tdm_error ret;
+
+   IFACE_ENTRY;
+
+   ret = tdm_hwc_window_get_property(evhw->hwc_window, id, value);
+   if (ret != TDM_ERROR_NONE)
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_property_set(E_Video_Comp_Iface *iface, unsigned int id, tdm_value value)
+{
+   const char *name;
+
+   IFACE_ENTRY;
+
+   VIN("set_attribute");
+
+   name = _e_video_hwc_windows_prop_name_get_by_id(evhw, id);
+
+   if (evhw->allowed_attribute)
+     {
+        VIN("set_attribute now : property(%s), value(%d)", name, value.u32);
+
+        /* set the property on the fly */
+        if (!e_hwc_window_set_property(evhw->hwc_window, id, name, value, EINA_TRUE))
+          {
+             VER("set property failed");
+             return EINA_FALSE;
+          }
+     }
+   else
+     {
+        VIN("set_attribute at commit : property(%s), value(%d)", name, value.u32);
+
+        /* set the property before hwc commit */
+        if (!e_hwc_window_set_property(evhw->hwc_window, id, name, value, EINA_FALSE))
+          {
+             VER("set property failed");
+             return EINA_FALSE;
+          }
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_available_properties_get(E_Video_Comp_Iface *iface, const tdm_prop **props, int *count)
+{
+   IFACE_ENTRY;
+
+   if (!e_hwc_windows_get_video_available_properties(evhw->hwc, props, count))
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_info_get(E_Video_Comp_Iface *iface, E_Client_Video_Info *info)
+{
+   IFACE_ENTRY;
+
+   memcpy(&info->src_config, &evhw->info.src_config, sizeof(tdm_info_config));
+   memcpy(&info->dst_pos, &evhw->info.dst_pos, sizeof(tdm_pos));
+   info->transform = evhw->info.transform;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_video_hwc_windows_iface_commit_data_release(E_Video_Comp_Iface *iface, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
+{
+   IFACE_ENTRY;
+
+   _e_video_commit_handler(NULL, sequence, tv_sec, tv_usec, evhw);
+
+   return EINA_TRUE;
+}
+
+static tbm_surface_h
+_e_video_hwc_windows_iface_tbm_surface_get(E_Video_Comp_Iface *iface)
+{
+   IFACE_ENTRY;
+
+   return evhw->cur_tsurface;
+}
+
+EINTERN E_Video_Comp_Iface *
+e_video_hwc_windows_iface_create(E_Client *ec)
+{
+   E_Video_Hwc_Windows *evhw;
+
+   INF("Initializing HWC Windows mode");
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+   evhw = _e_video_create(ec);
+   if (!evhw)
+     {
+        ERR("Failed to create 'E_Video_Hwc_Windows'");
+        return NULL;
+     }
+
+   _e_video_hwc_windows_ec_event_init(evhw);
+
+   evhw->base.destroy = _e_video_hwc_windows_iface_destroy;
+   evhw->base.follow_topmost_visibility = _e_video_hwc_windows_iface_follow_topmost_visibility;
+   evhw->base.unfollow_topmost_visibility = _e_video_hwc_windows_iface_unfollow_topmost_visibility;
+   evhw->base.allowed_property = _e_video_hwc_windows_iface_allowed_property;
+   evhw->base.disallowed_property = _e_video_hwc_windows_iface_disallowed_property;
+   evhw->base.property_get = _e_video_hwc_windows_iface_property_get;
+   evhw->base.property_set = _e_video_hwc_windows_iface_property_set;
+   evhw->base.property_delay_set = NULL;
+   evhw->base.available_properties_get = _e_video_hwc_windows_iface_available_properties_get;
+   evhw->base.info_get = _e_video_hwc_windows_iface_info_get;
+   evhw->base.commit_data_release = _e_video_hwc_windows_iface_commit_data_release;
+   evhw->base.tbm_surface_get = _e_video_hwc_windows_iface_tbm_surface_get;
+
+   return &evhw->base;
+}