The hwc policy applys to each E_Output.
The hwc policy is decided in the idle enterer instead of in the job handler(_e_comp_update_cb).
Therefore, e20 can decide the hwc policy without calling e_comp_redner_queue() when the e20 enters the idle.
Change-Id: I835bae1dd931d9ce157c3944bf6e0151764ab9ca
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_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 \
[E_COMP_HOOK_PREPARE_PLANE] = NULL,
};
-typedef enum _E_Comp_HWC_Mode
-{
- E_HWC_MODE_NO = 0,
- E_HWC_MODE_HYBRID,
- E_HWC_MODE_FULL
-} E_Comp_HWC_Mode;
-
E_API int E_EVENT_COMPOSITOR_RESIZE = -1;
E_API int E_EVENT_COMPOSITOR_DISABLE = -1;
E_API int E_EVENT_COMPOSITOR_ENABLE = -1;
}
}
-#ifdef ENABLE_HWC_MULTI
static void
_e_comp_hooks_clean(void)
{
}
}
-static void
-_e_comp_hook_call(E_Comp_Hook_Point hookpoint, void *data EINA_UNUSED)
+EINTERN void
+e_comp_hook_call(E_Comp_Hook_Point hookpoint, void *data EINA_UNUSED)
{
E_Comp_Hook *ch;
_e_comp_hooks_clean();
}
-static int
-_hwc_set(E_Output *eout)
-{
- const Eina_List *ep_l = NULL, *l;
- E_Plane *ep = NULL;
- E_Comp_HWC_Mode mode = E_HWC_MODE_NO;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
- EINA_SAFETY_ON_NULL_RETURN_VAL(eout->planes, EINA_FALSE);
-
- ep_l = e_output_planes_get(eout);
- EINA_LIST_REVERSE_FOREACH(ep_l, l , ep)
- {
- Eina_Bool set = EINA_FALSE;
-
- if (e_plane_is_fb_target(ep))
- {
- if (ep->prepare_ec)
- {
- set = e_plane_ec_set(ep, ep->prepare_ec);
- if (set)
- {
- ELOGF("HWC", "is set on fb_target( %d)", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
- mode = E_HWC_MODE_FULL;
-
- // fb target is occupied by a client surface, means compositor disabled
- ecore_event_add(E_EVENT_COMPOSITOR_DISABLE, NULL, NULL, NULL);
- }
- break;
- }
- }
- else if (ep->prepare_ec)
- {
- set = e_plane_ec_set(ep, ep->prepare_ec);
- if (set)
- {
- ELOGF("HWC", "is set on %d", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
- mode |= E_HWC_MODE_HYBRID;
- }
- else
- break;
- }
- }
-
- return mode;
-}
-
-static Eina_Bool
-_hwc_available_get(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;
- }
-
- if (e_comp_wl_tbm_buffer_sync_timeline_used(cdata->buffer_ref.buffer))
- 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
-_hwc_prepare_init(E_Output *eout)
-{
- const Eina_List *ep_l = NULL, *l ;
- E_Plane *ep = NULL;
-
- ep_l = e_output_planes_get(eout);
- EINA_LIST_FOREACH(ep_l, l, ep)
- {
- if (!e_comp->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
-_hwc_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
-_hwc_prepare(E_Output *eout, 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;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
- 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 (!e_comp->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 Eina_Bool
-_hwc_cancel(E_Output *eout)
-{
- Eina_List *l ;
- E_Plane *ep;
- Eina_Bool ret = EINA_TRUE;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
- EINA_SAFETY_ON_NULL_RETURN_VAL(eout->planes, EINA_FALSE);
-
- EINA_LIST_FOREACH(eout->planes, l, ep)
- {
- if (!e_comp->hwc_use_multi_plane &&
- !e_plane_is_cursor(ep) &&
- !e_plane_is_fb_target(ep))
- {
- if (ep->ec) ret = EINA_FALSE; // core cannot end HWC
- continue;
- }
-
- e_plane_ec_prepare_set(ep, NULL);
- e_plane_ec_set(ep, NULL);
- }
-
- return ret;
-}
-
-static Eina_Bool
-_hwc_reserved_clean()
-{
- Eina_List *l, *ll;
- E_Zone *zone;
- E_Plane *ep;
-
- EINA_LIST_FOREACH(e_comp->zones, l, zone)
- {
- E_Output * eout;
- if (!zone->output_id) continue;
- eout = e_output_find(zone->output_id);
- if (!eout) continue;;
- EINA_LIST_FOREACH(eout->planes, ll, ep)
- {
- if (!e_comp->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
-_hwc_plane_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
-_hwc_plane_change_ec(E_Plane *ep, E_Client *old_ec, E_Client *new_ec)
-{
- Eina_Bool ret = EINA_FALSE;
-
- if (!new_ec)
- {
- if (e_plane_is_reserved(ep))
- e_plane_reserved_set(ep, 0);
- }
-
- e_plane_ec_prepare_set(ep, NULL);
-
- if (e_plane_ec_set(ep, new_ec))
- {
- 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);
- }
- ret = EINA_TRUE;
- }
- else
- {
- 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 ret;
-}
-
-static Eina_Bool
-_e_comp_hwc_apply(E_Output * eout)
-{
- const Eina_List *ep_l = NULL, *l;
- E_Plane *ep = NULL, *ep_fb = NULL;
- int mode = 0;
-
- 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;
- if (ep->prepare_ec != NULL) goto hwcompose;
- }
- continue;
- }
- if (ep->zpos > ep_fb->zpos)
- if (ep->prepare_ec != NULL) goto hwcompose;
- }
-
- goto compose;
-
-hwcompose:
- mode = _hwc_set(eout);
- if (mode == E_HWC_MODE_NO) ELOGF("HWC", "it is failed to assign surface on plane", NULL, NULL);
-
-compose:
- if (mode != E_HWC_MODE_NO) e_comp->hwc_mode = mode;
-
- return !!mode;
-}
-
-static Eina_Bool
-_e_comp_hwc_changed(void)
-{
- Eina_List *l;
- E_Zone *zone;
- Eina_Bool ret = EINA_FALSE;
-
- EINA_LIST_FOREACH(e_comp->zones, l, zone)
- {
- E_Output *eout = NULL;
- E_Plane *ep = NULL;
- const Eina_List *ep_l = NULL, *p_l;
- Eina_Bool assign_success = EINA_TRUE;
- int mode = E_HWC_MODE_NO;
-
- if (!zone || !zone->output_id) continue;
-
- eout = e_output_find(zone->output_id);
- if (!eout) continue;
- ep_l = e_output_planes_get(eout);
- EINA_LIST_REVERSE_FOREACH(ep_l, p_l, ep)
- {
- if (!assign_success)
- {
- //unset planes from 'assign_success' became EINA_FALSE to the fb target
- _hwc_plane_unset(ep);
- continue;
- }
-
- if (ep->ec != ep->prepare_ec)
- {
- assign_success = _hwc_plane_change_ec(ep, ep->ec, ep->prepare_ec);
- ret = EINA_TRUE;
- }
- else if (!ep->prepare_ec)
- {
- if (e_plane_is_reserved(ep))
- {
- e_plane_reserved_set(ep, 0);
- ELOGF("HWC", "unset reserved mem on %d", NULL, NULL, ep->zpos);
- }
- }
-
- if (ep->ec) mode = E_HWC_MODE_HYBRID;
-
- if (e_plane_is_fb_target(ep))
- {
- if (ep->ec) mode = E_HWC_MODE_FULL;
- break;
- }
- }
-
- if (e_comp->hwc_mode != mode)
- {
- ELOGF("HWC", "mode changed (from %d to %d) due to surface changes",
- NULL, NULL,
- e_comp->hwc_mode, mode);
-
- if (mode == E_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 (e_comp->hwc_mode == E_HWC_MODE_FULL)
- {
- // fb target is occupied by a client surface, means compositor disabled
- ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
- }
-
- e_comp->hwc_mode = mode;
- }
- }
-
- return ret;
-}
-
-static Eina_Bool
-_e_comp_hwc_prepare(void)
-{
- Eina_List *l, *vl;
- E_Zone *zone;
- Eina_Bool ret = EINA_FALSE;
-
- EINA_SAFETY_ON_FALSE_RETURN_VAL(e_comp->hwc, EINA_FALSE);
-
- EINA_LIST_FOREACH(e_comp->zones, l, zone)
- {
- E_Client *ec;
- E_Output *output;
- int n_vis = 0, n_ec = 0, n_cur = 0, n_skip = 0;
- Eina_List *hwc_ok_clist = NULL, *vis_clist = NULL;
-
- if (!zone || !zone->output_id) continue; // no hw layer
-
- output = e_output_find(zone->output_id);
- if (!output) continue;
-
- vis_clist = e_comp_vis_ec_list_get(zone);
- if (!vis_clist) continue;
-
- EINA_LIST_FOREACH(vis_clist, vl, ec)
- {
- // check clients not able to use hwc
- if (E_POLICY_QUICKPANEL_LAYER >= evas_object_layer_get(ec->frame))
- {
- // check whether quickpanel is open than break
- if (e_qp_visible_get()) break;
- }
-
- // 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 nextzone;
-
- // if there is UI subfrace, it means need to composite
- if (e_client_normal_client_has(ec))
- goto nextzone;
-
- // if ec has invalid buffer or scaled( transformed ) or forced composite(never_hwc)
- if (!_hwc_available_get(ec))
- {
- if (!n_ec) goto nextzone;
- 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 nextzone;
-
- _hwc_prepare_init(output);
-
- if (n_cur >= 1)
- n_skip = _hwc_prepare_cursor(output, n_cur, hwc_ok_clist);
-
- if (n_skip > 0) ret = EINA_TRUE;
-
- ret |= _hwc_prepare(output, n_vis, n_skip, hwc_ok_clist);
-
- nextzone:
- eina_list_free(hwc_ok_clist);
- eina_list_free(vis_clist);
- }
-
- return ret;
-}
-
-static Eina_Bool
-_e_comp_hwc_usable(void)
-{
- Eina_List *l;
- E_Zone *zone;
- E_Comp_Wl_Buffer *buffer = NULL;
-
- if (!e_comp->hwc) return EINA_FALSE;
-
- // check whether to use hwc and prepare the core assignment policy
- if (!_e_comp_hwc_prepare()) return EINA_FALSE;
-
- // extra policy can replace core policy
- _e_comp_hook_call(E_COMP_HOOK_PREPARE_PLANE, NULL);
-
- // check the hwc is avaliable.
- EINA_LIST_FOREACH(e_comp->zones, l, zone)
- {
- E_Output *eout = NULL;
- E_Plane *ep = NULL, *ep_fb = NULL;
- const Eina_List *ep_l = NULL, *p_l;
-
- if (!zone || !zone->output_id) continue;
-
- eout = e_output_find(zone->output_id);
- if (!eout) continue;
- ep_l = e_output_planes_get(eout);
-
- // It is not hwc_usable if cursor is shown when the hw cursor is not supported.
- if ((eout->cursor_available.max_w == -1) ||
- (eout->cursor_available.max_h == -1))
- {
- // hw cursor is not supported by libtdm, than let's composite
- if (!e_pointer_is_hidden(e_comp->pointer)) return EINA_FALSE;
- }
-
- ep_fb = e_output_fb_target_get(eout);
- if (!ep_fb) return EINA_FALSE;
-
- if (ep_fb->prepare_ec)
- {
- // It is not hwc_usable if the geometry of the prepare_ec at the ep_fb is not proper.
- int bw = 0, bh = 0;
-
- // It is not hwc_usable if attached buffer is not valid.
- buffer = e_pixmap_resource_get(ep_fb->prepare_ec->pixmap);
- if (!buffer) return EINA_FALSE;
-
- e_pixmap_size_get(ep_fb->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_fb->reserved_memory &&
- ((bw != zone->w) || (bh != zone->h) ||
- (ep_fb->prepare_ec->x != zone->x) || (ep_fb->prepare_ec->y != zone->y) ||
- (ep_fb->prepare_ec->w != zone->w) || (ep_fb->prepare_ec->h != zone->h)))
- {
-
- DBG("Cannot use HWC if geometry is not 1 on 1 match with reserved_memory");
- return EINA_FALSE;
- }
- }
- else
- {
- // It is not hwc_usable if the all prepare_ec in every plane are null
- Eina_Bool all_null = EINA_TRUE;
-
- EINA_LIST_FOREACH(ep_l, p_l, ep)
- {
- if (ep == ep_fb) continue;
- if (ep->prepare_ec)
- {
- // if attached buffer is not valid, hwc is not usable
- buffer = e_pixmap_resource_get(ep->prepare_ec->pixmap);
- if (!buffer) return EINA_FALSE;
-
- // It is not hwc_usable if the zpos of the ep is over the one of ep_fb
- if (ep->zpos < ep_fb->zpos) return EINA_FALSE;
-
- all_null = EINA_FALSE;
- break;
- }
- }
- if (all_null) return EINA_FALSE;
- }
- }
-
- return EINA_TRUE;
-}
-
-static void
-_e_comp_hwc_begin(void)
-{
- Eina_List *l;
- E_Zone *zone;
- Eina_Bool mode_set = EINA_FALSE;
-
- E_FREE_FUNC(e_comp->nocomp_delay_timer, ecore_timer_del);
-
- if (!e_comp->hwc) return;
- if (e_comp->nocomp_override > 0) return;
-
- EINA_LIST_FOREACH(e_comp->zones, l, zone)
- {
- E_Output * eout;
- if (!zone->output_id) continue;
- eout = e_output_find(zone->output_id);
- if(eout) mode_set |= _e_comp_hwc_apply(eout);
- }
-
- if (!mode_set) return;
- if (!e_comp->hwc_mode) return;
-
- if (e_comp->calc_fps) e_comp->frametimes[0] = 0;
-
- ELOGF("HWC", " Begin ...", NULL, NULL);
-}
-
-static Eina_Bool
-_e_comp_hwc_cb_begin_timeout(void *data EINA_UNUSED)
-{
- e_comp->nocomp_delay_timer = NULL;
-
- if (e_comp->nocomp_override == 0)
- {
- e_comp_render_queue();
- }
- return EINA_FALSE;
-}
-
-E_API void
-e_comp_hwc_end(const char *location)
-{
- Eina_Bool mode_set = EINA_FALSE;
- E_Zone *zone;
- Eina_List *l;
- Eina_Bool fully_hwc = (e_comp->hwc_mode == E_HWC_MODE_FULL) ? EINA_TRUE : EINA_FALSE;
-
- E_FREE_FUNC(e_comp->nocomp_delay_timer, ecore_timer_del);
- _hwc_reserved_clean();
-
- if (!e_comp->hwc) return;
- if (!e_comp->hwc_mode) return;
-
- EINA_LIST_FOREACH(e_comp->zones, l, zone)
- {
- E_Output * eout;
- if (!zone->output_id) continue;
- eout = e_output_find(zone->output_id);
- if (eout) mode_set |= _hwc_cancel(eout);
- }
-
- if (!mode_set) return;
-
- e_comp->hwc_mode = E_HWC_MODE_NO;
-
- if (fully_hwc)
- ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
-
- ELOGF("HWC", " End... at %s.", NULL, NULL, location);
-}
-
-EINTERN void
-e_comp_hwc_multi_plane_set(Eina_Bool set)
-{
- if (!conf->hwc_use_multi_plane) return;
-
- if (e_comp->hwc_use_multi_plane == set) return;
-
- e_comp_hwc_end(__FUNCTION__);
- e_comp->hwc_use_multi_plane = set;
-
- ELOGF("HWC", "e_comp_hwc_multi_plane_set : %d", NULL, NULL, set);
-}
-#endif // end of ENABLE_HWC_MULTI
-
static Eina_Bool
_e_comp_cb_update(void)
{
e_comp_object_dirty(ec->frame);
}
- if (e_comp->hwc_mode == E_HWC_MODE_FULL) goto setup_hwcompose;
-
#ifndef ENABLE_HWC_MULTI
if (conf->fps_show || e_comp->calc_fps)
{
if (e_comp->updates && (!e_comp->update_job))
ecore_animator_thaw(e_comp->render_animator);
-setup_hwcompose:
-#ifdef ENABLE_HWC_MULTI
- // query if HWC can be used
- if (!e_comp->hwc ||
- e_comp->hwc_deactive)
- {
- goto end;
- }
-
- if(_e_comp_hwc_usable())
- {
- if (e_comp->hwc_mode)
- {
- if (_e_comp_hwc_changed())
- {
- if (e_comp->hwc_mode == E_HWC_MODE_NO)
- ELOGF("HWC", " End... due to surface changes", NULL, NULL);
- else
- ELOGF("HWC", " hwc surface changed", NULL, NULL);
- }
- }
- else
- {
- // switch mode
- if (conf->nocomp_use_timer)
- {
- if (!e_comp->nocomp_delay_timer)
- {
- e_comp->nocomp_delay_timer = ecore_timer_add(conf->nocomp_begin_timeout,
- _e_comp_hwc_cb_begin_timeout,
- NULL);
- }
- }
- else
- {
- _e_comp_hwc_begin();
- }
- }
- }
- else
- {
- e_comp_hwc_end(__FUNCTION__);
- }
-
-end:
-#endif // end of ENABLE_HWC_MULTI
TRACE_DS_END();
return ECORE_CALLBACK_RENEW;
e_comp_new();
- if (conf->hwc_ignore_primary) e_comp->hwc_ignore_primary = EINA_TRUE;
+ if (conf->hwc)
+ {
+ e_comp->hwc = EINA_TRUE; // activate hwc policy on the primary output
+ if (conf->hwc_reuse_cursor_buffer) e_comp->hwc_reuse_cursor_buffer = EINA_TRUE;
+ if (conf->hwc_sync_mode_change) e_comp->hwc_sync_mode_change = EINA_TRUE;
+ if (conf->hwc_use_detach) e_comp->hwc_use_detach = EINA_TRUE;
+ if (conf->hwc_deactive) e_comp_hwc_deactive_set(EINA_TRUE);
+ if (conf->hwc_use_multi_plane) e_comp_hwc_multi_plane_set(EINA_TRUE);
+ if (conf->hwc_ignore_primary) e_comp->hwc_ignore_primary = EINA_TRUE;
+ }
+
+ if (conf->use_native_type_buffer) e_comp->use_native_type_buffer = EINA_TRUE;
e_main_ts_begin("\tE_Comp_Screen Init");
if (!e_comp_screen_init())
e_comp_canvas_fake_layers_init();
- if (conf->hwc) e_comp->hwc = EINA_TRUE; // activate hwc policy
- if (conf->hwc_deactive) e_comp->hwc_deactive = EINA_TRUE; // deactive hwc policy
- if (conf->hwc_reuse_cursor_buffer) e_comp->hwc_reuse_cursor_buffer = EINA_TRUE;
- if (conf->hwc_sync_mode_change) e_comp->hwc_sync_mode_change = EINA_TRUE;
- if (conf->hwc_use_detach) e_comp->hwc_use_detach = EINA_TRUE;
-#ifdef ENABLE_HWC_MULTI
- if (conf->hwc_use_multi_plane) e_comp->hwc_use_multi_plane = EINA_TRUE;
-#endif
- if (conf->use_native_type_buffer) e_comp->use_native_type_buffer = EINA_TRUE;
-
E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_ON, _e_comp_screensaver_on, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_OFF, _e_comp_screensaver_off, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_KEY_DOWN, _e_comp_key_down, NULL);
EINTERN Eina_Bool
e_comp_is_on_overlay(E_Client *ec)
{
+ Eina_List *l, *ll;
+ E_Output *eout;
+ E_Plane *ep;
+
if (!ec) return EINA_FALSE;
- if (e_comp->hwc_mode)
+ if (!ec->zone || !ec->zone->output_id) return EINA_FALSE;
+
+ eout = e_output_find(ec->zone->output_id);
+ if (!eout) return EINA_FALSE;
+ if (!e_output_hwc_mode_get(eout->output_hwc)) return EINA_FALSE;
+
+ EINA_LIST_FOREACH_SAFE(eout->planes, l, ll, ep)
{
- Eina_List *l, *ll;
- E_Output * eout;
- E_Plane *ep;
-
- if (!ec->zone || !ec->zone->output_id) return EINA_FALSE;
- eout = e_output_find(ec->zone->output_id);
- if (!eout) return EINA_FALSE;
- EINA_LIST_FOREACH_SAFE(eout->planes, l, ll, ep)
- {
- E_Client *overlay_ec = ep->ec;
- if (overlay_ec == ec) return EINA_TRUE;
- }
+ E_Client *overlay_ec = ep->ec;
+ if (overlay_ec == ec) return EINA_TRUE;
}
+
return EINA_FALSE;
}
+EINTERN E_Zone *
+e_comp_zone_find(const char *output_id)
+{
+ Eina_List *l = NULL;
+ E_Zone *zone = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output_id, NULL);
+
+ EINA_LIST_FOREACH(e_comp->zones, l, zone)
+ {
+ if (!zone) continue;
+ if (!strcmp(zone->output_id, output_id)) return zone;
+ }
+
+ return NULL;
+}
+
+
E_API Eina_List *
e_comp_vis_ec_list_get(E_Zone *zone)
{
return EINA_TRUE;
}
+
+/* set the deactive value to the only primary output */
+EINTERN void
+e_comp_hwc_deactive_set(Eina_Bool set)
+{
+ E_Output *output = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(e_comp);
+ EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
+
+ output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
+ EINA_SAFETY_ON_NULL_RETURN(output);
+
+ e_output_hwc_deactive_set(output->output_hwc, EINA_TRUE);
+}
+
+/* get the deactive value to the only primary output */
+EINTERN Eina_Bool
+e_comp_hwc_deactive_get(void)
+{
+ E_Output *output = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, EINA_FALSE);
+
+ output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ return e_output_hwc_deactive_get(output->output_hwc);
+}
+
+/* set the multi_plane value to the only primary output */
+EINTERN void
+e_comp_hwc_multi_plane_set(Eina_Bool set)
+{
+ E_Output *output = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(e_comp);
+ EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
+
+ output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
+ EINA_SAFETY_ON_NULL_RETURN(output);
+
+ e_output_hwc_multi_plane_set(output->output_hwc, EINA_TRUE);
+}
+
+/* get the multi_plane value to the only primary output */
+EINTERN Eina_Bool
+e_comp_hwc_multi_plane_get(void)
+{
+ E_Output *output = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, EINA_FALSE);
+
+ output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ return e_output_hwc_multi_plane_get(output->output_hwc);
+}
+
+/* end the hwc policy at the primary output */
+E_API void
+e_comp_hwc_end(const char *location)
+{
+ E_Output *output = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(e_comp);
+ EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
+
+ output = e_comp_screen_primary_output_get(e_comp->e_comp_screen);
+ EINA_SAFETY_ON_NULL_RETURN(output);
+
+ e_output_hwc_end(output->output_hwc, location);
+}
+
Ecore_Timer *nocomp_override_timer;
int nocomp_override; //number of times hwc override has been requested
Eina_Bool nocomp : 1; // TODO: remove it from E_Comp!!
- int hwc_mode;
Eina_Bool hwc : 1;
- Eina_Bool hwc_deactive : 1; // deactive hwc policy
Eina_Bool hwc_reuse_cursor_buffer;
Eina_Bool hwc_sync_mode_change;
Eina_Bool hwc_use_detach;
- Eina_Bool hwc_use_multi_plane;
Eina_Bool hwc_ignore_primary;
Eina_Bool use_native_type_buffer : 1; // use native buffer type
E_API E_Comp_Hook *e_comp_hook_add(E_Comp_Hook_Point hookpoint, E_Comp_Hook_Cb func, const void *data);
E_API void e_comp_hook_del(E_Comp_Hook *ph);
+EINTERN void e_comp_hook_call(E_Comp_Hook_Point hookpoint, void *data EINA_UNUSED);
+
EINTERN Eina_Bool e_comp_is_on_overlay(E_Client *ec);
+EINTERN E_Zone *e_comp_zone_find(const char *output_id);
E_API Eina_List *e_comp_vis_ec_list_get(E_Zone *zone); // visible ec list sorted by z order
-#ifdef ENABLE_HWC_MULTI
-E_API void e_comp_hwc_end(const char *location);
-EINTERN void e_comp_hwc_multi_plane_set(Eina_Bool set);
-#endif
-
E_API Eina_Bool e_comp_socket_init(const char *name);
+EINTERN void e_comp_hwc_deactive_set(Eina_Bool set);
+EINTERN Eina_Bool e_comp_hwc_deactive_get(void);
+EINTERN void e_comp_hwc_multi_plane_set(Eina_Bool set);
+EINTERN Eina_Bool e_comp_hwc_multi_plane_get(void);
+E_API void e_comp_hwc_end(const char *location);
+
#endif
#endif
if (!e_output_commit(output))
ERR("fail to commit e_comp_screen->outputs.");
+ e_output_hwc_apply(output->output_hwc);
+
if (!e_output_render(output))
ERR("fail to render e_comp_screen->outputs.");
-
}
-
end:
return ECORE_CALLBACK_RENEW;
}
if (!e_output_setup(output))
{
- ERR("fail to e_ouptut_hwc_setup.");
+ ERR("fail to e_output_setup.");
continue;
}
}
{
if (disable)
e_comp_hwc_end("in runtime by e_desk");
- e_comp->hwc_deactive = disable;
+
+ e_comp_hwc_deactive_set(disable);
}
static void
#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"
*hwc = -1;
*pl_zpos = -999;
- if ((!e_comp->hwc) || (e_comp->hwc_deactive))
+ if ((!e_comp->hwc) || e_comp_hwc_deactive_get())
return;
*hwc = 0;
}
if (onoff == 1)
- {
- e_comp->hwc_deactive = EINA_FALSE;
- }
+ e_comp_hwc_deactive_set(EINA_FALSE);
else if (onoff == 0)
{
e_comp_hwc_end("in runtime by e_info..");
- e_comp->hwc_deactive = EINA_TRUE;
+ e_comp_hwc_deactive_set(EINA_TRUE);
}
return reply;
if (!output) return;
+ if (output->output_hwc) e_output_hwc_del(output->output_hwc);
+
e_plane_shutdown();
if (output->id) free(output->id);
EINTERN Eina_Bool
e_output_setup(E_Output *output)
{
+ E_Output_Hwc *output_hwc = NULL;
Eina_List *l, *ll;
E_Plane *plane = NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+ /* available only the primary output now. */
+ if (e_comp->hwc)
+ {
+ output_hwc = e_output_hwc_new(output);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, EINA_FALSE);
+ output->output_hwc = output_hwc;
+ }
+
+ /* ecore evas engine setup */
EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane)
{
if (plane->is_fb)
return EINA_TRUE;
}
+EINTERN const char *
+e_output_output_id_get(E_Output *output)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+ return output->id;
+}
+
E_API E_Output *
e_output_find(const char *id)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(ep, EINA_FALSE);
#ifdef ENABLE_HWC_MULTI
- e_comp_hwc_multi_plane_set(EINA_FALSE);
+ e_output_hwc_multi_plane_set(output->output_hwc, EINA_FALSE);
#endif
output->zoom_conf.zoomx = zoomx;
{
ERR("e_plane_zoom_set failed.");
#ifdef ENABLE_HWC_MULTI
- e_comp_hwc_multi_plane_set(EINA_TRUE);
+ e_output_hwc_multi_plane_set(output->output_hwc, EINA_TRUE);
#endif
return EINA_FALSE;
}
output->zoom_set = EINA_FALSE;
#ifdef ENABLE_HWC_MULTI
- e_comp_hwc_multi_plane_set(EINA_TRUE);
+ e_output_hwc_multi_plane_set(output->output_hwc, EINA_TRUE);
#endif
/* update the ecore_evas */
Ecore_Timer *timer;
Eina_Bool wait_vblank;
} stream_capture;
+
+ /* output hwc */
+ E_Output_Hwc *output_hwc;
};
enum _E_Output_Hook_Point
EINTERN Eina_Bool e_output_stream_capture_dequeue(E_Output *output, tbm_surface_h surface);
EINTERN Eina_Bool e_output_stream_capture_start(E_Output *output);
EINTERN void e_output_stream_capture_stop(E_Output *output);
+EINTERN const char * e_output_output_id_get(E_Output *output);
E_API E_Output * e_output_find(const char *id);
E_API E_Output * e_output_find_by_index(int index);
E_API const Eina_List * e_output_planes_get(E_Output *output);
E_API E_Output_Intercept_Hook * e_output_intercept_hook_add(E_Output_Intercept_Hook_Point hookpoint, E_Output_Intercept_Hook_Cb func, const void *data);
E_API void e_output_intercept_hook_del(E_Output_Intercept_Hook *ch);
-
#endif
#endif
--- /dev/null
+#include "e.h"
+
+static int
+_hwc_set(E_Output *eout)
+{
+ const Eina_List *ep_l = NULL, *l;
+ E_Plane *ep = NULL;
+ E_Output_Hwc_Mode mode = E_OUTPUT_HWC_MODE_NO;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(eout->planes, EINA_FALSE);
+
+ ep_l = e_output_planes_get(eout);
+ EINA_LIST_REVERSE_FOREACH(ep_l, l , ep)
+ {
+ Eina_Bool set = EINA_FALSE;
+
+ if (e_plane_is_fb_target(ep))
+ {
+ if (ep->prepare_ec)
+ {
+ set = e_plane_ec_set(ep, ep->prepare_ec);
+ if (set)
+ {
+ 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);
+ }
+ break;
+ }
+ }
+ else if (ep->prepare_ec)
+ {
+ set = e_plane_ec_set(ep, ep->prepare_ec);
+ if (set)
+ {
+ ELOGF("HWC", "is set on %d", ep->prepare_ec->pixmap, ep->prepare_ec, ep->zpos);
+ mode |= E_OUTPUT_HWC_MODE_HYBRID;
+ }
+ else
+ break;
+ }
+ }
+
+ return mode;
+}
+
+static Eina_Bool
+_hwc_available_get(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;
+ }
+
+ if (e_comp_wl_tbm_buffer_sync_timeline_used(cdata->buffer_ref.buffer))
+ 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
+_hwc_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
+_hwc_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
+_hwc_prepare(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 Eina_Bool
+_hwc_cancel(E_Output_Hwc *output_hwc)
+{
+ Eina_List *l ;
+ E_Plane *ep;
+ Eina_Bool ret = EINA_TRUE;
+ E_Output *eout = output_hwc->output;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(eout->planes, EINA_FALSE);
+
+ 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))
+ {
+ if (ep->ec) ret = EINA_FALSE; // core cannot end HWC
+ continue;
+ }
+
+ e_plane_ec_prepare_set(ep, NULL);
+ e_plane_ec_set(ep, NULL);
+ }
+
+ return ret;
+}
+
+static Eina_Bool
+_hwc_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
+_hwc_plane_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
+_hwc_plane_change_ec(E_Plane *ep, E_Client *old_ec, E_Client *new_ec)
+{
+ Eina_Bool ret = EINA_FALSE;
+
+ if (!new_ec)
+ {
+ if (e_plane_is_reserved(ep))
+ e_plane_reserved_set(ep, 0);
+ }
+
+ e_plane_ec_prepare_set(ep, NULL);
+
+ if (e_plane_ec_set(ep, new_ec))
+ {
+ 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);
+ }
+ ret = EINA_TRUE;
+ }
+ else
+ {
+ 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 ret;
+}
+
+static Eina_Bool
+_e_output_hwc_apply(E_Output_Hwc *output_hwc)
+{
+ const Eina_List *ep_l = NULL, *l;
+ E_Plane *ep = NULL, *ep_fb = NULL;
+ int mode = 0;
+ E_Output *eout = output_hwc->output;
+
+ 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;
+ if (ep->prepare_ec != NULL) goto hwcompose;
+ }
+ continue;
+ }
+ if (ep->zpos > ep_fb->zpos)
+ if (ep->prepare_ec != NULL) goto hwcompose;
+ }
+
+ goto compose;
+
+hwcompose:
+ mode = _hwc_set(eout);
+ if (mode == E_OUTPUT_HWC_MODE_NO) ELOGF("HWC", "it is failed to assign surface on plane", NULL, NULL);
+
+compose:
+ if (mode != E_OUTPUT_HWC_MODE_NO) output_hwc->hwc_mode = mode;
+
+ return !!mode;
+}
+
+static Eina_Bool
+_e_output_hwc_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_NO;
+ E_Output *eout = output_hwc->output;
+
+ ep_l = e_output_planes_get(eout);
+ EINA_LIST_REVERSE_FOREACH(ep_l, p_l, ep)
+ {
+ if (!assign_success)
+ {
+ //unset planes from 'assign_success' became EINA_FALSE to the fb target
+ _hwc_plane_unset(ep);
+ continue;
+ }
+
+ if (ep->ec != ep->prepare_ec)
+ {
+ assign_success = _hwc_plane_change_ec(ep, ep->ec, ep->prepare_ec);
+ ret = EINA_TRUE;
+ }
+ else if (!ep->prepare_ec)
+ {
+ if (e_plane_is_reserved(ep))
+ {
+ e_plane_reserved_set(ep, 0);
+ ELOGF("HWC", "unset reserved mem on %d", NULL, NULL, ep->zpos);
+ }
+ }
+
+ 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;
+ }
+
+ return ret;
+}
+
+static Eina_Bool
+_e_output_hwc_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;
+
+ EINA_LIST_FOREACH(vis_clist, vl, ec)
+ {
+ // check clients not able to use hwc
+ // 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 (!_hwc_available_get(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;
+
+ _hwc_prepare_init(output_hwc);
+
+ if (n_cur >= 1)
+ n_skip = _hwc_prepare_cursor(output, n_cur, hwc_ok_clist);
+
+ if (n_skip > 0) ret = EINA_TRUE;
+
+ ret |= _hwc_prepare(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_usable(E_Output_Hwc *output_hwc)
+{
+ E_Output *eout = output_hwc->output;
+ E_Comp_Wl_Buffer *buffer = NULL;
+ E_Zone *zone = NULL;
+
+ 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_prepare(output_hwc, zone)) return EINA_FALSE;
+
+ // extra policy can replace core policy
+ e_comp_hook_call(E_COMP_HOOK_PREPARE_PLANE, NULL);
+
+ // check the hwc is avaliable.
+ E_Plane *ep = NULL, *ep_fb = NULL;
+ const Eina_List *ep_l = NULL, *p_l;
+
+ ep_l = e_output_planes_get(eout);
+
+ // It is not hwc_usable if cursor is shown when the hw cursor is not supported.
+ if ((eout->cursor_available.max_w == -1) ||
+ (eout->cursor_available.max_h == -1))
+ {
+ // hw cursor is not supported by libtdm, than let's composite
+ if (!e_pointer_is_hidden(e_comp->pointer)) return EINA_FALSE;
+ }
+
+ ep_fb = e_output_fb_target_get(eout);
+ if (!ep_fb) return EINA_FALSE;
+
+ if (ep_fb->prepare_ec)
+ {
+ // It is not hwc_usable if the geometry of the prepare_ec at the ep_fb is not proper.
+ int bw = 0, bh = 0;
+
+ // It is not hwc_usable if attached buffer is not valid.
+ buffer = e_pixmap_resource_get(ep_fb->prepare_ec->pixmap);
+ if (!buffer) return EINA_FALSE;
+
+ e_pixmap_size_get(ep_fb->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_fb->reserved_memory &&
+ ((bw != zone->w) || (bh != zone->h) ||
+ (ep_fb->prepare_ec->x != zone->x) || (ep_fb->prepare_ec->y != zone->y) ||
+ (ep_fb->prepare_ec->w != zone->w) || (ep_fb->prepare_ec->h != zone->h)))
+ {
+ DBG("Cannot use HWC if geometry is not 1 on 1 match with reserved_memory");
+ return EINA_FALSE;
+ }
+ }
+ else
+ {
+ // It is not hwc_usable if the all prepare_ec in every plane are null
+ Eina_Bool all_null = EINA_TRUE;
+
+ EINA_LIST_FOREACH(ep_l, p_l, ep)
+ {
+ if (ep == ep_fb) continue;
+ if (ep->prepare_ec)
+ {
+ // if attached buffer is not valid, hwc is not usable
+ buffer = e_pixmap_resource_get(ep->prepare_ec->pixmap);
+ if (!buffer) return EINA_FALSE;
+
+ // It is not hwc_usable if the zpos of the ep is over the one of ep_fb
+ if (ep->zpos < ep_fb->zpos) return EINA_FALSE;
+
+ all_null = EINA_FALSE;
+ break;
+ }
+ }
+ if (all_null) return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void
+_e_output_hwc_begin(E_Output_Hwc *output_hwc)
+{
+ Eina_Bool mode_set = EINA_FALSE;
+
+ if (e_comp->nocomp_override > 0) return;
+
+ mode_set = _e_output_hwc_apply(output_hwc);
+ if (!mode_set) return;
+ if (!output_hwc->hwc_mode) return;
+
+ ELOGF("HWC", " Begin ...", NULL, NULL);
+}
+
+EINTERN void
+e_output_hwc_end(E_Output_Hwc *output_hwc, const char *location)
+{
+ Eina_Bool mode_set = EINA_FALSE;
+ E_Zone *zone;
+ Eina_List *l;
+ Eina_Bool fully_hwc;
+
+ EINA_SAFETY_ON_NULL_RETURN(output_hwc);
+
+ fully_hwc = (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_FULL) ? EINA_TRUE : EINA_FALSE;
+
+ _hwc_reserved_clean(output_hwc);
+
+ if (!e_comp->hwc) return;
+ if (!output_hwc->hwc_mode) return;
+
+ EINA_LIST_FOREACH(e_comp->zones, l, zone)
+ {
+ E_Output * eout;
+ if (!zone->output_id) continue;
+ eout = e_output_find(zone->output_id);
+ if (eout) mode_set |= _hwc_cancel(output_hwc);
+ }
+
+ if (!mode_set) return;
+
+ output_hwc->hwc_mode = E_OUTPUT_HWC_MODE_NO;
+
+ if (fully_hwc)
+ ecore_event_add(E_EVENT_COMPOSITOR_ENABLE, NULL, NULL, NULL);
+
+ ELOGF("HWC", " End... at %s.", NULL, NULL, location);
+}
+
+EINTERN void
+e_output_hwc_multi_plane_set(E_Output_Hwc *output_hwc, Eina_Bool set)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output_hwc);
+
+ e_output_hwc_end(output_hwc, __FUNCTION__);
+ output_hwc->hwc_use_multi_plane = set;
+
+ ELOGF("HWC", "e_output_hwc_multi_plane_set : %d", NULL, NULL, set);
+}
+
+EINTERN Eina_Bool
+e_output_hwc_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_deactive_set(E_Output_Hwc *output_hwc, Eina_Bool set)
+{
+ EINA_SAFETY_ON_NULL_RETURN(output_hwc);
+
+ e_output_hwc_end(output_hwc, __FUNCTION__);
+ output_hwc->hwc_deactive = set;
+
+ ELOGF("HWC", "e_output_hwc_deactive_set : %d", NULL, NULL, set);
+}
+
+EINTERN Eina_Bool
+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_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_usable(output_hwc))
+ {
+ if (output_hwc->hwc_mode)
+ {
+ if (_e_output_hwc_changed(output_hwc))
+ {
+ if (output_hwc->hwc_mode == E_OUTPUT_HWC_MODE_NO)
+ ELOGF("HWC", " End... due to surface changes", NULL, NULL);
+ else
+ ELOGF("HWC", " hwc surface changed", NULL, NULL);
+ }
+ }
+ else
+ _e_output_hwc_begin(output_hwc);
+ }
+ else
+ e_output_hwc_end(output_hwc, __FUNCTION__);
+}
+
+EINTERN E_Output_Hwc_Mode
+e_output_hwc_mode_get(E_Output_Hwc *output_hwc)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, E_OUTPUT_HWC_MODE_NO);
+
+ return output_hwc->hwc_mode;
+}
+
+EINTERN E_Output_Hwc *
+e_output_hwc_new(E_Output *output)
+{
+ E_Output_Hwc *output_hwc = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+ output_hwc = E_NEW(E_Output_Hwc, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output_hwc, NULL);
+
+ output_hwc->output = output;
+
+ return output_hwc;
+}
+
+EINTERN void
+e_output_hwc_del(E_Output_Hwc *output_hwc)
+{
+ if (!output_hwc) return;
+
+ E_FREE(output_hwc);
+}
--- /dev/null
+#ifdef E_TYPEDEFS
+
+typedef struct _E_Output_Hwc E_Output_Hwc;
+
+typedef enum _E_Output_Hwc_Mode
+{
+ E_OUTPUT_HWC_MODE_NO = 0,
+ E_OUTPUT_HWC_MODE_HYBRID,
+ E_OUTPUT_HWC_MODE_FULL
+} E_Output_Hwc_Mode;
+
+#else
+#ifndef E_OUTPUT_HWC_H
+#define E_OUTPUT_HWC_H
+
+struct _E_Output_Hwc
+{
+ E_Output *output;
+ E_Output_Hwc_Mode hwc_mode;
+ Eina_Bool hwc_deactive : 1; // deactive hwc policy
+ Eina_Bool hwc_use_multi_plane;
+};
+
+EINTERN E_Output_Hwc *e_output_hwc_new(E_Output *output);
+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_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_multi_plane_set(E_Output_Hwc *output_hwc, Eina_Bool set);
+EINTERN Eina_Bool e_output_hwc_multi_plane_get(E_Output_Hwc *output_hwc);
+
+EINTERN void e_output_hwc_end(E_Output_Hwc *output_hwc, const char *location);
+#endif
+#endif
{
switch (on)
{
- case 0: accept = EINA_TRUE; e_comp->hwc_deactive = EINA_TRUE; break;
- case 1: accept = EINA_TRUE; e_comp->hwc_deactive = EINA_FALSE; break;
+ case 0: accept = EINA_TRUE; e_comp_hwc_deactive_set(EINA_TRUE); break;
+ case 1: accept = EINA_TRUE; e_comp_hwc_deactive_set(EINA_FALSE); break;
default: break;
}
}