e_output_hwc: generate the e_output_hwc_planes files. 48/165948/3
authorSooChan Lim <sc1.lim@samsung.com>
Thu, 4 Jan 2018 07:02:59 +0000 (16:02 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Fri, 5 Jan 2018 10:01:41 +0000 (10:01 +0000)
move the codes for hwc_planes from e_output_hwc to the e_output_hwc_planes file.

Change-Id: I23e80ce9e615eadae40255704dcc7b4213911f99

src/bin/Makefile.mk
src/bin/e_includes.h
src/bin/e_output_hwc.c
src/bin/e_output_hwc.h
src/bin/e_output_hwc_planes.c [new file with mode: 0644]
src/bin/e_output_hwc_planes.h [new file with mode: 0644]

index bf2761ab5764bf53af15bac0c4901bbb4ae38791..86aa9ba1f1b923224e96a70185299f4270678c07 100644 (file)
@@ -84,12 +84,13 @@ src/bin/e_zoomap.h \
 src/bin/e_zone.h \
 src/bin/e_util_transform.h \
 src/bin/e_comp_screen.h \
-src/bin/e_output_hwc.h \
 src/bin/e_info_protocol.h \
 src/bin/e_uuid_store.h \
 src/bin/e_comp_wl_data.h \
 src/bin/e_comp_wl_input.h \
-src/bin/e_comp_wl.h
+src/bin/e_comp_wl.h \
+src/bin/e_output_hwc.h \
+src/bin/e_output_hwc_planes.h
 
 if HAVE_WAYLAND_TBM
 ENLIGHTENMENTHEADERS += \
@@ -134,7 +135,6 @@ src/bin/e_comp_canvas.c \
 src/bin/e_comp_cfdata.c \
 src/bin/e_comp_object.c \
 src/bin/e_comp_screen.c \
-src/bin/e_output_hwc.c \
 src/bin/e_config.c \
 src/bin/e_config_data.c \
 src/bin/e_dbusmenu.c \
@@ -189,6 +189,8 @@ src/bin/e_comp_wl_data.c \
 src/bin/e_comp_wl_input.c \
 src/bin/e_comp_wl.c \
 src/bin/tizen-surface-protocol.c \
+src/bin/e_output_hwc.c \
+src/bin/e_output_hwc_planes.c \
 $(ENLIGHTENMENTHEADERS)
 
 if HAVE_WAYLAND_TBM
index b2c9e549ee58a5ce8df878bcf8161e8119091fd8..d399f90afdcc1f4b7bb88ace650163761d84193a 100644 (file)
@@ -43,7 +43,6 @@
 #include "e_log.h"
 #include "e_dbusmenu.h"
 #include "e_comp_screen.h"
-#include "e_output_hwc.h"
 #include "e_comp.h"
 #include "e_comp_cfdata.h"
 #include "e_comp_canvas.h"
@@ -52,6 +51,8 @@
 #include "e_plane.h"
 #include "e_plane_renderer.h"
 #include "e_output.h"
+#include "e_output_hwc.h"
+#include "e_output_hwc_planes.h"
 #include "e_comp_wl.h"
 #include "e_comp_wl_data.h"
 #include "e_comp_wl_input.h"
index 34add42eb99b2cf8e7bd2a883613d9d82202b415..952fcc53c2411d947bbf87cbe8fa1862d494c895 100644 (file)
@@ -1,602 +1,6 @@
 #include "e.h"
 #include "services/e_service_quickpanel.h"
 
-static Eina_Bool
-_e_output_hwc_ec_check(E_Client *ec)
-{
-   E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
-   E_Output *eout;
-   int minw = 0, minh = 0;
-
-   if ((!cdata) ||
-       (!cdata->buffer_ref.buffer) ||
-       (cdata->width_from_buffer != cdata->width_from_viewport) ||
-       (cdata->height_from_buffer != cdata->height_from_viewport) ||
-       cdata->never_hwc)
-     {
-        return EINA_FALSE;
-     }
-
-   if (e_client_transform_core_enable_get(ec)) return EINA_FALSE;
-
-   switch (cdata->buffer_ref.buffer->type)
-     {
-      case E_COMP_WL_BUFFER_TYPE_NATIVE:
-         break;
-      case E_COMP_WL_BUFFER_TYPE_TBM:
-         if (cdata->buffer_ref.buffer->resource)
-           break;
-      case E_COMP_WL_BUFFER_TYPE_SHM:
-         if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role))
-           break;
-
-      default:
-         return EINA_FALSE;
-     }
-
-   eout = e_output_find(ec->zone->output_id);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
-
-   tdm_output_get_available_size(eout->toutput, &minw, &minh, NULL, NULL, NULL);
-
-   if ((minw > 0) && (minw > cdata->buffer_ref.buffer->w))
-     return EINA_FALSE;
-   if ((minh > 0) && (minh > cdata->buffer_ref.buffer->h))
-     return EINA_FALSE;
-
-   /* If a client doesn't watch the ignore_output_transform events, we can't show
-    * a client buffer to HW overlay directly when the buffer transform is not same
-    * with output transform. If a client watch the ignore_output_transform events,
-    * we can control client's buffer transform. In this case, we don't need to
-    * check client's buffer transform here.
-    */
-   if (!e_comp_screen_rotation_ignore_output_transform_watch(ec))
-     {
-        int transform = e_comp_wl_output_buffer_transform_get(ec);
-
-        if ((eout->config.rotation / 90) != transform)
-          return EINA_FALSE;
-     }
-
-   return EINA_TRUE;
-}
-
-static void
-_e_output_hwc_planes_prepare_init(E_Output_Hwc *output_hwc)
-{
-   const Eina_List *ep_l = NULL, *l ;
-   E_Plane *ep = NULL;
-   E_Output *eout = output_hwc->output;
-
-   EINA_SAFETY_ON_NULL_RETURN(output_hwc);
-
-   ep_l = e_output_planes_get(eout);
-   EINA_LIST_FOREACH(ep_l, l, ep)
-     {
-        if (!output_hwc->hwc_use_multi_plane &&
-            !e_plane_is_cursor(ep) &&
-            !e_plane_is_fb_target(ep))
-          continue;
-
-        e_plane_ec_prepare_set(ep, NULL);
-     }
-}
-
-static int
-_e_output_hwc_planes_prepare_cursor(E_Output *eout, int n_cur, Eina_List *hwc_clist)
-{
-   // policy for cursor layer
-   const Eina_List *ep_l = NULL, *l ;
-   Eina_List *cur_ly = NULL;
-   E_Plane *ep = NULL;
-   int n_skip = 0;
-   int n_curly = 0;
-   int nouse = 0;
-
-   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_clist, EINA_FALSE);
-
-   // list up cursor only layers
-   ep_l = e_output_planes_get(eout);
-   EINA_LIST_FOREACH(ep_l, l, ep)
-     {
-        if (e_plane_is_cursor(ep))
-          {
-             cur_ly = eina_list_append(cur_ly, ep);
-             continue;
-          }
-     }
-
-   if (!cur_ly) return 0;
-   n_curly = eina_list_count(cur_ly);
-
-   if (n_cur > 0 && n_curly > 0)
-     {
-        if (n_cur >= n_curly) nouse = 0;
-        else nouse = n_curly - n_cur;
-
-        //assign cursor on cursor only layers
-        EINA_LIST_REVERSE_FOREACH(cur_ly, l, ep)
-          {
-             E_Client *ec = NULL;
-             if (nouse > 0)
-               {
-                  nouse--;
-                  continue;
-               }
-             if (hwc_clist) ec = eina_list_data_get(hwc_clist);
-             if (ec && e_plane_ec_prepare_set(ep, ec))
-               {
-                  n_skip += 1;
-                  hwc_clist = eina_list_next(hwc_clist);
-               }
-          }
-     }
-
-   eina_list_free(cur_ly);
-
-   return n_skip;
-}
-
-static Eina_Bool
-_e_output_hwc_planes_prepare_plane(E_Output_Hwc *output_hwc, int n_vis, int n_skip, Eina_List *hwc_clist)
-{
-   const Eina_List *ep_l = NULL, *l ;
-   Eina_List *hwc_ly = NULL;
-   E_Plane *ep = NULL, *ep_fb = NULL;
-   int n_ly = 0, n_ec = 0;
-   E_Client *ec = NULL;
-   Eina_Bool ret = EINA_FALSE;
-   int nouse = 0;
-   E_Output *eout = output_hwc->output;
-
-   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_clist, EINA_FALSE);
-
-   n_ec = eina_list_count(hwc_clist);
-   if (n_skip > 0)
-     {
-        int i;
-        for (i = 0; i < n_skip; i++)
-          hwc_clist = eina_list_next(hwc_clist);
-
-        n_ec -= n_skip;
-        n_vis -= n_skip;
-     }
-
-   if (n_ec <= 0) return EINA_FALSE;
-
-   // list up available_hw layers E_Client can be set
-   // if e_comp->hwc_use_multi_plane FALSE, than use only fb target plane
-   ep_l = e_output_planes_get(eout);
-   EINA_LIST_FOREACH(ep_l, l, ep)
-     {
-        if (!ep_fb)
-          {
-             if (e_plane_is_fb_target(ep))
-               {
-                  ep_fb = ep;
-                  hwc_ly = eina_list_append(hwc_ly, ep);
-               }
-             continue;
-          }
-        if (!output_hwc->hwc_use_multi_plane) continue;
-        if (e_plane_is_cursor(ep)) continue;
-        if (ep->zpos > ep_fb->zpos)
-          hwc_ly = eina_list_append(hwc_ly, ep);
-     }
-
-   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_ly, EINA_FALSE);
-
-   // finally, assign client on available_hw layers
-   n_ly = eina_list_count(hwc_ly);
-   if ((n_ec == n_vis) &&
-       (n_ec <= n_ly)) // fully hwc
-     {
-        nouse = n_ly - n_ec;
-     }
-   else if ((n_ly < n_vis) || // e_comp->evas on fb target plane
-            (n_ec < n_vis))
-     {
-        if (n_ec <= n_ly) nouse = n_ly - n_ec - 1;
-        else nouse = 0;
-     }
-
-   EINA_LIST_REVERSE_FOREACH(hwc_ly, l, ep)
-     {
-        ec = NULL;
-        if (nouse > 0)
-          {
-             nouse--;
-             continue;
-          }
-        if (hwc_clist) ec = eina_list_data_get(hwc_clist);
-        if (ec && e_plane_ec_prepare_set(ep, ec))
-          {
-             ret = EINA_TRUE;
-
-             hwc_clist = eina_list_next(hwc_clist);
-             n_ec--; n_vis--;
-          }
-        if (e_plane_is_fb_target(ep))
-          {
-             if (n_ec > 0 || n_vis > 0) e_plane_ec_prepare_set(ep, NULL);
-             break;
-          }
-     }
-
-   eina_list_free(hwc_ly);
-
-   return ret;
-}
-
-static void
-_e_output_hwc_planes_cancel(E_Output_Hwc *output_hwc)
-{
-   Eina_List *l ;
-   E_Plane *ep;
-   E_Output *eout = output_hwc->output;
-
-   EINA_LIST_FOREACH(eout->planes, l, ep)
-     {
-        if (!output_hwc->hwc_use_multi_plane &&
-            !e_plane_is_cursor(ep) &&
-            !e_plane_is_fb_target(ep))
-             continue;
-
-        e_plane_ec_prepare_set(ep, NULL);
-        e_plane_ec_set(ep, NULL);
-     }
-}
-
-static Eina_Bool
-_e_output_hwc_planes_reserved_clean(E_Output_Hwc *output_hwc)
-{
-   Eina_List *l;
-   E_Plane *ep;
-   E_Output *eout = output_hwc->output;
-
-   EINA_LIST_FOREACH(eout->planes, l, ep)
-     {
-        if (!output_hwc->hwc_use_multi_plane &&
-            !e_plane_is_cursor(ep) &&
-            !e_plane_is_fb_target(ep))
-          continue;
-
-        if (e_plane_is_reserved(ep))
-            e_plane_reserved_set(ep, 0);
-     }
-
-   return EINA_TRUE;
-}
-
-static void
-_e_output_hwc_planes_unset(E_Plane *ep)
-{
-   if (e_plane_is_reserved(ep))
-     e_plane_reserved_set(ep, 0);
-
-   e_plane_ec_prepare_set(ep, NULL);
-   e_plane_ec_set(ep, NULL);
-
-   ELOGF("HWC", "unset plane %d to NULL", NULL, NULL, ep->zpos);
-}
-
-static Eina_Bool
-_e_output_hwc_planes_change_ec(E_Plane *ep, E_Client *new_ec)
-{
-   if (!e_plane_ec_set(ep, new_ec))
-     {
-        ELOGF("HWC", "failed to set new_ec(%s) on %d",
-              NULL, new_ec,
-              new_ec ? (new_ec->icccm.name ? new_ec->icccm.name : "no name") : "NULL",
-              ep->zpos);
-        return EINA_FALSE;
-     }
-
-   if (new_ec)
-     ELOGF("HWC", "new_ec(%s) is set on %d",
-           new_ec->pixmap, new_ec,
-           e_client_util_name_get(new_ec) ? new_ec->icccm.name : "no name", ep->zpos);
-   else
-     ELOGF("HWC", "NULL is set on %d", NULL, NULL, ep->zpos);
-
-   return EINA_TRUE;
-}
-
-static void
-_e_output_hwc_planes_changed(E_Output_Hwc *output_hwc)
-{
-   Eina_Bool ret = EINA_FALSE;
-   E_Plane *ep = NULL;
-   const Eina_List *ep_l = NULL, *p_l;
-   Eina_Bool assign_success = EINA_TRUE;
-   int mode = E_OUTPUT_HWC_MODE_NONE;
-   E_Output *eout = output_hwc->output;
-
-   ep_l = e_output_planes_get(eout);
-   /* check the planes from top to down */
-   EINA_LIST_REVERSE_FOREACH(ep_l, p_l, ep)
-     {
-        if (!assign_success)
-          {
-             //unset planes from 'assign_success' became EINA_FALSE to the fb target
-             _e_output_hwc_planes_unset(ep);
-             continue;
-          }
-
-        if (e_plane_is_reserved(ep) &&
-            ep->prepare_ec == NULL)
-          {
-             e_plane_reserved_set(ep, 0);
-             ELOGF("HWC", "unset reserved mem on %d", NULL, NULL, ep->zpos);
-          }
-
-        if (ep->ec != ep->prepare_ec)
-          {
-             assign_success = _e_output_hwc_planes_change_ec(ep, ep->prepare_ec);
-             ret = EINA_TRUE;
-          }
-
-        if (ep->ec) mode = E_OUTPUT_HWC_MODE_HYBRID;
-
-        if (e_plane_is_fb_target(ep))
-          {
-             if (ep->ec) mode = E_OUTPUT_HWC_MODE_FULL;
-             break;
-          }
-   }
-
-   if (output_hwc->hwc_mode != mode)
-     {
-        ELOGF("HWC", "mode changed (from %d to %d) due to surface changes",
-              NULL, NULL,
-              output_hwc->hwc_mode, mode);
-
-        if (mode == E_OUTPUT_HWC_MODE_FULL)
-          {
-             // fb target is occupied by a client surface, means compositor disabled
-             ecore_event_add(E_EVENT_COMPOSITOR_DISABLE, NULL, NULL, NULL);
-          }
-        else if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_FULL)
-          {
-             // fb target is occupied by a client surface, means compositor disabled
-             ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
-          }
-
-        output_hwc->hwc_mode = mode;
-     }
-
-   if (ret)
-     {
-        if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_NONE)
-          ELOGF("HWC", " End...  due to surface changes", NULL, NULL);
-        else
-          ELOGF("HWC", " hwc surface changed", NULL, NULL);
-     }
-}
-
-static Eina_Bool
-_e_output_hwc_planes_prepare(E_Output_Hwc *output_hwc, E_Zone *zone)
-{
-   Eina_List *vl;
-   Eina_Bool ret = EINA_FALSE;
-   E_Client *ec;
-   int n_vis = 0, n_ec = 0, n_cur = 0, n_skip = 0;
-   Eina_List *hwc_ok_clist = NULL, *vis_clist = NULL;
-   E_Output *output = output_hwc->output;
-
-   vis_clist = e_comp_vis_ec_list_get(zone);
-   if (!vis_clist) return EINA_FALSE;
-
-   // check clients not able to use hwc
-   EINA_LIST_FOREACH(vis_clist, vl, ec)
-     {
-        // if there is a ec which is lower than quickpanel and quickpanel is opened.
-        if (E_POLICY_QUICKPANEL_LAYER >= evas_object_layer_get(ec->frame))
-          {
-             // check whether quickpanel is open than break
-             if (e_qp_visible_get()) goto done;
-          }
-
-        // if ec->frame is not for client buffer (e.g. launchscreen)
-        if (e_comp_object_content_type_get(ec->frame) != E_COMP_OBJECT_CONTENT_TYPE_INT_IMAGE)
-           goto done;
-
-        // if there is UI subfrace, it means need to composite
-        if (e_client_normal_client_has(ec))
-           goto done;
-
-        // if ec has invalid buffer or scaled( transformed ) or forced composite(never_hwc)
-        if (!_e_output_hwc_ec_check(ec))
-          {
-             if (!n_ec) goto done;
-             break;
-          }
-
-        // listup as many as possible from the top most visible order
-        n_ec++;
-        if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role)) n_cur++;
-        hwc_ok_clist = eina_list_append(hwc_ok_clist, ec);
-     }
-
-   n_vis = eina_list_count(vis_clist);
-   if ((n_vis < 1) || (n_ec < 1))
-     goto done;
-
-   _e_output_hwc_planes_prepare_init(output_hwc);
-
-   if (n_cur >= 1)
-     n_skip = _e_output_hwc_planes_prepare_cursor(output, n_cur, hwc_ok_clist);
-
-   if (n_skip > 0) ret = EINA_TRUE;
-
-   ret |= _e_output_hwc_planes_prepare_plane(output_hwc, n_vis, n_skip, hwc_ok_clist);
-
-done:
-   eina_list_free(hwc_ok_clist);
-   eina_list_free(vis_clist);
-
-   return ret;
-}
-
-static Eina_Bool
-_e_output_hwc_planes_usable(E_Output_Hwc *output_hwc)
-{
-   E_Output *eout = output_hwc->output;
-   E_Comp_Wl_Buffer *buffer = NULL;
-   E_Zone *zone = NULL;
-   int bw = 0, bh = 0;
-   Eina_Bool all_null = EINA_TRUE;
-   E_Plane *ep = NULL;
-   const Eina_List *ep_l = NULL, *p_l;
-
-   zone = e_comp_zone_find(e_output_output_id_get(eout));
-   EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
-
-   // check whether to use hwc and prepare the core assignment policy
-   if (!_e_output_hwc_planes_prepare(output_hwc, zone)) return EINA_FALSE;
-
-   // extra policy can replace core policy
-   e_comp_hook_call(E_COMP_HOOK_PREPARE_PLANE, NULL);
-
-   // It is not hwc_usable if cursor is shown when the hw cursor is not supported by libtdm.
-   if (!e_pointer_is_hidden(e_comp->pointer) &&
-       (eout->cursor_available.max_w == -1 || eout->cursor_available.max_h == -1))
-     return EINA_FALSE;
-
-   // check the hwc is avaliable.
-   ep_l = e_output_planes_get(eout);
-   EINA_LIST_FOREACH(ep_l, p_l, ep)
-     {
-        if (!ep->prepare_ec) continue;
-
-        // It is not hwc_usable if attached buffer is not valid.
-        buffer = e_pixmap_resource_get(ep->prepare_ec->pixmap);
-        if (!buffer) return EINA_FALSE;
-
-        if (e_plane_is_fb_target(ep))
-          {
-             // It is not hwc_usable if the geometry of the prepare_ec at the ep_fb is not proper.
-             e_pixmap_size_get(ep->prepare_ec->pixmap, &bw, &bh);
-
-             // if client and zone's geometry is not match with, or
-             // if plane with reserved_memory(esp. fb target) has assigned smaller buffer,
-             // won't support hwc properly, than let's composite
-             if (ep->reserved_memory &&
-                 ((bw != zone->w) || (bh != zone->h) ||
-                 (ep->prepare_ec->x != zone->x) || (ep->prepare_ec->y != zone->y) ||
-                 (ep->prepare_ec->w != zone->w) || (ep->prepare_ec->h != zone->h)))
-               {
-                  DBG("Cannot use HWC if geometry is not 1 on 1 match with reserved_memory");
-                  return EINA_FALSE;
-               }
-          }
-
-        all_null = EINA_FALSE;
-        break;
-     }
-
-   // It is not hwc_usable if the all prepare_ec in every plane are null
-   if (all_null) return EINA_FALSE;
-
-   return EINA_TRUE;
-}
-
-static Eina_Bool
-_e_output_hwc_planes_can_hwcompose(E_Output *eout)
-{
-   const Eina_List *ep_l = NULL, *l;
-   E_Plane *ep = NULL, *ep_fb = NULL;
-
-   ep_l = e_output_planes_get(eout);
-   /* check the planes from down to top */
-   EINA_LIST_FOREACH(ep_l, l, ep)
-     {
-        if (e_plane_is_fb_target(ep))
-          {
-             /* can hwcompose if fb_target has a ec. */
-             if (ep->prepare_ec != NULL) return EINA_TRUE;
-             else ep_fb = ep;
-          }
-        else
-          {
-             /* can hwcompose if ep has a ec and zpos is higher than ep_fb */
-             if (ep->prepare_ec != NULL &&
-                 ep_fb &&
-                 ep->zpos > ep_fb->zpos)
-               return EINA_TRUE;
-          }
-     }
-
-   return EINA_FALSE;
-}
-
-static void
-_e_output_hwc_planes_begin(E_Output_Hwc *output_hwc)
-{
-   const Eina_List *ep_l = NULL, *l;
-   E_Output *eout = output_hwc->output;
-   E_Plane *ep = NULL;
-   E_Output_Hwc_Mode mode = E_OUTPUT_HWC_MODE_NONE;
-   Eina_Bool set = EINA_FALSE;
-
-   if (e_comp->nocomp_override > 0) return;
-
-   if (_e_output_hwc_planes_can_hwcompose(eout))
-     {
-        ep_l = e_output_planes_get(eout);
-
-        /* set the prepare_ec to the e_plane */
-        /* check the planes from top to down */
-        EINA_LIST_REVERSE_FOREACH(ep_l, l , ep)
-          {
-             if (!ep->prepare_ec) continue;
-
-             set = e_plane_ec_set(ep, ep->prepare_ec);
-             if (!set) break;
-
-             if (e_plane_is_fb_target(ep))
-               {
-                  ELOGF("HWC", "is set on fb_target( %d)", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
-                  mode = E_OUTPUT_HWC_MODE_FULL;
-
-                  // fb target is occupied by a client surface, means compositor disabled
-                  ecore_event_add(E_EVENT_COMPOSITOR_DISABLE, NULL, NULL, NULL);
-               }
-             else
-               {
-                  ELOGF("HWC", "is set on %d", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
-                  mode = E_OUTPUT_HWC_MODE_HYBRID;
-               }
-          }
-
-        if (mode == E_OUTPUT_HWC_MODE_NONE)
-           ELOGF("HWC", " Begin is not available yet ...", NULL, NULL);
-        else
-           ELOGF("HWC", " Begin ...", NULL, NULL);
-     }
-
-   output_hwc->hwc_mode = mode;
-}
-
-static E_Output_Hwc_Mode
-_e_output_hwc_mode_get(E_Output_Hwc *output_hwc)
-{
-   const Eina_List *ll = NULL, *l;
-   E_Output *output = output_hwc->output;
-   E_Plane *plane = NULL;
-
-   /* check the planes from down to top */
-   EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane)
-     {
-        if (!plane->ec) continue;
-        if (e_plane_is_fb_target(plane)) return E_OUTPUT_HWC_MODE_FULL;
-
-        return E_OUTPUT_HWC_MODE_HYBRID;
-     }
-
-   return E_OUTPUT_HWC_MODE_NONE;
-}
-
 EINTERN E_Output_Hwc *
 e_output_hwc_new(E_Output *output)
 {
@@ -618,14 +22,26 @@ e_output_hwc_new(E_Output *output)
     *   - The tdm-backend decides the hwc policy with the E_Hwc_Windows associated with the tdm_hwc_window.
     *   - E20 asks to verify the compsition types of the E_Hwc_Window of the ec.
     */
-   if (output->tdm_hwc)
+   if (!output->tdm_hwc)
      {
-        output_hwc->hwc_policy = E_OUTPUT_HWC_POLICY_WINDOWS;
+        output_hwc->hwc_policy = E_OUTPUT_HWC_POLICY_PLANES;
+        if (!e_output_hwc_planes_init())
+          {
+             ERR("hwc_opt: e_output_hwc_windows_init failed");
+             goto fail;
+          }
+
+        INF("Output uses the HWC PLANES Policy.");
      }
    else
-     output_hwc->hwc_policy = E_OUTPUT_HWC_POLICY_PLANES;
+     output_hwc->hwc_policy = E_OUTPUT_HWC_POLICY_WINDOWS;
 
    return output_hwc;
+
+fail:
+   if (output_hwc) E_FREE(output_hwc);
+
+   return NULL;
 }
 
 EINTERN void
@@ -633,6 +49,9 @@ e_output_hwc_del(E_Output_Hwc *output_hwc)
 {
    if (!output_hwc) return;
 
+   if (output_hwc->hwc_policy == E_OUTPUT_HWC_POLICY_PLANES)
+      e_output_hwc_planes_deinit();
+
    E_FREE(output_hwc);
 }
 
@@ -641,24 +60,28 @@ e_output_hwc_apply(E_Output_Hwc *output_hwc)
 {
    EINA_SAFETY_ON_NULL_RETURN(output_hwc);
    EINA_SAFETY_ON_NULL_RETURN(output_hwc->output);
+   if (e_output_hwc_policy_get(output_hwc) == E_OUTPUT_HWC_POLICY_NONE) return;
 
-   if (e_output_hwc_deactive_get(output_hwc))
+   if (e_output_hwc_policy_get(output_hwc) == E_OUTPUT_HWC_POLICY_PLANES)
      {
-        if (output_hwc->hwc_mode != E_OUTPUT_HWC_MODE_NONE)
-          e_output_hwc_planes_end(output_hwc, "deactive set.");
-        return;
-     }
+        if (e_output_hwc_deactive_get(output_hwc))
+          {
+             if (output_hwc->hwc_mode != E_OUTPUT_HWC_MODE_NONE)
+               e_output_hwc_planes_end(output_hwc, "deactive set.");
+             return;
+          }
 
-   if (!_e_output_hwc_planes_usable(output_hwc))
-     {
-        e_output_hwc_planes_end(output_hwc, __FUNCTION__);
-        return;
-     }
+        if (!e_output_hwc_planes_usable(output_hwc))
+          {
+             e_output_hwc_planes_end(output_hwc, __FUNCTION__);
+             return;
+          }
 
-   if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_NONE)
-     _e_output_hwc_planes_begin(output_hwc);
-   else
-     _e_output_hwc_planes_changed(output_hwc);
+        if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_NONE)
+          e_output_hwc_planes_begin(output_hwc);
+        else
+          e_output_hwc_planes_changed(output_hwc);
+     }
 }
 
 EINTERN E_Output_Hwc_Mode
@@ -694,50 +117,4 @@ e_output_hwc_deactive_get(E_Output_Hwc *output_hwc)
    EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, EINA_FALSE);
 
    return output_hwc->hwc_deactive;
-}
-
-EINTERN void
-e_output_hwc_planes_multi_plane_set(E_Output_Hwc *output_hwc, Eina_Bool set)
-{
-   EINA_SAFETY_ON_NULL_RETURN(output_hwc);
-
-   e_output_hwc_planes_end(output_hwc, __FUNCTION__);
-   output_hwc->hwc_use_multi_plane = set;
-
-   ELOGF("HWC", "e_output_hwc_planes_multi_plane_set : %d", NULL, NULL, set);
-}
-
-EINTERN Eina_Bool
-e_output_hwc_planes_multi_plane_get(E_Output_Hwc *output_hwc)
-{
-   EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, EINA_FALSE);
-
-   return output_hwc->hwc_use_multi_plane;
-}
-
-EINTERN void
-e_output_hwc_planes_end(E_Output_Hwc *output_hwc, const char *location)
-{
-   E_Output_Hwc_Mode new_mode = E_OUTPUT_HWC_MODE_NONE;
-
-   EINA_SAFETY_ON_NULL_RETURN(output_hwc);
-
-   /* clean the reserved planes(clean the candidate ecs) */
-   _e_output_hwc_planes_reserved_clean(output_hwc);
-
-   if (!output_hwc->hwc_mode) return;
-
-   /* set null to the e_planes */
-   _e_output_hwc_planes_cancel(output_hwc);
-
-   /* check the current mode */
-   new_mode = _e_output_hwc_mode_get(output_hwc);
-
-   if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_FULL &&
-       new_mode != E_OUTPUT_HWC_MODE_FULL)
-     ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
-
-   output_hwc->hwc_mode = new_mode;
-
-   ELOGF("HWC", " End...  at %s.", NULL, NULL, location);
 }
\ No newline at end of file
index 437299a8c9aba9b49d0d869c573c754c88536c64..a677f59c474ef72f1f4560ff1254281125a1bd35 100644 (file)
@@ -22,11 +22,13 @@ typedef enum _E_Output_Hwc_Policy
 
 struct _E_Output_Hwc
 {
-   E_Output          *output;
+   E_Output            *output;
 
    E_Output_Hwc_Policy  hwc_policy;
-   E_Output_Hwc_Mode  hwc_mode;
-   Eina_Bool          hwc_deactive : 1; // deactive hwc policy
+   E_Output_Hwc_Mode    hwc_mode;
+   Eina_Bool            hwc_deactive : 1; // deactive hwc policy
+
+   /* variables for hwc_planes polic  */
    Eina_Bool          hwc_use_multi_plane;
 };
 
@@ -35,13 +37,8 @@ EINTERN void                 e_output_hwc_del(E_Output_Hwc *output_hwc);
 EINTERN void                 e_output_hwc_apply(E_Output_Hwc *output_hwc);
 EINTERN E_Output_Hwc_Policy  e_output_hwc_policy_get(E_Output_Hwc *output_hwc);
 EINTERN E_Output_Hwc_Mode    e_output_hwc_mode_get(E_Output_Hwc *output_hwc);
-
-EINTERN void               e_output_hwc_deactive_set(E_Output_Hwc *output_hwc, Eina_Bool set);
-EINTERN Eina_Bool          e_output_hwc_deactive_get(E_Output_Hwc *output_hwc);
-EINTERN void               e_output_hwc_planes_multi_plane_set(E_Output_Hwc *output_hwc, Eina_Bool set);
-EINTERN Eina_Bool          e_output_hwc_planes_multi_plane_get(E_Output_Hwc *output_hwc);
-
-EINTERN void               e_output_hwc_planes_end(E_Output_Hwc *output_hwc, const char *location);
+EINTERN void                 e_output_hwc_deactive_set(E_Output_Hwc *output_hwc, Eina_Bool set);
+EINTERN Eina_Bool            e_output_hwc_deactive_get(E_Output_Hwc *output_hwc);
 
 #endif
 #endif
diff --git a/src/bin/e_output_hwc_planes.c b/src/bin/e_output_hwc_planes.c
new file mode 100644 (file)
index 0000000..8ca86dd
--- /dev/null
@@ -0,0 +1,656 @@
+#include "e.h"
+#include "services/e_service_quickpanel.h"
+
+EINTERN Eina_Bool
+e_output_hwc_planes_init(void)
+{
+   return EINA_TRUE;
+}
+
+EINTERN void
+e_output_hwc_planes_deinit(void)
+{
+   // TODO:
+   ;;;
+}
+
+static Eina_Bool
+_e_output_hwc_planes_ec_check(E_Client *ec)
+{
+   E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+   E_Output *eout;
+   int minw = 0, minh = 0;
+
+   if ((!cdata) ||
+       (!cdata->buffer_ref.buffer) ||
+       (cdata->width_from_buffer != cdata->width_from_viewport) ||
+       (cdata->height_from_buffer != cdata->height_from_viewport) ||
+       cdata->never_hwc)
+     {
+        return EINA_FALSE;
+     }
+
+   if (e_client_transform_core_enable_get(ec)) return EINA_FALSE;
+
+   switch (cdata->buffer_ref.buffer->type)
+     {
+      case E_COMP_WL_BUFFER_TYPE_NATIVE:
+         break;
+      case E_COMP_WL_BUFFER_TYPE_TBM:
+         if (cdata->buffer_ref.buffer->resource)
+           break;
+      case E_COMP_WL_BUFFER_TYPE_SHM:
+         if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role))
+           break;
+      default:
+         return EINA_FALSE;
+     }
+
+   eout = e_output_find(ec->zone->output_id);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
+
+   tdm_output_get_available_size(eout->toutput, &minw, &minh, NULL, NULL, NULL);
+
+   if ((minw > 0) && (minw > cdata->buffer_ref.buffer->w))
+     return EINA_FALSE;
+   if ((minh > 0) && (minh > cdata->buffer_ref.buffer->h))
+     return EINA_FALSE;
+
+   /* If a client doesn't watch the ignore_output_transform events, we can't show
+    * a client buffer to HW overlay directly when the buffer transform is not same
+    * with output transform. If a client watch the ignore_output_transform events,
+    * we can control client's buffer transform. In this case, we don't need to
+    * check client's buffer transform here.
+    */
+   if (!e_comp_screen_rotation_ignore_output_transform_watch(ec))
+     {
+        int transform = e_comp_wl_output_buffer_transform_get(ec);
+
+        if ((eout->config.rotation / 90) != transform)
+          return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_e_output_hwc_planes_prepare_init(E_Output_Hwc *output_hwc)
+{
+   const Eina_List *ep_l = NULL, *l ;
+   E_Plane *ep = NULL;
+   E_Output *eout = output_hwc->output;
+
+   EINA_SAFETY_ON_NULL_RETURN(output_hwc);
+
+   ep_l = e_output_planes_get(eout);
+   EINA_LIST_FOREACH(ep_l, l, ep)
+     {
+        if (!output_hwc->hwc_use_multi_plane &&
+            !e_plane_is_cursor(ep) &&
+            !e_plane_is_fb_target(ep))
+          continue;
+
+        e_plane_ec_prepare_set(ep, NULL);
+     }
+}
+
+static int
+_e_output_hwc_planes_prepare_cursor(E_Output *eout, int n_cur, Eina_List *hwc_clist)
+{
+   // policy for cursor layer
+   const Eina_List *ep_l = NULL, *l ;
+   Eina_List *cur_ly = NULL;
+   E_Plane *ep = NULL;
+   int n_skip = 0;
+   int n_curly = 0;
+   int nouse = 0;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_clist, EINA_FALSE);
+
+   // list up cursor only layers
+   ep_l = e_output_planes_get(eout);
+   EINA_LIST_FOREACH(ep_l, l, ep)
+     {
+        if (e_plane_is_cursor(ep))
+          {
+             cur_ly = eina_list_append(cur_ly, ep);
+             continue;
+          }
+     }
+
+   if (!cur_ly) return 0;
+   n_curly = eina_list_count(cur_ly);
+
+   if (n_cur > 0 && n_curly > 0)
+     {
+        if (n_cur >= n_curly) nouse = 0;
+        else nouse = n_curly - n_cur;
+
+        //assign cursor on cursor only layers
+        EINA_LIST_REVERSE_FOREACH(cur_ly, l, ep)
+          {
+             E_Client *ec = NULL;
+             if (nouse > 0)
+               {
+                  nouse--;
+                  continue;
+               }
+             if (hwc_clist) ec = eina_list_data_get(hwc_clist);
+             if (ec && e_plane_ec_prepare_set(ep, ec))
+               {
+                  n_skip += 1;
+                  hwc_clist = eina_list_next(hwc_clist);
+               }
+          }
+     }
+
+   eina_list_free(cur_ly);
+
+   return n_skip;
+}
+
+static Eina_Bool
+_e_output_hwc_planes_prepare_plane(E_Output_Hwc *output_hwc, int n_vis, int n_skip, Eina_List *hwc_clist)
+{
+   const Eina_List *ep_l = NULL, *l ;
+   Eina_List *hwc_ly = NULL;
+   E_Plane *ep = NULL, *ep_fb = NULL;
+   int n_ly = 0, n_ec = 0;
+   E_Client *ec = NULL;
+   Eina_Bool ret = EINA_FALSE;
+   int nouse = 0;
+   E_Output *eout = output_hwc->output;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_clist, EINA_FALSE);
+
+   n_ec = eina_list_count(hwc_clist);
+   if (n_skip > 0)
+     {
+        int i;
+        for (i = 0; i < n_skip; i++)
+          hwc_clist = eina_list_next(hwc_clist);
+
+        n_ec -= n_skip;
+        n_vis -= n_skip;
+     }
+
+   if (n_ec <= 0) return EINA_FALSE;
+
+   // list up available_hw layers E_Client can be set
+   // if e_comp->hwc_use_multi_plane FALSE, than use only fb target plane
+   ep_l = e_output_planes_get(eout);
+   EINA_LIST_FOREACH(ep_l, l, ep)
+     {
+        if (!ep_fb)
+          {
+             if (e_plane_is_fb_target(ep))
+               {
+                  ep_fb = ep;
+                  hwc_ly = eina_list_append(hwc_ly, ep);
+               }
+             continue;
+          }
+        if (!output_hwc->hwc_use_multi_plane) continue;
+        if (e_plane_is_cursor(ep)) continue;
+        if (ep->zpos > ep_fb->zpos)
+          hwc_ly = eina_list_append(hwc_ly, ep);
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hwc_ly, EINA_FALSE);
+
+   // finally, assign client on available_hw layers
+   n_ly = eina_list_count(hwc_ly);
+   if ((n_ec == n_vis) &&
+       (n_ec <= n_ly)) // fully hwc
+     {
+        nouse = n_ly - n_ec;
+     }
+   else if ((n_ly < n_vis) || // e_comp->evas on fb target plane
+            (n_ec < n_vis))
+     {
+        if (n_ec <= n_ly) nouse = n_ly - n_ec - 1;
+        else nouse = 0;
+     }
+
+   EINA_LIST_REVERSE_FOREACH(hwc_ly, l, ep)
+     {
+        ec = NULL;
+        if (nouse > 0)
+          {
+             nouse--;
+             continue;
+          }
+        if (hwc_clist) ec = eina_list_data_get(hwc_clist);
+        if (ec && e_plane_ec_prepare_set(ep, ec))
+          {
+             ret = EINA_TRUE;
+
+             hwc_clist = eina_list_next(hwc_clist);
+             n_ec--; n_vis--;
+          }
+        if (e_plane_is_fb_target(ep))
+          {
+             if (n_ec > 0 || n_vis > 0) e_plane_ec_prepare_set(ep, NULL);
+             break;
+          }
+     }
+
+   eina_list_free(hwc_ly);
+
+   return ret;
+}
+
+static void
+_e_output_hwc_planes_cancel(E_Output_Hwc *output_hwc)
+{
+   Eina_List *l ;
+   E_Plane *ep;
+   E_Output *eout = output_hwc->output;
+
+   EINA_LIST_FOREACH(eout->planes, l, ep)
+     {
+        if (!output_hwc->hwc_use_multi_plane &&
+            !e_plane_is_cursor(ep) &&
+            !e_plane_is_fb_target(ep))
+             continue;
+
+        e_plane_ec_prepare_set(ep, NULL);
+        e_plane_ec_set(ep, NULL);
+     }
+}
+
+static Eina_Bool
+_e_output_hwc_planes_reserved_clean(E_Output_Hwc *output_hwc)
+{
+   Eina_List *l;
+   E_Plane *ep;
+   E_Output *eout = output_hwc->output;
+
+   EINA_LIST_FOREACH(eout->planes, l, ep)
+     {
+        if (!output_hwc->hwc_use_multi_plane &&
+            !e_plane_is_cursor(ep) &&
+            !e_plane_is_fb_target(ep))
+          continue;
+
+        if (e_plane_is_reserved(ep))
+            e_plane_reserved_set(ep, 0);
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_e_output_hwc_planes_unset(E_Plane *ep)
+{
+   if (e_plane_is_reserved(ep))
+     e_plane_reserved_set(ep, 0);
+
+   e_plane_ec_prepare_set(ep, NULL);
+   e_plane_ec_set(ep, NULL);
+
+   ELOGF("HWC", "unset plane %d to NULL", NULL, NULL, ep->zpos);
+}
+
+static Eina_Bool
+_e_output_hwc_planes_change_ec(E_Plane *ep, E_Client *new_ec)
+{
+   if (!e_plane_ec_set(ep, new_ec))
+     {
+        ELOGF("HWC", "failed to set new_ec(%s) on %d",
+              NULL, new_ec,
+              new_ec ? (new_ec->icccm.name ? new_ec->icccm.name : "no name") : "NULL",
+              ep->zpos);
+        return EINA_FALSE;
+     }
+
+   if (new_ec)
+     ELOGF("HWC", "new_ec(%s) is set on %d",
+           new_ec->pixmap, new_ec,
+           e_client_util_name_get(new_ec) ? new_ec->icccm.name : "no name", ep->zpos);
+   else
+     ELOGF("HWC", "NULL is set on %d", NULL, NULL, ep->zpos);
+
+   return EINA_TRUE;
+}
+
+EINTERN void
+e_output_hwc_planes_changed(E_Output_Hwc *output_hwc)
+{
+   Eina_Bool ret = EINA_FALSE;
+   E_Plane *ep = NULL;
+   const Eina_List *ep_l = NULL, *p_l;
+   Eina_Bool assign_success = EINA_TRUE;
+   int mode = E_OUTPUT_HWC_MODE_NONE;
+   E_Output *eout = output_hwc->output;
+
+   ep_l = e_output_planes_get(eout);
+   /* check the planes from top to down */
+   EINA_LIST_REVERSE_FOREACH(ep_l, p_l, ep)
+     {
+        if (!assign_success)
+          {
+             //unset planes from 'assign_success' became EINA_FALSE to the fb target
+             _e_output_hwc_planes_unset(ep);
+             continue;
+          }
+
+        if (e_plane_is_reserved(ep) &&
+            ep->prepare_ec == NULL)
+          {
+             e_plane_reserved_set(ep, 0);
+             ELOGF("HWC", "unset reserved mem on %d", NULL, NULL, ep->zpos);
+          }
+
+        if (ep->ec != ep->prepare_ec)
+          {
+             assign_success = _e_output_hwc_planes_change_ec(ep, ep->prepare_ec);
+             ret = EINA_TRUE;
+          }
+
+        if (ep->ec) mode = E_OUTPUT_HWC_MODE_HYBRID;
+
+        if (e_plane_is_fb_target(ep))
+          {
+             if (ep->ec) mode = E_OUTPUT_HWC_MODE_FULL;
+             break;
+          }
+   }
+
+   if (output_hwc->hwc_mode != mode)
+     {
+        ELOGF("HWC", "mode changed (from %d to %d) due to surface changes",
+              NULL, NULL,
+              output_hwc->hwc_mode, mode);
+
+        if (mode == E_OUTPUT_HWC_MODE_FULL)
+          {
+             // fb target is occupied by a client surface, means compositor disabled
+             ecore_event_add(E_EVENT_COMPOSITOR_DISABLE, NULL, NULL, NULL);
+          }
+        else if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_FULL)
+          {
+             // fb target is occupied by a client surface, means compositor disabled
+             ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
+          }
+
+        output_hwc->hwc_mode = mode;
+     }
+
+   if (ret)
+     {
+        if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_NONE)
+          ELOGF("HWC", " End...  due to surface changes", NULL, NULL);
+        else
+          ELOGF("HWC", " hwc surface changed", NULL, NULL);
+     }
+}
+
+static Eina_Bool
+_e_output_hwc_planes_prepare(E_Output_Hwc *output_hwc, E_Zone *zone)
+{
+   Eina_List *vl;
+   Eina_Bool ret = EINA_FALSE;
+   E_Client *ec;
+   int n_vis = 0, n_ec = 0, n_cur = 0, n_skip = 0;
+   Eina_List *hwc_ok_clist = NULL, *vis_clist = NULL;
+   E_Output *output = output_hwc->output;
+
+   vis_clist = e_comp_vis_ec_list_get(zone);
+   if (!vis_clist) return EINA_FALSE;
+
+   // check clients not able to use hwc
+   EINA_LIST_FOREACH(vis_clist, vl, ec)
+     {
+        // if there is a ec which is lower than quickpanel and quickpanel is opened.
+        if (E_POLICY_QUICKPANEL_LAYER >= evas_object_layer_get(ec->frame))
+          {
+             // check whether quickpanel is open than break
+             if (e_qp_visible_get()) goto done;
+          }
+
+        // if ec->frame is not for client buffer (e.g. launchscreen)
+        if (e_comp_object_content_type_get(ec->frame) != E_COMP_OBJECT_CONTENT_TYPE_INT_IMAGE)
+           goto done;
+
+        // if there is UI subfrace, it means need to composite
+        if (e_client_normal_client_has(ec))
+           goto done;
+
+        // if ec has invalid buffer or scaled( transformed ) or forced composite(never_hwc)
+        if (!_e_output_hwc_planes_ec_check(ec))
+          {
+             if (!n_ec) goto done;
+             break;
+          }
+
+        // listup as many as possible from the top most visible order
+        n_ec++;
+        if (!e_util_strcmp("wl_pointer-cursor", ec->icccm.window_role)) n_cur++;
+        hwc_ok_clist = eina_list_append(hwc_ok_clist, ec);
+     }
+
+   n_vis = eina_list_count(vis_clist);
+   if ((n_vis < 1) || (n_ec < 1))
+     goto done;
+
+   _e_output_hwc_planes_prepare_init(output_hwc);
+
+   if (n_cur >= 1)
+     n_skip = _e_output_hwc_planes_prepare_cursor(output, n_cur, hwc_ok_clist);
+
+   if (n_skip > 0) ret = EINA_TRUE;
+
+   ret |= _e_output_hwc_planes_prepare_plane(output_hwc, n_vis, n_skip, hwc_ok_clist);
+
+done:
+   eina_list_free(hwc_ok_clist);
+   eina_list_free(vis_clist);
+
+   return ret;
+}
+
+EINTERN Eina_Bool
+e_output_hwc_planes_usable(E_Output_Hwc *output_hwc)
+{
+   E_Output *eout = output_hwc->output;
+   E_Comp_Wl_Buffer *buffer = NULL;
+   E_Zone *zone = NULL;
+   int bw = 0, bh = 0;
+   Eina_Bool all_null = EINA_TRUE;
+   E_Plane *ep = NULL;
+   const Eina_List *ep_l = NULL, *p_l;
+
+   zone = e_comp_zone_find(e_output_output_id_get(eout));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(zone, EINA_FALSE);
+
+   // check whether to use hwc and prepare the core assignment policy
+   if (!_e_output_hwc_planes_prepare(output_hwc, zone)) return EINA_FALSE;
+
+   // extra policy can replace core policy
+   e_comp_hook_call(E_COMP_HOOK_PREPARE_PLANE, NULL);
+
+   // It is not hwc_usable if cursor is shown when the hw cursor is not supported by libtdm.
+   if (!e_pointer_is_hidden(e_comp->pointer) &&
+       (eout->cursor_available.max_w == -1 || eout->cursor_available.max_h == -1))
+     return EINA_FALSE;
+
+   // check the hwc is avaliable.
+   ep_l = e_output_planes_get(eout);
+   EINA_LIST_FOREACH(ep_l, p_l, ep)
+     {
+        if (!ep->prepare_ec) continue;
+
+        // It is not hwc_usable if attached buffer is not valid.
+        buffer = e_pixmap_resource_get(ep->prepare_ec->pixmap);
+        if (!buffer) return EINA_FALSE;
+
+        if (e_plane_is_fb_target(ep))
+          {
+             // It is not hwc_usable if the geometry of the prepare_ec at the ep_fb is not proper.
+             e_pixmap_size_get(ep->prepare_ec->pixmap, &bw, &bh);
+
+             // if client and zone's geometry is not match with, or
+             // if plane with reserved_memory(esp. fb target) has assigned smaller buffer,
+             // won't support hwc properly, than let's composite
+             if (ep->reserved_memory &&
+                 ((bw != zone->w) || (bh != zone->h) ||
+                 (ep->prepare_ec->x != zone->x) || (ep->prepare_ec->y != zone->y) ||
+                 (ep->prepare_ec->w != zone->w) || (ep->prepare_ec->h != zone->h)))
+               {
+                  DBG("Cannot use HWC if geometry is not 1 on 1 match with reserved_memory");
+                  return EINA_FALSE;
+               }
+          }
+
+        all_null = EINA_FALSE;
+        break;
+     }
+
+   // It is not hwc_usable if the all prepare_ec in every plane are null
+   if (all_null) return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_output_hwc_planes_can_hwcompose(E_Output *eout)
+{
+   const Eina_List *ep_l = NULL, *l;
+   E_Plane *ep = NULL, *ep_fb = NULL;
+
+   ep_l = e_output_planes_get(eout);
+   /* check the planes from down to top */
+   EINA_LIST_FOREACH(ep_l, l, ep)
+     {
+        if (e_plane_is_fb_target(ep))
+          {
+             /* can hwcompose if fb_target has a ec. */
+             if (ep->prepare_ec != NULL) return EINA_TRUE;
+             else ep_fb = ep;
+          }
+        else
+          {
+             /* can hwcompose if ep has a ec and zpos is higher than ep_fb */
+             if (ep->prepare_ec != NULL &&
+                 ep_fb &&
+                 ep->zpos > ep_fb->zpos)
+               return EINA_TRUE;
+          }
+     }
+
+   return EINA_FALSE;
+}
+
+EINTERN void
+e_output_hwc_planes_begin(E_Output_Hwc *output_hwc)
+{
+   const Eina_List *ep_l = NULL, *l;
+   E_Output *eout = output_hwc->output;
+   E_Plane *ep = NULL;
+   E_Output_Hwc_Mode mode = E_OUTPUT_HWC_MODE_NONE;
+   Eina_Bool set = EINA_FALSE;
+
+   if (e_comp->nocomp_override > 0) return;
+
+   if (_e_output_hwc_planes_can_hwcompose(eout))
+     {
+        ep_l = e_output_planes_get(eout);
+
+        /* set the prepare_ec to the e_plane */
+        /* check the planes from top to down */
+        EINA_LIST_REVERSE_FOREACH(ep_l, l , ep)
+          {
+             if (!ep->prepare_ec) continue;
+
+             set = e_plane_ec_set(ep, ep->prepare_ec);
+             if (!set) break;
+
+             if (e_plane_is_fb_target(ep))
+               {
+                  ELOGF("HWC", "is set on fb_target( %d)", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
+                  mode = E_OUTPUT_HWC_MODE_FULL;
+
+                  // fb target is occupied by a client surface, means compositor disabled
+                  ecore_event_add(E_EVENT_COMPOSITOR_DISABLE, NULL, NULL, NULL);
+               }
+             else
+               {
+                  ELOGF("HWC", "is set on %d", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
+                  mode = E_OUTPUT_HWC_MODE_HYBRID;
+               }
+          }
+
+        if (mode == E_OUTPUT_HWC_MODE_NONE)
+           ELOGF("HWC", " Begin is not available yet ...", NULL, NULL);
+        else
+           ELOGF("HWC", " Begin ...", NULL, NULL);
+     }
+
+   output_hwc->hwc_mode = mode;
+}
+
+static E_Output_Hwc_Mode
+_e_output_hwc_mode_get(E_Output_Hwc *output_hwc)
+{
+   const Eina_List *ll = NULL, *l;
+   E_Output *output = output_hwc->output;
+   E_Plane *plane = NULL;
+
+   /* check the planes from down to top */
+   EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane)
+     {
+        if (!plane->ec) continue;
+        if (e_plane_is_fb_target(plane)) return E_OUTPUT_HWC_MODE_FULL;
+
+        return E_OUTPUT_HWC_MODE_HYBRID;
+     }
+
+   return E_OUTPUT_HWC_MODE_NONE;
+}
+
+EINTERN void
+e_output_hwc_planes_multi_plane_set(E_Output_Hwc *output_hwc, Eina_Bool set)
+{
+   EINA_SAFETY_ON_NULL_RETURN(output_hwc);
+
+   e_output_hwc_planes_end(output_hwc, __FUNCTION__);
+   output_hwc->hwc_use_multi_plane = set;
+
+   ELOGF("HWC", "e_output_hwc_planes_multi_plane_set : %d", NULL, NULL, set);
+}
+
+EINTERN Eina_Bool
+e_output_hwc_planes_multi_plane_get(E_Output_Hwc *output_hwc)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, EINA_FALSE);
+
+   return output_hwc->hwc_use_multi_plane;
+}
+
+EINTERN void
+e_output_hwc_planes_end(E_Output_Hwc *output_hwc, const char *location)
+{
+   E_Output_Hwc_Mode new_mode = E_OUTPUT_HWC_MODE_NONE;
+
+   EINA_SAFETY_ON_NULL_RETURN(output_hwc);
+
+   /* clean the reserved planes(clean the candidate ecs) */
+   _e_output_hwc_planes_reserved_clean(output_hwc);
+
+   if (!output_hwc->hwc_mode) return;
+
+   /* set null to the e_planes */
+   _e_output_hwc_planes_cancel(output_hwc);
+
+   /* check the current mode */
+   new_mode = _e_output_hwc_mode_get(output_hwc);
+
+   if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_FULL &&
+       new_mode != E_OUTPUT_HWC_MODE_FULL)
+     ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
+
+   output_hwc->hwc_mode = new_mode;
+
+   ELOGF("HWC", " End...  at %s.", NULL, NULL, location);
+}
diff --git a/src/bin/e_output_hwc_planes.h b/src/bin/e_output_hwc_planes.h
new file mode 100644 (file)
index 0000000..0430299
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef E_TYPEDEFS
+#else
+#ifndef E_OUTPUT_HWC_PLANES_H
+#define E_OUTPUT_HWC_PLANES_H
+
+/* used by e_output_hwc */
+EINTERN Eina_Bool            e_output_hwc_planes_init(void);
+EINTERN void                 e_output_hwc_planes_deinit(void);
+
+EINTERN Eina_Bool            e_output_hwc_planes_usable(E_Output_Hwc *output_hwc);
+EINTERN void                 e_output_hwc_planes_begin(E_Output_Hwc *output_hwc);
+EINTERN void                 e_output_hwc_planes_end(E_Output_Hwc *output_hwc, const char *location);
+EINTERN void                 e_output_hwc_planes_changed(E_Output_Hwc *output_hwc);
+
+EINTERN void                 e_output_hwc_planes_multi_plane_set(E_Output_Hwc *output_hwc, Eina_Bool set);
+EINTERN Eina_Bool            e_output_hwc_planes_multi_plane_get(E_Output_Hwc *output_hwc);
+
+#endif
+#endif