%if "%{MEMCPY_SWC}" == "use"
--enable-memcpy_swc \
%endif
- --enable-quick-init
+ --enable-quick-init \
+ --enable-hwc-multi
make %{?_smp_mflags}
{
const Eina_List *ep_l = NULL, *l;
E_Plane *ep = NULL, *ep_fb = NULL;
+ Eina_Bool ret = EINA_FALSE;
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_FOREACH(ep_l, l , ep)
{
+ Eina_Bool set = EINA_FALSE;
if (!ep_fb)
{
if (e_plane_is_fb_target(ep))
ep_fb = ep;
if (ep->prepare_ec)
{
- e_client_redirected_set(ep->prepare_ec, 0);
- ep->ec = ep->prepare_ec;
+
+ set = e_plane_ec_set(ep, ep->prepare_ec);
+ if (set)
+ {
+ INF("HWC : ec(0x%08x, %s) is set on fb_target( %d)\n", ep->prepare_ec, ep->prepare_ec->icccm.title, ep->zpos);
+ e_client_redirected_set(ep->prepare_ec, 0);
+ ret |= EINA_TRUE;
+ }
+ else
+ return EINA_FALSE;
}
}
continue;
{
if (ep->prepare_ec)
{
- e_client_redirected_set(ep->prepare_ec, 0);
- ep->ec = ep->prepare_ec;
+ set = e_plane_ec_set(ep, ep->prepare_ec);
+ if (set)
+ {
+ INF("HWC : ec(0x%08x, %s) is set on %d\n", ep->prepare_ec, ep->prepare_ec->icccm.title, ep->zpos);
+ e_client_redirected_set(ep->prepare_ec, 0);
+ ret |= EINA_TRUE;
+ }
+ else
+ break;
}
}
}
- return EINA_TRUE;
+ return ret;
}
static Eina_Bool
EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(clist, EINA_FALSE);
+ // list up available_hw layers E_Client can be set
ep_l = e_output_planes_get(eout);
EINA_LIST_FOREACH(ep_l, l, ep)
{
}
continue;
}
+ if (conf->hwc_use_single_plane) continue;
if (e_plane_is_cursor(ep)) continue;
if (ep->zpos > ep_fb->zpos)
hwc_l = eina_list_append(hwc_l, ep);
(n_ec <= n_ly)) // full hwc including nocomp
{
int del = n_ly - n_ec;
- INF("HWC : \t fully hwc \t n_ec(%d), n_vis(%d), n_ly(%d), hwc_mode(%d) \n", n_ec, n_vis, n_ly, e_comp->hwc_mode);
EINA_LIST_REVERSE_FOREACH(hwc_l, l, ep)
{
ec = NULL;
if (del > 0)
{
- ep->prepare_ec = NULL;
+ e_plane_ec_prepare_set(ep, NULL);
del--;
continue;
}
if (clist) ec = eina_list_data_get(clist);
- if (ec) ep->prepare_ec = ec;
+ if (ec) e_plane_ec_prepare_set(ep, ec);
clist = eina_list_next(clist);
}
ret = EINA_TRUE;
(n_ec < n_vis))
{
int del = n_ly - n_ec;
- INF("HWC : \t hybrid \t n_ec(%d), n_vis(%d), n_ly(%d), hwc_mode(%d) \n", n_ec, n_vis, n_ly, e_comp->hwc_mode);
EINA_LIST_REVERSE_FOREACH(hwc_l, l, ep)
{
ec = NULL;
if (del > 0)
{
- ep->prepare_ec = NULL;
+ e_plane_ec_prepare_set(ep, NULL);
del--;
continue;
}
if (clist2) ec = eina_list_data_get(clist2);
- if (ec) ep->prepare_ec = ec;
- if (e_plane_is_fb_target(ep)) ep->prepare_ec = NULL;
+ if (ec) e_plane_ec_prepare_set(ep, ec);
+ if (e_plane_is_fb_target(ep)) e_plane_ec_prepare_set(ep, NULL);
clist2 = eina_list_next(clist2);
}
ret = EINA_TRUE;
EINA_LIST_FOREACH(eout->planes, l, ep)
{
if (ep->ec) e_client_redirected_set(ep->ec, 1);
- ep->prepare_ec = NULL;
- ep->ec = NULL;
+ e_plane_ec_prepare_set(ep, NULL);
+ e_plane_ec_set(ep, NULL);
+ }
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_hwc_plane_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);
+ EINA_LIST_FOREACH(eout->planes, ll, ep)
+ {
+ if (e_plane_is_reserved(ep))
+ e_plane_reserved_set(ep, 0);
+ }
}
return EINA_TRUE;
{
const Eina_List *ep_l = NULL, *l;
E_Plane *ep = NULL, *ep_fb = NULL;
+ Eina_Bool ret = EINA_FALSE;
ep_l = e_output_planes_get(eout);
EINA_LIST_FOREACH(ep_l, l, ep)
if (ep->prepare_ec != NULL) goto hwcompose;
}
- _hwc_cancel(eout);
- return EINA_FALSE;
+ goto compose;
hwcompose:
- e_comp->hwc_mode = 1;
- _hwc_set(eout);
- return EINA_TRUE;
+ ret = _hwc_set(eout);
+ if (!ret) INF("HWC : it is failed to assign surface on plane\n");
+
+compose:
+ if (ret) e_comp->hwc_mode = 1;
+ else
+ {
+ e_comp->hwc_mode = 0;
+
+ EINA_LIST_FOREACH(ep_l, l, ep)
+ {
+ if (ep->ec)
+ e_client_redirected_set(ep->ec, 1);
+
+ e_plane_ec_prepare_set(ep, NULL);
+ }
+ }
+ return ret;
}
static Eina_Bool
static Eina_Bool
_e_comp_hwc_prepare(void)
{
- Eina_List *l;
+ Eina_List *l, *vl;
E_Zone *zone;
Eina_Bool ret = EINA_FALSE;
- if (!e_comp->hwc) return EINA_FALSE;
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(e_comp->hwc, EINA_FALSE);
- // TODO: e_comp->canvases
EINA_LIST_FOREACH(e_comp->zones, l, zone)
{
E_Client *ec;
- E_Output *eout;
- int n_visible = 0, n_ec = 0;
- Eina_List *clist = NULL;
+ E_Output *output;
+ int n_vis = 0, n_ec = 0;
+ Eina_List *clist = NULL, *vis_clist = NULL;
if (!zone || !zone->output_id) continue;
- eout = e_output_find(zone->output_id);
+ output = e_output_find(zone->output_id);
+ if (!output) continue;
+
+ vis_clist = e_comp_vis_ec_list_get(zone);
+ if (!vis_clist) continue;
- E_CLIENT_REVERSE_FOREACH(ec)
+ EINA_LIST_FOREACH(vis_clist, vl, ec)
{
E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+ int cnt = 0;
- if (ec->zone != zone) continue;
-
- // check clients to skip composite
- if (ec->ignored || ec->input_only || (!evas_object_visible_get(ec->frame)))
- continue;
+ // check clients not able to use hwc
+ // if pixmap is launch screen image
+ if ((ec->pixmap) && (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT))
+ goto composite;
- if (!E_INTERSECTS(0, 0, e_comp->w, e_comp->h,
- ec->client.x, ec->client.y, ec->client.w, ec->client.h))
- {// check quick panel
- continue;
+ // if video client could not draw it on video hw layer
+ if (cdata->sub.below_list || cdata->sub.below_list_pending)
+ {
+ if (!e_comp_wl_video_client_has(ec))
+ goto composite;
}
- if (evas_object_data_get(ec->frame, "comp_skip"))
- continue;
-
- // check clients not able to use hwc
- if ((!cdata->buffer_ref.buffer) ||
+ // if ec has invalid buffer or scaled( transformed )
+ if ((!cdata) ||
+ (!cdata->buffer_ref.buffer) ||
(cdata->buffer_ref.buffer->type != E_COMP_WL_BUFFER_TYPE_NATIVE) ||
(cdata->width_from_buffer != cdata->width_from_viewport) ||
(cdata->height_from_buffer != cdata->height_from_viewport) ||
e_client_transform_core_enable_get(ec))
{
- if (!n_visible) goto fullcomp;
- n_visible++;
+ if (!n_vis) goto composite;
+ cnt++;
break;
}
- n_visible++;
+ cnt++;
clist = eina_list_append(clist, ec);
}
+ n_vis = eina_list_count(vis_clist);
n_ec = eina_list_count(clist);
- if ((n_visible < 1) || (n_ec < 1))
- {
- eina_list_free(clist);
- goto fullcomp;
- }
+ if ((n_vis < 1) || (n_ec < 1))
+ goto composite;
+
+ ret |= _hwc_prepare_set(output, n_vis, clist);
- ret = _hwc_prepare_set(eout, n_visible, clist);
+ composite:
eina_list_free(clist);
+ eina_list_free(vis_clist);
}
return ret;
-
-fullcomp:
- return EINA_FALSE;
}
static Eina_Bool
{
Eina_List *l;
E_Zone *zone;
+ Eina_Bool ret = EINA_FALSE;
if (!e_comp->hwc) return EINA_FALSE;
+
+ if ((ec->pixmap) && (e_pixmap_type_get(ec->pixmap) == E_PIXMAP_TYPE_EXT_OBJECT))
+ break;
+
+ if ((!cdata) ||
+ (!cdata->buffer_ref.buffer) ||
+ (cdata->buffer_ref.buffer->type != E_COMP_WL_BUFFER_TYPE_NATIVE))
+ break;
+
+ if (cdata->sub.below_list || cdata->sub.below_list_pending)
+ {
+ if (!e_comp_wl_video_client_has(ec))
+ break;
+ }
+
// check whether to use hwc
// core assignment policy
- _e_comp_hwc_prepare();
+ ret = _e_comp_hwc_prepare();
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(ret, EINA_FALSE);
// extra policy can replace core policy
_e_comp_hook_call(E_COMP_HOOK_PREPARE_PLANE, NULL);
e_comp->selcomp_want = 0;
E_FREE_FUNC(e_comp->selcomp_delay_timer, ecore_timer_del);
+ _hwc_plane_reserved_clean();
if (!e_comp->hwc) return;
if (!_e_comp_hwc_is_on()) return;
INF("HWC : End... at %s", location);
#else
+ if (!e_comp->hwc) return;
+ if (!e_comp->nocomp) return;
+ if (!e_comp->nocomp_ec) return;
+
e_comp_nocomp_end(location);
#endif // end of ENABLE_HWC_MULTI
}
}
else
{
- if (_e_comp_hwc_is_on()) e_comp_hwc_end(__FUNCTION__);
+ e_comp_hwc_end(__FUNCTION__);
}
#else
ec = _e_comp_fullscreen_check();
e_comp_canvas_fake_layers_init();
#ifdef HAVE_HWC
- // TO DO : check hwc init condition
- if (conf->hwc && e_comp_gl_get())
+ if (conf->hwc &&
+ e_comp_gl_get()) // TODO: check hwc init condition
{
e_comp->hwc = e_comp_hwc_init();
if (!e_comp->hwc)
else
e_comp->hwc_fs = EINA_TRUE; // 1: active hwc policy
}
+ conf->hwc_use_single_plane = 1; // TODO: 0 if multi plane is working.
#endif
E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_ON, _e_comp_screensaver_on, NULL);
e_comp_override_add()
{
e_comp->hwc_override++;
- if ((e_comp->hwc_override > 0) &&
-#ifdef ENABLE_HWC_MULTI
- (_e_comp_hwc_is_on()))
-#else
- (e_comp->nocomp))
-#endif
+ if (e_comp->hwc_override > 0)
{
+ // go full compositing
e_comp_hwc_end(__FUNCTION__);
}
}
void *data;
} autoclose;
+ E_Comp_Screen *e_comp_screen;
+
Eina_List *debug_rects;
Eina_List *ignore_wins;
static void
_e_comp_canvas_resize(Ecore_Evas *ee EINA_UNUSED)
{
- e_output_screens_setup(e_comp->w, e_comp->h);
+ e_comp_screen_e_screens_setup(e_comp->e_comp_screen, e_comp->w, e_comp->h);
e_comp_canvas_update();
}
e_comp->ee_win = ecore_evas_window_get(e_comp->ee);
- screens = (Eina_List *)e_output_screens_get();
+ screens = (Eina_List *)e_comp_screen_e_screens_get(e_comp->e_comp_screen);
if (screens)
{
E_Screen *scr;
int i;
Eina_Bool changed = EINA_FALSE;
- screens = (Eina_List *)e_output_screens_get();
+ screens = (Eina_List *)e_comp_screen_e_screens_get(e_comp->e_comp_screen);
if (screens)
{
E_CONFIG_VAL(D, T, selcomp_use_timer, UCHAR);
E_CONFIG_VAL(D, T, selcomp_begin_timeout, DOUBLE);
E_CONFIG_VAL(D, T, hwc, UCHAR);
+ E_CONFIG_VAL(D, T, hwc_use_single_plane, UCHAR);
E_CONFIG_VAL(D, T, nofade, UCHAR);
E_CONFIG_VAL(D, T, smooth_windows, UCHAR);
E_CONFIG_VAL(D, T, first_draw_delay, DOUBLE);
cfg->selcomp_use_timer = 1;
cfg->selcomp_begin_timeout = 2.0;
cfg->hwc = 0;
+ cfg->hwc_use_single_plane = 0;
cfg->nofade = 0;
cfg->smooth_windows = 0; // 1 if gl, 0 if not
cfg->first_draw_delay = 0.15;
unsigned char selcomp_use_timer;
double selcomp_begin_timeout;
unsigned char hwc;
+ unsigned char hwc_use_single_plane;
unsigned char smooth_windows;
unsigned char nofade;
double first_draw_delay;
#include "e.h"
#ifdef HAVE_HWC
+#ifdef ENABLE_HWC_MULTI
+EINTERN Eina_Bool
+e_comp_hwc_init(void)
+{
+ if (!e_comp || !e_comp->e_comp_screen)
+ {
+ e_error_message_show(_("Enlightenment cannot has no e_comp at HWC(HardWare Composite)!\n"));
+ return EINA_FALSE;
+ }
+
+ if (!e_comp_screen_hwc_setup(e_comp->e_comp_screen))
+ {
+ ERR("fail to e_comp_screen_hwc_setup");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EINTERN void
+e_comp_hwc_shutdown(void)
+{
+ ;
+}
+
+EINTERN Eina_Bool
+e_comp_hwc_mode_nocomp(E_Client *ec)
+{
+ return EINA_FALSE;
+}
+
+EINTERN void
+e_comp_hwc_display_client(E_Client *ec)
+{
+ ;
+}
+
+EINTERN void
+e_comp_hwc_trace_debug(Eina_Bool onoff)
+{
+ ;
+}
+
+EINTERN void
+e_comp_hwc_info_debug(void)
+{
+ ;
+}
+
+EINTERN Eina_Bool
+e_comp_hwc_native_surface_set(E_Client *ec)
+{
+ return EINA_FALSE;
+}
+
+EINTERN void
+e_comp_hwc_client_commit(E_Client *ec)
+{
+ ;
+}
+
+E_API Eina_Bool
+e_comp_hwc_client_set_layer(E_Client *ec, int zorder)
+{
+ return EINA_FALSE;
+}
+
+E_API void
+e_comp_hwc_client_unset_layer(int zorder)
+{
+ ;
+}
+#else
# include "e_comp_wl.h"
# include "e_comp_hwc.h"
Ecore_Drm_Device *dev;
Ecore_Drm_Output *drm_output;
E_Output *eout;
+ E_Comp_Screen *e_comp_screen;
const Eina_List *l, *ll;
int x, y, w, h;
+ e_comp_screen = e_comp->e_comp_screen;
+
EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
{
EINA_LIST_FOREACH(e_comp_screen->outputs, ll, eout)
EINTERN Eina_Bool
e_comp_hwc_init(void)
{
+#ifdef ENABLE_HWC_MULTI
+ if (!e_comp || !e_comp->e_comp_screen)
+ {
+ e_error_message_show(_("Enlightenment cannot has no e_comp at HWC(HardWare Composite)!\n"));
+ return EINA_FALSE;
+ }
+
+ if (!e_comp_screen_hwc_setup(e_comp->e_comp_screen))
+ {
+ ERR("fail to e_comp_screen_hwc_setup");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+#else
E_Comp_Hwc *hwc = NULL;
E_Comp_Hwc_Output *hwc_output = NULL;
E_Comp_Hwc_Layer *hwc_layer = NULL;
_e_comp_hwc_remove(hwc);
return EINA_FALSE;
+#endif
}
EINTERN void
{
if (!e_comp) return;
+#ifdef ENABLE_HWC_MULTI
+#else
_e_comp_hwc_remove(g_hwc);
+#endif
}
EINTERN Eina_Bool
e_comp_hwc_native_surface_set(E_Client *ec)
{
+#ifdef ENABLE_HWC_MULTI
+ return EINA_FALSE;
+#else
EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
E_Comp_Hwc_Client *hwc_client = NULL;
#endif
return EINA_TRUE;
+#endif
}
EINTERN void
}
return;
}
-
+#endif /* end of ENABLE_HWC_MULTI */
#else /* HAVE_HWC */
EINTERN Eina_Bool
e_comp_hwc_init(void)
}
#ifdef HAVE_HWC
+#ifdef ENABLE_HWC_MULTI
+ e_comp_object_native_surface_set(obj, e_comp->gl);
+#else
if (e_comp->hwc)
{
if (!e_comp_hwc_native_surface_set(cw->ec))
}
else
e_comp_object_native_surface_set(obj, e_comp->gl);
+#endif
#else
e_comp_object_native_surface_set(obj, e_comp->gl);
#endif
{
API_ENTRY EINA_FALSE;
return cw->hwc_need_update;
-}
\ No newline at end of file
+}
+
+// will remove out
+E_API void
+e_comp_object_hwc_update_set(Evas_Object *obj, Eina_Bool set)
+{
+ API_ENTRY;
+ cw->hwc_need_update = set;
+}
E_API void e_comp_object_clear(Evas_Object *obj);
E_API Eina_Bool e_comp_object_hwc_update_exists(Evas_Object *obj);
-
+E_API void e_comp_object_hwc_update_set(Evas_Object *obj, Eina_Bool set);
#endif
#endif
static Eina_Bool dont_set_ecore_drm_keymap = EINA_FALSE;
static Eina_Bool dont_use_xkb_cache = EINA_FALSE;
+E_API int E_EVENT_SCREEN_CHANGE = 0;
+
static Eina_Bool
_e_comp_screen_cb_activate(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
}
static Eina_Bool
-_e_comp_screen_cb_output(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+_e_comp_screen_cb_output_drm(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
const Eina_List *l;
- E_Output *eout;
+ E_Output *output;
Ecore_Drm_Event_Output *e;
+ E_Comp_Screen *e_comp_screen = NULL;
if (!(e = event)) goto end;
+ if (!e_comp) goto end;
+ if (!e_comp->e_comp_screen) goto end;
+
+ e_comp_screen = e_comp->e_comp_screen;
DBG("WL_DRM OUTPUT CHANGE");
- EINA_LIST_FOREACH(e_comp_screen->outputs, l, eout)
+ EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
{
- if ((!strcmp(eout->info.name, e->name)) &&
- (!strcmp(eout->info.screen, e->model)))
+ if ((!strcmp(output->info.name, e->name)) &&
+ (!strcmp(output->info.screen, e->model)))
{
if (e->plug)
{
- if (!e_comp_wl_output_init(eout->id, e->make, e->model,
+ if (!e_comp_wl_output_init(output->id, e->make, e->model,
e->x, e->y, e->w, e->h,
e->phys_width, e->phys_height,
e->refresh, e->subpixel_order,
e->transform))
{
- ERR("Could not setup new output: %s", eout->id);
+ ERR("Could not setup new output: %s", output->id);
}
}
else
- e_comp_wl_output_remove(eout->id);
+ e_comp_wl_output_remove(output->id);
break;
}
return ECORE_CALLBACK_PASS_ON;
}
+#ifdef ENABLE_HWC_MULTI
+static Eina_Bool
+_e_comp_screen_commit_idle_cb(void *data EINA_UNUSED)
+{
+ Eina_List *l, *ll;
+ E_Comp_Screen *e_comp_screen = NULL;
+ E_Output *output = NULL;
+
+ if (!e_comp->e_comp_screen) goto end;
+
+ e_comp_screen = e_comp->e_comp_screen;
+
+ EINA_LIST_FOREACH_SAFE(e_comp_screen->outputs, l, ll, output)
+ {
+ if (!output) continue;
+ if (!output->config.enabled) continue;
+
+ if (!e_output_commit(output))
+ {
+ ERR("fail to e_comp_screen->outputs.");
+ continue;
+ }
+ }
+
+end:
+ return ECORE_CALLBACK_RENEW;
+}
+#endif
+
static Eina_Bool
_e_comp_screen_cb_input_device_add(void *data, int type, void *event)
{
}
static Ecore_Drm_Output_Mode *
-_e_comp_screen_mode_screen_find(E_Output *eout, Ecore_Drm_Output *output)
+_e_comp_screen_mode_screen_find(E_Output *output, Ecore_Drm_Output *drm_output)
{
Ecore_Drm_Output_Mode *mode, *m = NULL;
const Eina_List *l;
int diff, distance = 0x7fffffff;
- EINA_LIST_FOREACH(ecore_drm_output_modes_get(output), l, mode)
+ EINA_LIST_FOREACH(ecore_drm_output_modes_get(drm_output), l, mode)
{
- diff = (100 * abs(eout->config.mode.w - mode->width)) +
- (100 * abs(eout->config.mode.h - mode->height)) +
- fabs((100 * eout->config.mode.refresh) - (100 * mode->refresh));
+ diff = (100 * abs(output->config.mode.w - mode->width)) +
+ (100 * abs(output->config.mode.h - mode->height)) +
+ fabs((100 * output->config.mode.refresh) - (100 * mode->refresh));
if (diff < distance)
{
m = mode;
return m;
}
-static Eina_Bool
-_e_comp_screen_output_exists(Ecore_Drm_Output *output, unsigned int crtc)
+static E_Comp_Screen *
+_e_comp_screen_new(void)
{
- /* find out if this output can go into the 'possibles' */
- return ecore_drm_output_possible_crtc_get(output, crtc);
+ E_Comp_Screen *e_comp_screen = NULL;
+ tdm_error error = TDM_ERROR_NONE;
+
+ e_comp_screen = E_NEW(E_Comp_Screen, 1);
+ if (!e_comp_screen) return NULL;
+
+ if (e_comp_gl_get())
+ {
+ /* tdm display init */
+ e_comp_screen->tdisplay = tdm_display_init(&error);
+ if (!e_comp_screen->tdisplay)
+ {
+ ERR("fail to get tdm_display\n");
+ free(e_comp_screen);
+ return NULL;
+ }
+ }
+ else
+ {
+ /* Ecore_Drm_Device list */
+ e_comp_screen->devices = ecore_drm_devices_get();
+ }
+
+ return e_comp_screen;
}
-static char *
-_e_comp_screen_output_screen_get(Ecore_Drm_Output *output)
+static void
+_e_comp_screen_del(E_Comp_Screen *e_comp_screen)
{
- const char *model;
+ if (!e_comp_screen) return;
- model = ecore_drm_output_model_get(output);
- if (!model) return NULL;
+ if (e_comp_screen->tdisplay) tdm_display_deinit(e_comp_screen->tdisplay);
- return strdup(model);
+ free(e_comp_screen);
}
-EINTERN E_Comp_Screen *
-e_comp_screen_init_outputs(void)
+static void
+_e_comp_screen_deinit_outputs(E_Comp_Screen *e_comp_screen)
+{
+ E_Output *output;
+
+ // free up e_outputs
+ EINA_LIST_FREE(e_comp_screen->outputs, output)
+ {
+ e_output_del(output);
+ }
+
+ e_output_shutdown();
+}
+
+static Eina_Bool
+_e_comp_screen_init_drm_outputs(E_Comp_Screen *e_comp_screen)
{
Ecore_Drm_Device *dev;
Ecore_Drm_Output *output;
const Eina_List *l, *ll;
- E_Comp_Screen *r = NULL;
+ E_Output *eout = NULL;
- r = E_NEW(E_Comp_Screen, 1);
- if (!r) return NULL;
-
- EINA_LIST_FOREACH(ecore_drm_devices_get(), l, dev)
+ EINA_LIST_FOREACH(e_comp_screen->devices, l, dev)
{
EINA_LIST_FOREACH(dev->outputs, ll, output)
{
- E_Output *eout;
- const Eina_List *m;
- Ecore_Drm_Output_Mode *omode;
- unsigned int j;
- int priority;
- Eina_Bool ok = EINA_FALSE;
- Eina_Bool possible = EINA_FALSE;
- int len = 0;
-
- eout = E_NEW(E_Output, 1);
+ if (!output) continue;
+ eout = e_output_drm_new(output);
if (!eout) continue;
-
- eout->info.name = ecore_drm_output_name_get(output);
- printf("COMP TDM: .... out %s\n", eout->info.name);
-
- eout->info.connected = ecore_drm_output_connected_get(output);
- printf("COMP TDM: ...... connected %i\n", eout->info.connected);
-
- eout->info.screen = _e_comp_screen_output_screen_get(output);
-
- eout->info.edid = ecore_drm_output_edid_get(output);
- if (eout->info.edid)
- eout->id = malloc(strlen(eout->info.name) + 1 + strlen(eout->info.edid) + 1);
- else
- eout->id = malloc(strlen(eout->info.name) + 1 + 1);
- if (!eout->id)
+ if(!e_output_drm_update(eout))
{
- free(eout->info.screen);
- free(eout->info.edid);
- free(eout);
- continue;
+ ERR("fail to e_output_update.");
}
- len = strlen(eout->info.name);
- strncpy(eout->id, eout->info.name, len + 1);
- strncat(eout->id, "/", 1);
- if (eout->info.edid) strncat(eout->id, eout->info.edid, strlen(eout->info.edid));
-
- printf("COMP TDM: ...... screen: %s\n", eout->id);
-
- ecore_drm_output_physical_size_get(output, &eout->info.size.w,
- &eout->info.size.h);
-
- EINA_LIST_FOREACH(ecore_drm_output_modes_get(output), m, omode)
- {
- E_Output_Mode *rmode;
-
- rmode = malloc(sizeof(E_Output_Mode));
- if (!rmode) continue;
+ e_comp_screen->outputs = eina_list_append(e_comp_screen->outputs, eout);
+ }
+ }
- rmode->w = omode->width;
- rmode->h = omode->height;
- rmode->refresh = omode->refresh;
- rmode->preferred = (omode->flags & DRM_MODE_TYPE_PREFERRED);
+ //TODO: if there is no output connected, make the fake output which is connected.
- eout->info.modes = eina_list_append(eout->info.modes, rmode);
- }
+ return EINA_TRUE;
+}
- priority = 0;
- if (ecore_drm_output_primary_get(dev) == output)
- priority = 100;
- eout->config.priority = priority;
+static Eina_Bool
+_e_comp_screen_init_outputs(E_Comp_Screen *e_comp_screen)
+{
+ E_Output *output = NULL;
+ E_Output_Mode *mode = NULL;
+ tdm_display *tdisplay = e_comp_screen->tdisplay;
+ int num_outputs;
+ int i;
- for (j = 0; j < dev->crtc_count; j++)
- {
- if (dev->crtcs[j] == ecore_drm_output_crtc_id_get(output))
- {
- ok = EINA_TRUE;
- break;
- }
- }
+ /* init e_output */
+ if (!e_output_init())
+ {
+ ERR("fail to e_output_init.");
+ return EINA_FALSE;
+ }
- if (!ok)
- {
- /* get possible crtcs, compare to output_crtc_id_get */
- for (j = 0; j < dev->crtc_count; j++)
- {
- if (_e_comp_screen_output_exists(output, dev->crtcs[j]))
- {
- ok = EINA_TRUE;
- possible = EINA_TRUE;
- break;
- }
- }
- }
+ /* get the num of outputs */
+ tdm_display_get_output_count(tdisplay, &num_outputs);
+ if (num_outputs < 1)
+ {
+ ERR("fail to get tdm_display_get_output_count\n");
+ return EINA_FALSE;
+ }
+ e_comp_screen->num_outputs = num_outputs;
- if (ok)
- {
- if (!possible)
- {
- unsigned int refresh;
+ INF("E_COMP_SCREEN: num_outputs = %i", e_comp_screen->num_outputs);
- ecore_drm_output_position_get(output, &eout->config.geom.x,
- &eout->config.geom.y);
- ecore_drm_output_crtc_size_get(output, &eout->config.geom.w,
- &eout->config.geom.h);
+ for (i = 0; i < num_outputs; i++)
+ {
+ output = e_output_new(e_comp_screen, i);
+ if (!output) goto fail;
- ecore_drm_output_current_resolution_get(output,
- &eout->config.mode.w,
- &eout->config.mode.h,
- &refresh);
- eout->config.mode.refresh = refresh;
- eout->config.enabled =
- ((eout->config.mode.w != 0) && (eout->config.mode.h != 0));
+ if (!e_output_update(output))
+ {
+ ERR("fail to e_output_update.");
+ goto fail;
+ }
- printf("COMP TDM: '%s' %i %i %ix%i\n", eout->info.name,
- eout->config.geom.x, eout->config.geom.y,
- eout->config.geom.w, eout->config.geom.h);
+ e_comp_screen->outputs = eina_list_append(e_comp_screen->outputs, output);
- }
+ if (!e_output_connected(output)) continue;
- /* TODO: are rotations possible ?? */
- }
- eout->plane_count = 1; // TODO: get proper value using libtdm
- printf("COMP TDM: planes %i\n", eout->plane_count);
- for (j = 0; j < eout->plane_count; j++)
- {
- printf("COMP TDM: added plane %i\n", j);
- Eina_Bool pri = EINA_FALSE;
- if (j == 0) pri = EINA_TRUE;
- e_plane_new(eout, j, pri);
- }
+ /* setting with the best mode and enable the output */
+ mode = e_output_best_mode_find(output);
+ if (!mode)
+ {
+ ERR("fail to get best mode.");
+ goto fail;
+ }
- r->outputs = eina_list_append(r->outputs, eout);
+ if (!e_output_mode_apply(output, mode))
+ {
+ ERR("fail to e_output_mode_apply.");
+ goto fail;
+ }
+ if (!e_output_dpms_set(output, E_OUTPUT_DPMS_ON))
+ {
+ ERR("fail to e_output_dpms.");
+ goto fail;
}
}
- return r;
-}
+ //TODO: if there is no output connected, make the fake output which is connected.
+
-EINTERN Eina_Bool
-e_comp_screen_available(void)
-{
return EINA_TRUE;
+fail:
+ _e_comp_screen_deinit_outputs(e_comp_screen);
+
+ return EINA_FALSE;
}
-EINTERN void
-e_comp_screen_apply(void)
+static void
+_e_comp_screen_apply(E_Comp_Screen *e_comp_screen)
{
Ecore_Drm_Device *dev;
Ecore_Drm_Output *out;
- E_Output *eout;
+ E_Output *output;
+
const Eina_List *l, *ll;
int nw, nh, pw, ph, ww, hh;
int minw, minh, maxw, maxh;
int top_priority = 0;
+ EINA_SAFETY_ON_NULL_RETURN(e_comp);
+ EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
+
/* TODO: what the actual fuck */
nw = e_comp_screen->w;
nh = e_comp_screen->h;
printf("COMP TDM: set vsize: %ix%i\n", ww, hh);
- EINA_LIST_FOREACH(e_comp_screen->outputs, ll, eout)
+ EINA_LIST_FOREACH(e_comp_screen->outputs, ll, output)
{
Ecore_Drm_Output_Mode *mode = NULL;
- printf("COMP TDM: find output for '%s'\n", eout->info.name);
+ printf("COMP TDM: find output for '%s'\n", output->info.name);
- out = ecore_drm_device_output_name_find(dev, eout->info.name);
+ out = ecore_drm_device_output_name_find(dev, output->info.name);
if (!out) continue;
- mode = _e_comp_screen_mode_screen_find(eout, out);
+ mode = _e_comp_screen_mode_screen_find(output, out);
- if (eout->config.priority > top_priority)
- top_priority = eout->config.priority;
+ if (output->config.priority > top_priority)
+ top_priority = output->config.priority;
- printf("\tCOMP TDM: Priority: %d\n", eout->config.priority);
+ printf("\tCOMP TDM: Priority: %d\n", output->config.priority);
printf("\tCOMP TDM: Geom: %d %d %d %d\n",
- eout->config.geom.x, eout->config.geom.y,
- eout->config.geom.w, eout->config.geom.h);
+ output->config.geom.x, output->config.geom.y,
+ output->config.geom.w, output->config.geom.h);
if (mode)
{
printf("\tCOMP TDM: No Valid Drm Mode Found\n");
ecore_drm_output_mode_set(out, mode,
- eout->config.geom.x, eout->config.geom.y);
- if (eout->config.priority == top_priority)
+ output->config.geom.x, output->config.geom.y);
+ if (output->config.priority == top_priority)
ecore_drm_output_primary_set(out);
ecore_drm_output_enable(out);
printf("\tCOMP TDM: Mode\n");
printf("\t\tCOMP TDM: Geom: %d %d\n",
- eout->config.mode.w, eout->config.mode.h);
- printf("\t\tCOMP TDM: Refresh: %f\n", eout->config.mode.refresh);
+ output->config.mode.w, output->config.mode.h);
+ printf("\t\tCOMP TDM: Refresh: %f\n", output->config.mode.refresh);
printf("\t\tCOMP TDM: Preferred: %d\n",
- eout->config.mode.preferred);
+ output->config.mode.preferred);
}
}
}
_drm_read_pixels(E_Comp_Wl_Output *output, void *pixels)
{
Ecore_Drm_Device *dev;
- Ecore_Drm_Fb *fb = NULL;
+ Ecore_Drm_Fb *fb;
const Eina_List *drm_devs, *l;
int i = 0, bstride;
unsigned char *s, *d = pixels;
if (fb) break;
}
- EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
+ if (!fb) return EINA_FALSE;
bstride = output->w * sizeof(int);
TRACE_INPUT_END();
}
+static void
+_e_comp_screen_config_eval(E_Comp_Screen *e_comp_screen)
+{
+ Eina_List *l;
+ E_Output *output;
+ int minx, miny, maxx, maxy;
+
+ minx = 65535;
+ miny = 65535;
+ maxx = -65536;
+ maxy = -65536;
+
+ EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ {
+ if (!output->config.enabled) continue;
+ if (output->config.geom.x < minx) minx = output->config.geom.x;
+ if (output->config.geom.y < miny) miny = output->config.geom.y;
+ if ((output->config.geom.x + output->config.geom.w) > maxx)
+ maxx = output->config.geom.x + output->config.geom.w;
+ if ((output->config.geom.y + output->config.geom.h) > maxy)
+ maxy = output->config.geom.y + output->config.geom.h;
+ printf("OUTPUT: s: '%s' @ %i %i - %ix%i\n",
+ output->info.name,
+ output->config.geom.x, output->config.geom.y,
+ output->config.geom.w, output->config.geom.h);
+ }
+ printf("OUTPUT:--- %i %i -> %i %i\n", minx, miny, maxx, maxy);
+ EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ {
+ output->config.geom.x -= minx;
+ output->config.geom.y -= miny;
+ }
+ e_comp_screen->w = maxx - minx;
+ e_comp_screen->h = maxy - miny;
+}
+
+static void
+_e_comp_screen_config_maxsize(E_Comp_Screen *e_comp_screen)
+{
+ Eina_List *l;
+ E_Output *output;
+ int maxx, maxy;
+
+ maxx = -65536;
+ maxy = -65536;
+ EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ {
+ if (!output->config.enabled) continue;
+ if ((output->config.geom.x + output->config.geom.w) > maxx)
+ maxx = output->config.geom.x + output->config.geom.w;
+ if ((output->config.geom.y + output->config.geom.h) > maxy)
+ maxy = output->config.geom.y + output->config.geom.h;
+ printf("OUTPUT: '%s': %i %i %ix%i\n",
+ output->info.name,
+ output->config.geom.x, output->config.geom.y,
+ output->config.geom.w, output->config.geom.h);
+ }
+ printf("OUTPUT: result max: %ix%i\n", maxx, maxy);
+ e_comp_screen->w = maxx;
+ e_comp_screen->h = maxy;
+}
+
+static int
+_e_comp_screen_e_screen_sort_cb(const void *data1, const void *data2)
+{
+ const E_Output *s1 = data1, *s2 = data2;
+ int dif;
+
+ dif = -(s1->config.priority - s2->config.priority);
+ if (dif == 0)
+ {
+ dif = s1->config.geom.x - s2->config.geom.x;
+ if (dif == 0)
+ dif = s1->config.geom.y - s2->config.geom.y;
+ }
+ return dif;
+}
+
+static void
+_e_comp_screen_e_screen_free(E_Screen *scr)
+{
+ free(scr->id);
+ free(scr);
+}
+
+static void
+_e_comp_screen_e_screens_set(E_Comp_Screen *e_comp_screen, Eina_List *screens)
+{
+ E_FREE_LIST(e_comp_screen->e_screens, _e_comp_screen_e_screen_free);
+ e_comp_screen->e_screens = screens;
+}
+
+EINTERN void
+e_comp_screen_e_screens_setup(E_Comp_Screen *e_comp_screen, int rw, int rh)
+{
+ int i;
+ E_Screen *screen;
+ Eina_List *outputs = NULL, *outputs_rem;
+ Eina_List *e_screens = NULL;
+ Eina_List *l, *ll;
+ E_Output *output, *s2, *s_chosen;
+ Eina_Bool removed;
+
+ if (!e_comp_screen->outputs) goto out;
+ // put screens in tmp list
+ EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ {
+ if ((output->config.enabled) &&
+ (output->config.geom.w > 0) &&
+ (output->config.geom.h > 0))
+ {
+ outputs = eina_list_append(outputs, output);
+ }
+ }
+ // remove overlapping screens - if a set of screens overlap, keep the
+ // smallest/lowest res
+ do
+ {
+ removed = EINA_FALSE;
+
+ EINA_LIST_FOREACH(outputs, l, output)
+ {
+ outputs_rem = NULL;
+
+ EINA_LIST_FOREACH(l->next, ll, s2)
+ {
+ if (E_INTERSECTS(output->config.geom.x, output->config.geom.y,
+ output->config.geom.w, output->config.geom.h,
+ s2->config.geom.x, s2->config.geom.y,
+ s2->config.geom.w, s2->config.geom.h))
+ {
+ if (!outputs_rem)
+ outputs_rem = eina_list_append(outputs_rem, output);
+ outputs_rem = eina_list_append(outputs_rem, s2);
+ }
+ }
+ // we have intersecting screens - choose the lowest res one
+ if (outputs_rem)
+ {
+ removed = EINA_TRUE;
+ // find the smallest screen (chosen one)
+ s_chosen = NULL;
+ EINA_LIST_FOREACH(outputs_rem, ll, s2)
+ {
+ if (!s_chosen) s_chosen = s2;
+ else
+ {
+ if ((s_chosen->config.geom.w *
+ s_chosen->config.geom.h) >
+ (s2->config.geom.w *
+ s2->config.geom.h))
+ s_chosen = s2;
+ }
+ }
+ // remove all from screens but the chosen one
+ EINA_LIST_FREE(outputs_rem, s2)
+ {
+ if (s2 != s_chosen)
+ outputs = eina_list_remove_list(outputs, l);
+ }
+ // break our list walk and try again
+ break;
+ }
+ }
+ }
+ while (removed);
+ // sort screens by priority etc.
+ outputs = eina_list_sort(outputs, 0, _e_comp_screen_e_screen_sort_cb);
+ i = 0;
+ EINA_LIST_FOREACH(outputs, l, output)
+ {
+ screen = E_NEW(E_Screen, 1);
+ screen->escreen = screen->screen = i;
+ screen->x = output->config.geom.x;
+ screen->y = output->config.geom.y;
+ screen->w = output->config.geom.w;
+ screen->h = output->config.geom.h;
+ if (output->id) screen->id = strdup(output->id);
+
+ e_screens = eina_list_append(e_screens, screen);
+ INF("E INIT: SCREEN: [%i][%i], %ix%i+%i+%i",
+ i, i, screen->w, screen->h, screen->x, screen->y);
+ i++;
+ }
+ eina_list_free(outputs);
+ // if we have NO screens at all (above - i will be 0) AND we have no
+ // existing screens set up in xinerama - then just say root window size
+ // is the entire screen. this should handle the case where you unplug ALL
+ // screens from an existing setup (unplug external monitors and/or close
+ // laptop lid), in which case as long as at least one screen is configured
+ // in xinerama, it will be left-as is until next time we re-eval screen
+ // setup and have at least one screen
+ printf("e_comp_screen_e_screens_setup............... %i %p\n", i, e_comp_screen->e_screens);
+ if ((i == 0) && (!e_comp_screen->e_screens))
+ {
+out:
+ screen = E_NEW(E_Screen, 1);
+ screen->escreen = screen->screen = 0;
+ screen->x = 0;
+ screen->y = 0;
+ if ((rw > 0) && (rh > 0))
+ screen->w = rw, screen->h = rh;
+ else
+ ecore_evas_screen_geometry_get(e_comp->ee, NULL, NULL, &screen->w, &screen->h);
+ e_screens = eina_list_append(e_screens, screen);
+ }
+ _e_comp_screen_e_screens_set(e_comp_screen, e_screens);
+}
+
+EINTERN const Eina_List *
+e_comp_screen_e_screens_get(E_Comp_Screen *e_comp_screen)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, NULL);
+
+ return e_comp_screen->e_screens;
+}
+
E_API Eina_Bool
e_comp_screen_init()
{
E_Comp *comp;
+ E_Comp_Screen *e_comp_screen = NULL;
+
int w = 0, h = 0, scr_w = 1, scr_h = 1;
struct xkb_context *ctx = NULL;
struct xkb_keymap *map = NULL;
char buf[1024];
- dont_set_ecore_drm_keymap = getenv("NO_ECORE_DRM_KEYMAP_CACHE") ? EINA_TRUE : EINA_FALSE;
- dont_use_xkb_cache = getenv("NO_KEYMAP_CACHE") ? EINA_TRUE : EINA_FALSE;
-
- TRACE_DS_BEGIN(WL_DRM:INIT);
-
+ TRACE_DS_BEGIN(E_COMP_SCREEN:INIT);
if (!(comp = e_comp))
{
- comp = e_comp_new();
- if (!comp)
- {
- TRACE_DS_END();
- EINA_SAFETY_ON_NULL_RETURN_VAL(comp, EINA_FALSE);
- }
-
- comp->comp_type = E_PIXMAP_TYPE_WL;
+ TRACE_DS_END();
+ EINA_SAFETY_ON_NULL_RETURN_VAL(comp, EINA_FALSE);
}
/* set gl available if we have ecore_evas support */
INF("GL available:%d config engine:%d screen size:%dx%d",
e_comp_gl_get(), e_comp_config_get()->engine, scr_w, scr_h);
- if (e_config->xkb.use_cache && !dont_use_xkb_cache)
- {
- e_main_ts("\tDRM Keymap Init");
- _e_comp_screen_keymap_set(&ctx, &map);
- e_main_ts("\tDRM Keymap Init Done");
- }
-
if ((e_comp_gl_get()) &&
(e_comp_config_get()->engine == E_COMP_ENGINE_GL))
{
ecore_evas_callback_resize_set(e_comp->ee, _e_comp_screen_cb_ee_resize);
- e_main_ts("\tE_Output Init");
- if (!e_output_init())
+ /* e_comp_screen new */
+ e_comp_screen = _e_comp_screen_new();
+ if (!e_comp_screen)
{
- e_error_message_show(_("Enlightenment cannot initialize output!\n"));
TRACE_DS_END();
- return EINA_FALSE;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE);
+ }
+ e_comp->e_comp_screen = e_comp_screen;
+
+ e_main_ts("\tE_Outputs Init");
+ if (e_comp_gl_get())
+ {
+ if (!_e_comp_screen_init_outputs(e_comp_screen))
+ {
+ e_error_message_show(_("Enlightenment cannot initialize outputs!\n"));
+ _e_comp_screen_del(e_comp_screen);
+ e_comp->e_comp_screen = NULL;
+ TRACE_DS_END();
+ return EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (!_e_comp_screen_init_drm_outputs(e_comp_screen))
+ {
+ e_error_message_show(_("Enlightenment cannot initialize outputs!\n"));
+ _e_comp_screen_del(e_comp_screen);
+ e_comp->e_comp_screen = NULL;
+ TRACE_DS_END();
+ return EINA_FALSE;
+ }
+
+ // take current e_output config and apply it to the driver
+ _e_comp_screen_config_maxsize(e_comp_screen);
+ printf("OUTPUT: eval config...\n");
+ _e_comp_screen_config_eval(e_comp_screen);
+ printf("OUTPUT: really apply config...\n");
+ _e_comp_screen_apply(e_comp_screen);
+ printf("OUTPUT: done config...\n");
}
- e_output_screens_setup(-1, -1);
- e_main_ts("\tE_Output Init Done");
+
+ if (!E_EVENT_SCREEN_CHANGE) E_EVENT_SCREEN_CHANGE = ecore_event_type_new();
+
+ ecore_event_add(E_EVENT_SCREEN_CHANGE, NULL, NULL, NULL);
+
+ e_comp_screen_e_screens_setup(e_comp_screen, -1, -1);
+ e_main_ts("\tE_Outputs Init Done");
e_main_ts("\tE_Comp_Wl Init");
if (!e_comp_wl_init())
}
e_main_ts("\tE_Comp_Wl Init Done");
+ /* canvas */
e_main_ts("\tE_Comp_Canvas Init");
if (!e_comp_canvas_init(w, h))
{
+ e_error_message_show(_("Enlightenment cannot initialize outputs!\n"));
+ _e_comp_screen_deinit_outputs(e_comp->e_comp_screen);
+ _e_comp_screen_del(e_comp_screen);
+ e_comp->e_comp_screen = NULL;
TRACE_DS_END();
return EINA_FALSE;
}
e_comp_wl->screenshooter.read_pixels = _drm_read_pixels;
+ /* pointer */
ecore_evas_pointer_xy_get(e_comp->ee,
&e_comp_wl->ptr.x,
&e_comp_wl->ptr.y);
}
e_main_ts("\tE_Pointer New Done");
+ /* keymap */
+ dont_set_ecore_drm_keymap = getenv("NO_ECORE_DRM_KEYMAP_CACHE") ? EINA_TRUE : EINA_FALSE;
+ dont_use_xkb_cache = getenv("NO_KEYMAP_CACHE") ? EINA_TRUE : EINA_FALSE;
+
+ if (e_config->xkb.use_cache && !dont_use_xkb_cache)
+ {
+ e_main_ts("\tDRM Keymap Init");
+ _e_comp_screen_keymap_set(&ctx, &map);
+ e_main_ts("\tDRM Keymap Init Done");
+ }
+
/* FIXME: We need a way to trap for user changing the keymap inside of E
* without the event coming from X11 */
e_main_ts("\tE_Comp_WL Keymap Init Done");
E_LIST_HANDLER_APPEND(event_handlers, ECORE_DRM_EVENT_ACTIVATE, _e_comp_screen_cb_activate, comp);
- E_LIST_HANDLER_APPEND(event_handlers, ECORE_DRM_EVENT_OUTPUT, _e_comp_screen_cb_output, comp);
+ E_LIST_HANDLER_APPEND(event_handlers, ECORE_DRM_EVENT_OUTPUT, _e_comp_screen_cb_output_drm, comp);
E_LIST_HANDLER_APPEND(event_handlers, ECORE_DRM_EVENT_INPUT_DEVICE_ADD, _e_comp_screen_cb_input_device_add, comp);
E_LIST_HANDLER_APPEND(event_handlers, ECORE_DRM_EVENT_INPUT_DEVICE_DEL, _e_comp_screen_cb_input_device_del, comp);
+#ifdef ENABLE_HWC_MULTI
+ ecore_idle_enterer_add(_e_comp_screen_commit_idle_cb, comp);
+#endif
+
TRACE_DS_END();
return EINA_TRUE;
E_API void
e_comp_screen_shutdown()
{
+ if (!e_comp) return;
+ if (!e_comp->e_comp_screen) return;
+
/* shutdown ecore_drm */
/* ecore_drm_shutdown(); */
- e_output_shutdown();
+
+ _e_comp_screen_deinit_outputs(e_comp->e_comp_screen);
dont_set_ecore_drm_keymap = EINA_FALSE;
dont_use_xkb_cache = EINA_FALSE;
E_FREE_LIST(event_handlers, ecore_event_handler_del);
+ /* delete e_comp_sreen */
+ _e_comp_screen_del(e_comp->e_comp_screen);
+ e_comp->e_comp_screen = NULL;
+}
+
+EINTERN Eina_Bool
+e_comp_screen_hwc_setup(E_Comp_Screen *e_comp_screen)
+{
+ Eina_List *l, *ll;
+ E_Output *output = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, EINA_FALSE);
+
+ EINA_LIST_FOREACH_SAFE(e_comp_screen->outputs, l, ll, output)
+ {
+ if (!output) continue;
+ if (!output->config.enabled) continue;
+
+ if (!e_output_hwc_setup(output))
+ {
+ ERR("fail to e_ouptut_hwc_setup.");
+ continue;
+ }
+ }
+
+ return EINA_TRUE;
}
#ifndef E_COMP_SCREEN_H
#define E_COMP_SCREEN_H
+#include <tdm.h>
-EINTERN Eina_Bool e_comp_screen_available(void);
-EINTERN void e_comp_screen_stub(void);
-EINTERN void e_comp_screen_apply(void);
-EINTERN E_Comp_Screen * e_comp_screen_init_outputs(void);
-EINTERN void e_comp_screen_dpms(int set);
+typedef struct _E_Comp_Screen E_Comp_Screen;
+typedef struct _E_Screen E_Screen;
-E_API Eina_Bool e_comp_screen_init(void);
-E_API void e_comp_screen_shutdown(void);
+struct _E_Comp_Screen
+{
+ Eina_List *outputs; // available screens
+ int w, h; // virtual resolution (calculated)
+ unsigned char ignore_hotplug_events;
+ unsigned char ignore_acpi_events;
+ Eina_List *e_screens;
+
+ int num_outputs;
+ tdm_display *tdisplay;
+
+ /* for sw compositing */
+ const Eina_List *devices;
+};
+
+
+struct _E_Screen
+{
+ int screen, escreen;
+ int x, y, w, h;
+ char *id; // this is the same id we get from _E_Output so look it up there
+};
+
+extern E_API int E_EVENT_SCREEN_CHANGE;
+
+E_API Eina_Bool e_comp_screen_init(void);
+E_API void e_comp_screen_shutdown(void);
+EINTERN Eina_Bool e_comp_screen_hwc_setup(E_Comp_Screen *e_comp_screen);
+
+EINTERN void e_comp_screen_e_screens_setup(E_Comp_Screen *e_comp_screen, int rw, int rh);
+EINTERN const Eina_List * e_comp_screen_e_screens_get(E_Comp_Screen *e_comp_screen);
#endif /*E_COMP_SCREEN_H*/
{
Eina_List *l;
E_Output *eout;
+ E_Comp_Screen *e_comp_screen;
unsigned int transform = WL_OUTPUT_TRANSFORM_NORMAL;
- if (!e_comp_screen) return ECORE_CALLBACK_RENEW;
+ if (!e_comp) return ECORE_CALLBACK_RENEW;
+ if (!e_comp->e_comp_screen) return ECORE_CALLBACK_RENEW;
+ e_comp_screen = e_comp->e_comp_screen;
EINA_LIST_FOREACH(e_comp_screen->outputs, l, eout)
{
#include "e_env.h"
#include "e_log.h"
#include "e_dbusmenu.h"
+#include "e_comp_screen.h"
#include "e_comp.h"
#include "e_comp_cfdata.h"
#include "e_comp_canvas.h"
#include "e_hints.h"
#include "e_plane.h"
#include "e_comp_hwc.h"
-#include "e_comp_screen.h"
#include "e_output.h"
#include "e_comp_wl.h"
#include "e_comp_wl_data.h"
#include "e.h"
+# include <Evas_Engine_GL_Drm.h>
-/////////////////////////////////////////////////////////////////////////
-static void _do_apply(void);
-static void _info_free(E_Comp_Screen *r);
-static void _screen_config_eval(void);
-static void _screen_config_maxsize(void);
+static void
+_e_output_cb_output_change(tdm_output *toutput,
+ tdm_output_change_type type,
+ tdm_value value,
+ void *user_data)
+{
+ E_Output *e_output = NULL;
+ E_OUTPUT_DPMS edpms;
+ tdm_output_dpms tdpms = (tdm_output_dpms)value.u32;
-/////////////////////////////////////////////////////////////////////////
+ EINA_SAFETY_ON_NULL_RETURN(toutput);
+ EINA_SAFETY_ON_NULL_RETURN(user_data);
-E_API E_Comp_Screen *e_comp_screen = NULL;
+ e_output = (E_Output *)user_data;
-E_API int E_EVENT_SCREEN_CHANGE = 0;
+ switch (type)
+ {
+ case TDM_OUTPUT_CHANGE_DPMS:
+ if (tdpms == TDM_OUTPUT_DPMS_OFF) edpms = E_OUTPUT_DPMS_OFF;
+ else if (tdpms == E_OUTPUT_DPMS_ON) edpms = E_OUTPUT_DPMS_ON;
+ else if (tdpms == TDM_OUTPUT_DPMS_STANDBY) edpms = E_OUTPUT_DPMS_STANDBY;
+ else if (tdpms == TDM_OUTPUT_DPMS_SUSPEND) edpms = E_OUTPUT_DPMS_SUSPEND;
+ else edpms = e_output->dpms;
+
+ ERR("[cyeon] dpms change:%d", edpms);
+ e_output->dpms = edpms;
+ break;
+ default:
+ break;
+ }
+}
-static Eina_List *all_screens = NULL; // e_screen list
+static void
+_e_output_commit_hanler(tdm_output *output, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ Eina_List *data_list = user_data;
+ E_Plane_Commit_Data *data = NULL;
+ Eina_List *l, *ll;
-/////////////////////////////////////////////////////////////////////////
-EINTERN Eina_Bool
-e_output_init(void)
+ EINA_LIST_FOREACH_SAFE(data_list, l, ll, data)
+ {
+ e_plane_commit_data_release(data);
+ data_list = eina_list_remove_list(data_list, l);
+ data = NULL;
+ }
+}
+
+static Eina_Bool
+_e_output_commit(E_Output *output)
{
- if (!E_EVENT_SCREEN_CHANGE) E_EVENT_SCREEN_CHANGE = ecore_event_type_new();
- if (!e_comp_screen_available()) return EINA_FALSE;
+ Eina_List *data_list = NULL;
+ E_Plane_Commit_Data *data = NULL;
+ E_Plane *plane = NULL;
+ Eina_List *l, *ll;
+ tdm_error error;
- e_comp_screen = e_comp_screen_init_outputs();
+ EINA_LIST_REVERSE_FOREACH(output->planes, l, plane)
+ {
+ data = e_plane_commit_data_aquire(plane);
+ if (!data) continue;
+ data_list = eina_list_append(data_list, data);
+ }
- _do_apply();
+ error = tdm_output_commit(output->toutput, 0, _e_output_commit_hanler, data_list);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("fail to tdm_output_commit");
+ EINA_LIST_FOREACH_SAFE(data_list, l, ll, data)
+ {
+ data_list = eina_list_remove_list(data_list, l);
+ e_plane_commit_data_release(data);
+ data = NULL;
+ }
+ return EINA_FALSE;
+ }
- ecore_event_add(E_EVENT_SCREEN_CHANGE, NULL, NULL, NULL);
+ return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_output_init(void)
+{
+#if 0
+ Evas_Engine_Info_GL_Drm *einfo;
+ /* TODO: enable hwc according to the conf->hwc */
+ if (e_comp_gl_get())
+ {
+ /* get the evas_engine_gl_drm information */
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ if (!einfo) return EINA_FALSE;
+ /* enable hwc to evas engine gl_drm */
+ einfo->info.hwc_enable = EINA_TRUE;
+ }
+#endif
return EINA_TRUE;
}
-EINTERN int
+EINTERN void
e_output_shutdown(void)
{
- // free up screen info
- _info_free(e_comp_screen);
- e_comp_screen = NULL;
-
- return 1;
+ ;
}
-/////////////////////////////////////////////////////////////////////////
+EINTERN E_Output *
+e_output_drm_new(Ecore_Drm_Output *output)
+{
+ E_Output *eout = NULL;
+ int i;
-static void
-_do_apply(void)
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+ eout = E_NEW(E_Output, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(eout, NULL);
+
+ eout->info.name = ecore_drm_output_name_get(output);
+ printf("E_OUTPUT: .... out %s\n", eout->info.name);
+
+ // TODO: get proper value using libtdm
+ eout->plane_count = 1;
+ printf("COMP TDM: planes %i\n", eout->plane_count);
+ for (i = 0; i < eout->plane_count; i++)
+ {
+ printf("COMP TDM: added plane %i\n", i);
+ // TODO: primary layer condition (0 is temp condition)
+ e_plane_new(eout, i);
+ }
+
+ eout->output = output;
+
+ return eout;
+}
+
+EINTERN E_Output *
+e_output_new(E_Comp_Screen *e_comp_screen, int index)
{
- // take current e_output config and apply it to the driver
- _screen_config_maxsize();
- printf("OUTPUT: eval config...\n");
- _screen_config_eval();
- printf("OUTPUT: really apply config...\n");
- e_comp_screen_apply();
- printf("OUTPUT: done config...\n");
+ E_Output *output = NULL;
+ E_Plane *plane = NULL;
+ tdm_output *toutput = NULL;
+ tdm_error error;
+ char *id = NULL;
+ const char *name;
+ int num_layers;
+ int i;
+ int size = 0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp_screen, NULL);
+
+ output = E_NEW(E_Output, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ output->index = index;
+
+ toutput = tdm_display_get_output(e_comp_screen->tdisplay, index, NULL);
+ if (!toutput) goto fail;
+ output->toutput = toutput;
+
+ error = tdm_output_get_model_info(toutput, NULL, NULL, &name);
+ if (error != TDM_ERROR_NONE) goto fail;
+
+ error = tdm_output_add_change_handler(toutput, _e_output_cb_output_change, output);
+ EINA_SAFETY_ON_FALSE_GOTO(error == TDM_ERROR_NONE, fail);
+
+ size = strlen(name) + 4;
+ id = calloc(1, size);
+ if (!id) return NULL;
+ snprintf(id, size, "%s-%d", name, index);
+
+ output->id = id;
+ INF("E_OUTPUT: (%d) output_id = %s", index, output->id);
+
+ tdm_output_get_layer_count(toutput, &num_layers);
+ if (num_layers < 1)
+ {
+ ERR("fail to get tdm_output_get_layer_count\n");
+ goto fail;
+ }
+ output->plane_count = num_layers;
+ INF("E_OUTPUT: num_planes %i", output->plane_count);
+
+ if (!e_plane_init())
+ {
+ ERR("fail to e_plane_init.");
+ goto fail;
+ }
+
+ for (i = 0; i < output->plane_count; i++)
+ {
+ plane = e_plane_new(output, i);
+ if (!plane)
+ {
+ ERR("fail to create the e_plane.");
+ goto fail;
+ }
+ output->planes = eina_list_append(output->planes, plane);
+ }
+
+ output->e_comp_screen = e_comp_screen;
+
+
+ return output;
+
+fail:
+ if (output) e_output_del(output);
+
+ return NULL;
}
-static void
-_info_free(E_Comp_Screen *r)
+EINTERN void
+e_output_del(E_Output *output)
{
- E_Output *output;
+ E_Plane *plane;
E_Output_Mode *m;
- E_Plane *ep;
- if (!r) return;
- // free up our output screen data
- EINA_LIST_FREE(r->outputs, output)
+ if (!output) return;
+
+ e_plane_shutdown();
+
+ if (output->id) free(output->id);
+ if (output->info.screen) free(output->info.screen);
+ if (output->info.name) free(output->info.name);
+ if (output->info.edid) free(output->info.edid);
+
+ tdm_output_remove_change_handler(output->toutput, _e_output_cb_output_change, output);
+
+ EINA_LIST_FREE(output->info.modes, m) free(m);
+
+ EINA_LIST_FREE(output->planes, plane) e_plane_free(plane);
+ free(output);
+}
+
+EINTERN Eina_Bool
+e_output_update(E_Output *output)
+{
+ Eina_List *m = NULL;
+ Eina_List *modes = NULL;
+ Eina_Bool connected = EINA_TRUE;
+ tdm_error error;
+ tdm_output_conn_status status;
+ int i;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ error = tdm_output_get_conn_status(output->toutput, &status);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("failt to get conn status.");
+ return EINA_FALSE;
+ }
+
+ if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) connected = EINA_FALSE;
+
+ if (connected)
+ {
+ /* disconnect --> connect */
+ if (connected != output->info.connected)
+ {
+ char *name;
+ const char *screen;
+ const char *maker;
+ unsigned int phy_w, phy_h;
+ const tdm_output_mode *tmodes = NULL;
+ int num_tmodes = 0;
+ int size = 0;
+
+ error = tdm_output_get_model_info(output->toutput, &maker, &screen, NULL);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("fail to get model info.");
+ return EINA_FALSE;
+ }
+
+ if (maker)
+ {
+ size = strlen(output->id) + 1 + strlen(maker) + 1;
+ name = calloc(1, size);
+ if (!name) return EINA_FALSE;
+ snprintf(name, size, "%s-%s", output->id, maker);
+ }
+ else
+ {
+ size = strlen(output->id) + 1;
+ name = calloc(1, size);
+ if (!name) return EINA_FALSE;
+ snprintf(name, size, "%s", output->id);
+ }
+ INF("E_OUTPUT: screen = %s, name = %s", screen, name);
+
+ error = tdm_output_get_physical_size(output->toutput, &phy_w, &phy_h);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("fail to get physical_size.");
+ free(name);
+ return EINA_FALSE;
+ }
+
+ error = tdm_output_get_available_modes(output->toutput, &tmodes, &num_tmodes);
+ if (error != TDM_ERROR_NONE || num_tmodes == 0)
+ {
+ ERR("fail to get tmodes");
+ free(name);
+ return EINA_FALSE;
+ }
+
+ for (i = 0; i < num_tmodes; i++)
+ {
+ E_Output_Mode *rmode;
+
+ rmode = malloc(sizeof(E_Output_Mode));
+ if (!rmode) continue;
+
+ rmode->w = tmodes[i].hdisplay;
+ rmode->h = tmodes[i].vdisplay;
+ rmode->refresh = tmodes[i].vrefresh;
+ rmode->preferred = (tmodes[i].flags & TDM_OUTPUT_MODE_TYPE_PREFERRED);
+ rmode->tmode = &tmodes[i];
+
+ modes = eina_list_append(modes, rmode);
+ }
+
+ /* resetting the output->info */
+ if (output->info.screen) free(output->info.screen);
+ if (output->info.name) free(output->info.name);
+ EINA_LIST_FREE(output->info.modes, m) free(m);
+
+ output->info.screen = strdup(screen);
+ output->info.name = name;
+ output->info.modes = modes;
+ output->info.size.w = phy_w;
+ output->info.size.h = phy_h;
+
+ output->info.connected = EINA_TRUE;
+
+ INF("E_OUTPUT: id(%s) connected..", output->id);
+ }
+
+#if 0
+ /* check the crtc setting */
+ if (status != TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
+ {
+ const tdm_output_mode *mode = NULL;
+
+ error = tdm_output_get_mode(output->toutput, &mode);
+ if (error != TDM_ERROR_NONE || mode == NULL)
+ {
+ ERR("fail to get mode.");
+ return EINA_FALSE;
+ }
+
+ output->config.geom.x = 0;
+ output->config.geom.y = 0;
+ output->config.geom.w = mode->hdisplay;
+ output->config.geom.h = mode->vdisplay;
+
+ output->config.mode.w = mode->hdisplay;
+ output->config.mode.h = mode->vdisplay;
+ output->config.mode.refresh = mode->vrefresh;
+
+ output->config.enabled = 1;
+
+ INF("E_OUTPUT: '%s' %i %i %ix%i", output->info.name,
+ output->config.geom.x, output->config.geom.y,
+ output->config.geom.w, output->config.geom.h);
+ }
+#endif
+
+ }
+ else
{
- free(output->id);
- free(output->info.screen);
- free(output->info.name);
- free(output->info.edid);
+ output->info.connected = EINA_FALSE;
+
+ /* reset output info */
+ if (output->info.screen)
+ {
+ free(output->info.screen);
+ output->info.screen = NULL;
+ }
+ if (output->info.name)
+ {
+ free(output->info.name);
+ output->info.name = NULL;
+ }
EINA_LIST_FREE(output->info.modes, m) free(m);
- EINA_LIST_FREE(output->planes, ep) e_plane_free(ep);
- free(output);
+ output->info.modes = NULL;
+
+ output->info.size.w = 0;
+ output->info.size.h = 0;
+
+ /* reset output config */
+ output->config.geom.x = 0;
+ output->config.geom.y = 0;
+ output->config.geom.w = 0;
+ output->config.geom.h = 0;
+
+ output->config.mode.w = 0;
+ output->config.mode.h = 0;
+ output->config.mode.refresh = 0;
+
+ output->config.rotation = 0;
+ output->config.priority = 0;
+ output->config.enabled = 0;
+
+ INF("E_OUTPUT: disconnected.. id: %s", output->id);
}
- free(r);
+
+ return EINA_TRUE;
}
-static void
-_screen_config_eval(void)
+EINTERN Eina_Bool
+e_output_mode_apply(E_Output *output, E_Output_Mode *mode)
{
- Eina_List *l;
- E_Output *output;
- int minx, miny, maxx, maxy;
+ tdm_error error;
- minx = 65535;
- miny = 65535;
- maxx = -65536;
- maxy = -65536;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
- EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ if (!output->info.connected)
{
- if (!output->config.enabled) continue;
- if (output->config.geom.x < minx) minx = output->config.geom.x;
- if (output->config.geom.y < miny) miny = output->config.geom.y;
- if ((output->config.geom.x + output->config.geom.w) > maxx)
- maxx = output->config.geom.x + output->config.geom.w;
- if ((output->config.geom.y + output->config.geom.h) > maxy)
- maxy = output->config.geom.y + output->config.geom.h;
- printf("OUTPUT: s: '%s' @ %i %i - %ix%i\n",
- output->info.name,
- output->config.geom.x, output->config.geom.y,
- output->config.geom.w, output->config.geom.h);
+ ERR("output is not connected.");
+ return EINA_FALSE;
}
- printf("OUTPUT:--- %i %i -> %i %i\n", minx, miny, maxx, maxy);
- EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+
+ error = tdm_output_set_mode(output->toutput, mode->tmode);
+ if (error != TDM_ERROR_NONE)
{
- output->config.geom.x -= minx;
- output->config.geom.y -= miny;
+ ERR("fail to set tmode.");
+ return EINA_FALSE;
}
- e_comp_screen->w = maxx - minx;
- e_comp_screen->h = maxy - miny;
+
+ output->config.geom.x = 0;
+ output->config.geom.y = 0;
+ output->config.geom.w = mode->w;
+ output->config.geom.h = mode->h;
+
+ output->config.mode.w = mode->w;
+ output->config.mode.h = mode->h;
+ output->config.mode.refresh = mode->refresh;
+
+ output->config.enabled = 1;
+
+ INF("E_OUTPUT: '%s' %i %i %ix%i", output->info.name,
+ output->config.geom.x, output->config.geom.y,
+ output->config.geom.w, output->config.geom.h);
+
+ return EINA_TRUE;
}
-static void
-_screen_config_maxsize(void)
+EINTERN Eina_Bool
+e_output_hwc_setup(E_Output *output)
{
- Eina_List *l;
- E_Output *output;
- int maxx, maxy;
+ Eina_List *l, *ll;
+ E_Plane *plane = NULL;
- maxx = -65536;
- maxy = -65536;
- EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ EINA_LIST_FOREACH_SAFE(output->planes, l, ll, plane)
{
- if (!output->config.enabled) continue;
- if ((output->config.geom.x + output->config.geom.w) > maxx)
- maxx = output->config.geom.x + output->config.geom.w;
- if ((output->config.geom.y + output->config.geom.h) > maxy)
- maxy = output->config.geom.y + output->config.geom.h;
- printf("OUTPUT: '%s': %i %i %ix%i\n",
- output->info.name,
- output->config.geom.x, output->config.geom.y,
- output->config.geom.w, output->config.geom.h);
+ if (plane->is_primary)
+ {
+ if (!e_plane_hwc_setup(plane)) return EINA_FALSE;
+ else return EINA_TRUE;
+ }
}
- printf("OUTPUT: result max: %ix%i\n", maxx, maxy);
- e_comp_screen->w = maxx;
- e_comp_screen->h = maxy;
+
+ return EINA_FALSE;
}
-static int
-_screen_sort_cb(const void *data1, const void *data2)
+
+EINTERN E_Output_Mode *
+e_output_best_mode_find(E_Output *output)
{
- const E_Output *s1 = data1, *s2 = data2;
- int dif;
+ Eina_List *l = NULL;
+ E_Output_Mode *mode = NULL;
+ E_Output_Mode *best_mode = NULL;
+ int best_size = 0;
+ int size = 0;
+ double best_refresh = 0.0;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output->info.modes, NULL);
+
+ if (!output->info.connected)
+ {
+ ERR("output is not connected.");
+ return EINA_FALSE;
+ }
- dif = -(s1->config.priority - s2->config.priority);
- if (dif == 0)
+ EINA_LIST_FOREACH(output->info.modes, l, mode)
{
- dif = s1->config.geom.x - s2->config.geom.x;
- if (dif == 0)
- dif = s1->config.geom.y - s2->config.geom.y;
+ size = mode->w + mode->h;
+ if (size > best_size) best_mode = mode;
+ if (size == best_size && mode->refresh > best_refresh) best_mode = mode;
}
- return dif;
+
+ return best_mode;
}
-static void
-_escreen_free(E_Screen *scr)
+EINTERN Eina_Bool
+e_output_connected(E_Output *output)
{
- free(scr->id);
- free(scr);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ return output->info.connected;
}
-void
-_escreens_set(Eina_List *screens)
+EINTERN Eina_Bool
+e_output_dpms_set(E_Output *output, E_OUTPUT_DPMS val)
{
- E_FREE_LIST(all_screens, _escreen_free);
- all_screens = screens;
+ tdm_output_dpms tval;
+ Eina_Bool ret = EINA_TRUE;
+ tdm_error error;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ if (val == E_OUTPUT_DPMS_OFF) tval = TDM_OUTPUT_DPMS_OFF;
+ else if (val == E_OUTPUT_DPMS_ON) tval = TDM_OUTPUT_DPMS_ON;
+ else if (val == E_OUTPUT_DPMS_STANDBY) tval = TDM_OUTPUT_DPMS_STANDBY;
+ else if (val == E_OUTPUT_DPMS_SUSPEND) tval = TDM_OUTPUT_DPMS_SUSPEND;
+ else ret = EINA_FALSE;
+
+ if (!ret) return EINA_FALSE;
+
+ error = tdm_output_set_dpms(output->toutput, tval);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("fail to set the dpms(value:%d).", tval);
+ return EINA_FALSE;
+ }
+
+ output->dpms = val;
+
+ return EINA_TRUE;
}
-EINTERN void
-e_output_screens_setup(int rw, int rh)
+static char *
+_e_output_drm_model_get(Ecore_Drm_Output *output)
{
- int i;
- E_Screen *screen;
- Eina_List *outputs = NULL, *outputs_rem;
- Eina_List *e_screens = NULL;
- Eina_List *l, *ll;
- E_Output *output, *s2, *s_chosen;
- Eina_Bool removed;
+ const char *model;
- if ((!e_comp_screen) || (!e_comp_screen->outputs)) goto out;
- // put screens in tmp list
- EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ model = ecore_drm_output_model_get(output);
+ if (!model) return NULL;
+
+ return strdup(model);
+}
+
+EINTERN Eina_Bool
+e_output_drm_update(E_Output *eout)
+{
+ Eina_List *m = NULL;
+ Eina_List *modes = NULL;
+ Eina_Bool connected;
+ E_Comp_Screen *e_comp_screen;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(eout, EINA_FALSE);
+
+ e_comp_screen = e_comp->e_comp_screen;
+
+ connected = ecore_drm_output_connected_get(eout->output);
+ if (connected)
{
- if ((output->config.enabled) &&
- (output->config.geom.w > 0) &&
- (output->config.geom.h > 0))
+ /* disconnect --> connect */
+ if (connected != eout->info.connected)
{
- outputs = eina_list_append(outputs, output);
- }
- }
- // remove overlapping screens - if a set of screens overlap, keep the
- // smallest/lowest res
- do
- {
- removed = EINA_FALSE;
+ int len = 0;
+ char *id;
+ char *screen;
+ char *edid;
+ int phy_w, phy_h;
+ Ecore_Drm_Output_Mode *omode;
+
+ screen = _e_output_drm_model_get(eout->output);
+ edid = ecore_drm_output_edid_get(eout->output);
+ if (eout->info.edid)
+ id = malloc(strlen(eout->info.name) + 1 + strlen(eout->info.edid) + 1);
+ else
+ id = malloc(strlen(eout->info.name) + 1 + 1);
+ if (!id)
+ {
+ free(edid);
+ return EINA_FALSE;
+ }
+ len = strlen(eout->info.name);
+ strncpy(id, eout->info.name, len + 1);
+ strncat(id, "/", 1);
+ if (eout->info.edid) strncat(id, edid, strlen(edid));
- EINA_LIST_FOREACH(outputs, l, output)
- {
- outputs_rem = NULL;
+ printf("E_OUTPUT: ...... screen: %s\n", id);
- EINA_LIST_FOREACH(l->next, ll, s2)
+ ecore_drm_output_physical_size_get(eout->output, &phy_w, &phy_h);
+
+ EINA_LIST_FOREACH(ecore_drm_output_modes_get(eout->output), m, omode)
{
- if (E_INTERSECTS(output->config.geom.x, output->config.geom.y,
- output->config.geom.w, output->config.geom.h,
- s2->config.geom.x, s2->config.geom.y,
- s2->config.geom.w, s2->config.geom.h))
- {
- if (!outputs_rem)
- outputs_rem = eina_list_append(outputs_rem, output);
- outputs_rem = eina_list_append(outputs_rem, s2);
- }
+ E_Output_Mode *rmode;
+
+ rmode = malloc(sizeof(E_Output_Mode));
+ if (!rmode) continue;
+
+ rmode->w = omode->width;
+ rmode->h = omode->height;
+ rmode->refresh = omode->refresh;
+ rmode->preferred = (omode->flags & DRM_MODE_TYPE_PREFERRED);
+
+ modes = eina_list_append(modes, rmode);
}
- // we have intersecting screens - choose the lowest res one
- if (outputs_rem)
+
+ free(eout->id);
+ free(eout->info.screen);
+ free(eout->info.edid);
+ EINA_LIST_FREE(eout->info.modes, m) free(m);
+
+ eout->id = id;
+ eout->info.screen = screen;
+ eout->info.edid = edid;
+ eout->info.modes = modes;
+ eout->info.size.w = phy_w;
+ eout->info.size.h = phy_h;
+
+ eout->info.connected = EINA_TRUE;
+
+ printf("E_OUTPUT: connected.. id: %s\n", eout->id);
+ }
+
+ /* check the crtc setting */
+ const Eina_List *l;
+ int i;
+ unsigned int refresh;
+ Ecore_Drm_Device *dev;
+
+ EINA_LIST_FOREACH(e_comp_screen->devices, l, dev)
+ {
+ if (ecore_drm_output_primary_get(dev) == eout->output)
+ eout->config.priority = 100;
+
+ for (i = 0; i < dev->crtc_count; i++)
{
- removed = EINA_TRUE;
- // find the smallest screen (chosen one)
- s_chosen = NULL;
- EINA_LIST_FOREACH(outputs_rem, ll, s2)
- {
- if (!s_chosen) s_chosen = s2;
- else
- {
- if ((s_chosen->config.geom.w *
- s_chosen->config.geom.h) >
- (s2->config.geom.w *
- s2->config.geom.h))
- s_chosen = s2;
- }
- }
- // remove all from screens but the chosen one
- EINA_LIST_FREE(outputs_rem, s2)
+ if (dev->crtcs[i] == ecore_drm_output_crtc_id_get(eout->output))
{
- if (s2 != s_chosen)
- outputs = eina_list_remove_list(outputs, l);
+ ecore_drm_output_position_get(eout->output, &eout->config.geom.x,
+ &eout->config.geom.y);
+ ecore_drm_output_crtc_size_get(eout->output, &eout->config.geom.w,
+ &eout->config.geom.h);
+ ecore_drm_output_current_resolution_get(eout->output,
+ &eout->config.mode.w,
+ &eout->config.mode.h,
+ &refresh);
+ eout->config.mode.refresh = refresh;
+ eout->config.enabled =
+ ((eout->config.mode.w != 0) && (eout->config.mode.h != 0));
+
+ printf("E_OUTPUT: '%s' %i %i %ix%i\n", eout->info.name,
+ eout->config.geom.x, eout->config.geom.y,
+ eout->config.geom.w, eout->config.geom.h);
+ break;
}
- // break our list walk and try again
- break;
}
}
}
- while (removed);
- // sort screens by priority etc.
- outputs = eina_list_sort(outputs, 0, _screen_sort_cb);
- i = 0;
- EINA_LIST_FOREACH(outputs, l, output)
- {
- screen = E_NEW(E_Screen, 1);
- screen->escreen = screen->screen = i;
- screen->x = output->config.geom.x;
- screen->y = output->config.geom.y;
- screen->w = output->config.geom.w;
- screen->h = output->config.geom.h;
- if (output->id) screen->id = strdup(output->id);
-
- e_screens = eina_list_append(e_screens, screen);
- INF("E INIT: SCREEN: [%i][%i], %ix%i+%i+%i",
- i, i, screen->w, screen->h, screen->x, screen->y);
- i++;
- }
- eina_list_free(outputs);
- // if we have NO screens at all (above - i will be 0) AND we have no
- // existing screens set up in xinerama - then just say root window size
- // is the entire screen. this should handle the case where you unplug ALL
- // screens from an existing setup (unplug external monitors and/or close
- // laptop lid), in which case as long as at least one screen is configured
- // in xinerama, it will be left-as is until next time we re-eval screen
- // setup and have at least one screen
- printf("e_output_screens_setup............... %i %p\n", i, all_screens);
- if ((i == 0) && (!all_screens))
+ else
{
-out:
- screen = E_NEW(E_Screen, 1);
- screen->escreen = screen->screen = 0;
- screen->x = 0;
- screen->y = 0;
- if ((rw > 0) && (rh > 0))
- screen->w = rw, screen->h = rh;
- else
- ecore_evas_screen_geometry_get(e_comp->ee, NULL, NULL, &screen->w, &screen->h);
- e_screens = eina_list_append(e_screens, screen);
+ eout->info.connected = EINA_FALSE;
+
+ /* reset eout info */
+ free(eout->id);
+ free(eout->info.screen);
+ free(eout->info.edid);
+ EINA_LIST_FREE(eout->info.modes, m) free(m);
+
+ eout->id = malloc(strlen(eout->info.name) + 1 + 1);
+ eout->info.size.w = 0;
+ eout->info.size.h = 0;
+
+ printf("E_OUTPUT: disconnected.. id: %s\n", eout->id);
}
- _escreens_set(e_screens);
+
+ return EINA_TRUE;
}
-EINTERN const Eina_List *
-e_output_screens_get(void)
+EINTERN Eina_Bool
+e_output_commit(E_Output *output)
{
- return all_screens;
+ E_Plane *plane = NULL;
+ Eina_List *l;
+ Eina_Bool commitable = EINA_FALSE;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
+
+ if (!output->config.enabled)
+ {
+ WRN("E_Output disconnected");
+ return EINA_FALSE;
+ }
+
+ if (output->dpms == E_OUTPUT_DPMS_OFF)
+ return EINA_TRUE;
+
+ /* set planes */
+ EINA_LIST_REVERSE_FOREACH(output->planes, l, plane)
+ {
+ if (e_plane_set(plane))
+ {
+ if (!commitable) commitable = EINA_TRUE;
+ }
+ }
+
+ /* commit output */
+ if (commitable)
+ {
+ if (!_e_output_commit(output))
+ {
+ ERR("fail to _e_output_commit.");
+
+ /* unset planes */
+ EINA_LIST_REVERSE_FOREACH(output->planes, l, plane)
+ e_plane_unset(plane);
+
+ return EINA_FALSE;
+ }
+ }
+
+ return EINA_TRUE;
}
+
E_API E_Output *
e_output_find(const char *id)
{
E_Output *output;
+ E_Comp_Screen *e_comp_screen;
Eina_List *l;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp->e_comp_screen, NULL);
+
+ e_comp_screen = e_comp->e_comp_screen;
+
EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
{
if (!strcmp(output->id, id)) return output;
E_API void
e_output_util_planes_print(void)
{
- Eina_List *l;
+ Eina_List *l, *ll, *p_l;
E_Output * output = NULL;
+ E_Comp_Screen *e_comp_screen = NULL;
- EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+ EINA_SAFETY_ON_NULL_RETURN(e_comp);
+ EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
+
+ e_comp_screen = e_comp->e_comp_screen;
+
+ EINA_LIST_FOREACH_SAFE(e_comp_screen->outputs, l, ll, output)
{
- Eina_List *p_l;
- E_Plane *ep;
+ E_Plane *plane;
E_Client *ec;
if (!output || !output->planes) continue;
fprintf(stderr, "HWC in %s .. \n", output->id);
fprintf(stderr, "HWC \tzPos \t on_plane \t\t\t\t on_prepare \t \n");
- EINA_LIST_FOREACH(output->planes, p_l, ep)
+ EINA_LIST_REVERSE_FOREACH(output->planes, p_l, plane)
{
- ec = ep->ec;
+ ec = plane->ec;
if (ec) fprintf(stderr, "HWC \t[%d]%s\t %s (0x%08x)",
- ep->zpos,
- ep->is_primary ? "--" : " ",
+ plane->zpos,
+ plane->is_primary ? "--" : " ",
ec->icccm.title, (unsigned int)ec->frame);
- ec = ep->prepare_ec;
+ ec = plane->prepare_ec;
if (ec) fprintf(stderr, "\t\t\t %s (0x%08x)",
ec->icccm.title, (unsigned int)ec->frame);
fputc('\n', stderr);
#ifdef E_TYPEDEFS
-typedef struct _E_Comp_Screen E_Comp_Screen;
typedef struct _E_Output E_Output;
typedef struct _E_Output_Mode E_Output_Mode;
-typedef struct _E_Screen E_Screen;
-
+typedef enum _E_Output_Dpms E_OUTPUT_DPMS;
#else
#ifndef E_OUTPUT_H
#define E_OUTPUT_H
#define E_OUTPUT_TYPE (int)0xE0b11002
-struct _E_Comp_Screen
+#include "e_comp_screen.h"
+#include <Ecore_Drm.h>
+
+enum _E_Output_Dpms
{
- Eina_List *outputs; // available screens
- int w, h; // virtual resolution (calculated)
- unsigned char ignore_hotplug_events;
- unsigned char ignore_acpi_events;
+ E_OUTPUT_DPMS_ON,
+ E_OUTPUT_DPMS_OFF,
+ E_OUTPUT_DPMS_STANDBY,
+ E_OUTPUT_DPMS_SUSPEND
};
struct _E_Output_Mode
int w, h; // resolution width and height
double refresh; // refresh in hz
Eina_Bool preferred : 1; // is this the preferred mode for the device?
+
+ const tdm_output_mode *tmode;
};
struct _E_Output
{
+ int index;
char *id; // string id which is "name/edid";
struct {
char *screen; // name of the screen device attached
int plane_count;
Eina_List *planes;
E_Zone *zone;
-};
-struct _E_Screen
-{
- int screen, escreen;
- int x, y, w, h;
- char *id; // this is the same id we get from _E_Output so look it up there
-};
+ tdm_output *toutput;
+ Ecore_Drm_Output *output; // for evas drm engine.
-extern E_API E_Comp_Screen *e_comp_screen;
-extern E_API int E_EVENT_SCREEN_CHANGE;
+ E_Comp_Screen *e_comp_screen;
+ E_OUTPUT_DPMS dpms;
+};
EINTERN Eina_Bool e_output_init(void);
-EINTERN int e_output_shutdown(void);
-EINTERN void e_output_screens_setup(int rw, int rh);
-EINTERN const Eina_List * e_output_screens_get(void);
+EINTERN void e_output_shutdown(void);
+EINTERN E_Output * e_output_new(E_Comp_Screen *e_comp_screen, int index);
+EINTERN E_Output * e_output_drm_new(Ecore_Drm_Output *output);
+EINTERN void e_output_del(E_Output *output);
+EINTERN Eina_Bool e_output_update(E_Output *output);
+EINTERN Eina_Bool e_output_drm_update(E_Output *output);
+EINTERN Eina_Bool e_output_mode_apply(E_Output *output, E_Output_Mode *mode);
+EINTERN Eina_Bool e_output_commit(E_Output *output);
+EINTERN Eina_Bool e_output_hwc_setup(E_Output *output);
+EINTERN E_Output_Mode * e_output_best_mode_find(E_Output *output);
+EINTERN Eina_Bool e_output_connected(E_Output *output);
+EINTERN Eina_Bool e_output_dpms_set(E_Output *output, E_OUTPUT_DPMS val);
E_API E_Output * e_output_find(const char *id);
E_API const Eina_List * e_output_planes_get(E_Output *output);
E_API void e_output_util_planes_print(void);
#include "e.h"
+# include <gbm/gbm_tbm.h>
+# include <tdm.h>
+# include <tdm_helper.h>
+# include <tbm_surface.h>
+# include <tbm_surface_internal.h>
+# include <wayland-tbm-server.h>
+# include <Evas_Engine_GL_Drm.h>
+
+# ifndef CLEAR
+# define CLEAR(x) memset(&(x), 0, sizeof (x))
+# endif
+
+# define E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED 7777
+
+typedef struct _E_Plane_Client E_Plane_Client;
+
+struct _E_Plane_Client
+{
+ E_Client *ec;
+
+ E_Plane *plane;
+ Eina_Bool activated;
+
+ E_Comp_Wl_Buffer *buffer;
+ struct wl_listener buffer_destroy_listener;
+
+ Eina_List *exported_surfaces;
+};
+
/* E_Plane is a child object of E_Output. There is one Output per screen
* E_plane represents hw overlay and a surface is assigned to disable composition
* Each Output always has dedicated canvas and a zone
*/
///////////////////////////////////////////
static const char *_e_plane_ec_last_err = NULL;
+static E_Client_Hook *client_hook_new = NULL;
+static E_Client_Hook *client_hook_del = NULL;
+static Eina_Hash *plane_clients = NULL;
+static Eina_List *plane_hdlrs = NULL;
+static Eina_Bool plane_trace_debug = 0;
+
+#if HAVE_MEMCPY_SWC
+extern void *memcpy_swc(void *dest, const void *src, size_t n);
+#endif
+
+static struct wl_resource *
+_get_wl_buffer(E_Client *ec)
+{
+ E_Pixmap *pixmap = ec->pixmap;
+ E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(pixmap);
+
+ if (!buffer) return NULL;
+
+ return buffer->resource;
+}
+
+static struct wl_resource *
+_get_wl_buffer_ref(E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+ if (!cdata) return NULL;
+
+ E_Comp_Wl_Buffer_Ref *buffer_ref = &cdata ->buffer_ref;
+
+ if (!buffer_ref->buffer) return NULL;
+
+ return buffer_ref->buffer->resource;
+}
+
+static struct wl_resource *
+_e_plane_wl_surface_get(E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata = NULL;
+ struct wl_resource *wl_surface = NULL;
+
+ cdata = (E_Comp_Wl_Client_Data *)e_pixmap_cdata_get(ec->pixmap);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cdata, NULL);
+
+ wl_surface = cdata->wl_surface;
+ if (!wl_surface) return NULL;
+
+ return wl_surface;
+}
+
+struct wayland_tbm_client_queue *
+_e_plane_wayland_tbm_client_queue_get(E_Client *ec)
+{
+ struct wayland_tbm_client_queue * cqueue = NULL;
+ struct wl_resource *wl_surface = NULL;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wl_comp_data, NULL);
+
+ wl_surface = _e_plane_wl_surface_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(wl_surface, NULL);
+
+ cqueue = wayland_tbm_server_client_queue_get(wl_comp_data->tbm.server, wl_surface);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cqueue, NULL);
+
+ return cqueue;
+}
+
+static E_Plane_Client *
+_e_plane_client_new(E_Client *ec)
+{
+ E_Plane_Client *plane_client = NULL;
+
+ plane_client = E_NEW(E_Plane_Client, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane_client, NULL);
+
+ plane_client->ec = ec;
+ plane_client->plane = NULL;
+ plane_client->exported_surfaces = NULL;
+
+ return plane_client;
+}
+
+static E_Plane_Client *
+_e_plane_client_get(E_Client *ec)
+{
+ E_Plane_Client *plane_client = NULL;
+
+ plane_client = eina_hash_find(plane_clients, &ec);
+
+ return plane_client;
+}
+
+static void
+_e_plane_client_cb_new(void *data EINA_UNUSED, E_Client *ec)
+{
+ E_Plane_Client *plane_client = NULL;
+
+ plane_client = _e_plane_client_get(ec);
+ if (!plane_client)
+ {
+ plane_client = _e_plane_client_new(ec);
+ if (plane_client)
+ eina_hash_add(plane_clients, &ec, plane_client);
+ }
+}
+
+static void
+_e_plane_client_cb_del(void *data EINA_UNUSED, E_Client *ec)
+{
+ E_Plane_Client *plane_client = NULL;
+
+ plane_client = _e_plane_client_get(ec);
+ if (plane_client)
+ {
+ /* destroy the plane_client */
+ eina_hash_del_by_key(plane_clients, &ec);
+ }
+}
+
+static tbm_surface_h
+_e_plane_copied_surface_create(E_Client *ec, Eina_Bool refresh)
+{
+ tbm_surface_h tsurface = NULL;
+ tbm_surface_h new_tsurface = NULL;
+ E_Pixmap *pixmap = NULL;
+ E_Comp_Wl_Buffer *buffer = NULL;
+ tbm_surface_info_s src_info, dst_info;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+
+ pixmap = ec->pixmap;
+
+ if (refresh)
+ e_pixmap_image_refresh(ec->pixmap);
+
+ buffer = e_pixmap_resource_get(pixmap);
+ if (!buffer) return NULL;
+
+ tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tsurface, NULL);
+
+ tbm_surface_map(tsurface, TBM_SURF_OPTION_READ, &src_info);
+ tbm_surface_unmap(tsurface);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(src_info.planes[0].ptr, NULL);
+
+ new_tsurface = tbm_surface_create(src_info.width, src_info.height, src_info.format);
+
+ tbm_surface_map(new_tsurface, TBM_SURF_OPTION_WRITE, &dst_info);
+ tbm_surface_unmap(new_tsurface);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(dst_info.planes[0].ptr, NULL);
+
+ /* copy from src to dst */
+#if HAVE_MEMCPY_SWC
+ memcpy_swc(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size);
+#else
+ memcpy(dst_info.planes[0].ptr, src_info.planes[0].ptr, src_info.planes[0].size);
+#endif
+
+ return new_tsurface;
+}
+
+static void
+_e_plane_copied_surface_destroy(tbm_surface_h tbm_surface)
+{
+ EINA_SAFETY_ON_NULL_RETURN(tbm_surface);
+
+ tbm_surface_internal_unref(tbm_surface);
+}
+
+static void
+_e_plane_client_backup_buffer_cb_destroy(struct wl_listener *listener, void *data)
+{
+ E_Plane_Client *plane_client = NULL;
+ E_Client *ec = NULL;
+
+ plane_client = container_of(listener, E_Plane_Client, buffer_destroy_listener);
+ EINA_SAFETY_ON_NULL_RETURN(plane_client);
+
+ if ((E_Comp_Wl_Buffer *)data != plane_client->buffer) return;
+
+ ec = plane_client->ec;
+ EINA_SAFETY_ON_NULL_RETURN(ec);
+
+ if (e_pixmap_resource_get(ec->pixmap) == (E_Comp_Wl_Buffer *)data)
+ {
+ e_pixmap_resource_set(ec->pixmap, NULL);
+ e_comp_object_native_surface_set(ec->frame, 0);
+ }
+
+ plane_client->buffer = NULL;
+}
+
+static Eina_Bool
+_e_plane_client_backup_buffer_set(E_Plane_Client *plane_client)
+{
+ E_Comp_Wl_Buffer *backup_buffer = NULL;
+ tbm_surface_h copied_tsurface = NULL;
+ E_Client *ec = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane_client, EINA_FALSE);
+
+ ec = plane_client->ec;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+ copied_tsurface = _e_plane_copied_surface_create(ec, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(copied_tsurface, EINA_FALSE);
+
+ backup_buffer = e_comp_wl_tbm_buffer_get(copied_tsurface);
+ EINA_SAFETY_ON_NULL_GOTO(backup_buffer, fail);
+
+ if (plane_client->buffer)
+ wl_list_remove(&plane_client->buffer_destroy_listener.link);
+
+ plane_client->buffer = backup_buffer;
+ wl_signal_add(&backup_buffer->destroy_signal, &plane_client->buffer_destroy_listener);
+ plane_client->buffer_destroy_listener.notify = _e_plane_client_backup_buffer_cb_destroy;
+
+ /* reference backup buffer to comp data */
+ e_comp_wl_buffer_reference(&ec->comp_data->buffer_ref, backup_buffer);
+
+ /* set the backup buffer resource to the pixmap */
+ e_pixmap_resource_set(ec->pixmap, backup_buffer);
+ e_pixmap_dirty(ec->pixmap);
+ e_pixmap_refresh(ec->pixmap);
+
+ return EINA_TRUE;
+
+fail :
+ if (copied_tsurface)
+ _e_plane_copied_surface_destroy(copied_tsurface);
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_plane_renderer_disp_surface_find(E_Plane_Renderer *renderer, tbm_surface_h tsurface)
+{
+ Eina_List *l_s;
+ tbm_surface_h tmp_tsurface = NULL;
+
+ EINA_LIST_FOREACH(renderer->disp_surfaces, l_s, tmp_tsurface)
+ {
+ if (!tmp_tsurface) continue;
+ if (tmp_tsurface == tsurface) return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static void
+_e_plane_surface_queue_release(E_Plane *plane, tbm_surface_h tsurface)
+{
+
+ tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
+ E_Plane_Renderer *renderer = NULL;
+ tbm_surface_queue_h tqueue = NULL;
+
+ renderer = plane->renderer;
+ EINA_SAFETY_ON_NULL_RETURN(renderer);
+
+ tqueue = renderer->tqueue;
+ EINA_SAFETY_ON_NULL_RETURN(tqueue);
+
+ /* debug */
+ if (plane_trace_debug)
+ {
+ E_Client *ec = renderer->activated_ec;
+ if (ec)
+ ELOGF("E_PLANE", "Release Layer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) wl_buffer_ref(%p)",
+ ec->pixmap, ec, plane, _get_wl_buffer(ec), tsurface, renderer->tqueue, _get_wl_buffer_ref(ec));
+ else
+ ELOGF("E_PLANE", "Release Layer(%p) tsurface(%p) tqueue(%p)",
+ NULL, NULL, plane, tsurface, renderer->tqueue);
+ }
+
+ tsq_err = tbm_surface_queue_release(tqueue, tsurface);
+ if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
+ {
+ ERR("Failed to release tbm_surface(%p) from tbm_surface_queue(%p): tsq_err = %d", tsurface, tqueue, tsq_err);
+ return;
+ }
+}
+
+static Eina_Bool
+_e_plane_client_exported_surface_find(E_Plane_Client *plane_client, tbm_surface_h tsurface)
+{
+ Eina_List *l_s;
+ tbm_surface_h tmp_tsurface = NULL;
+
+ /* destroy the plane_client */
+ EINA_LIST_FOREACH(plane_client->exported_surfaces, l_s, tmp_tsurface)
+ {
+ if (!tmp_tsurface) continue;
+ if (tmp_tsurface == tsurface) return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static void
+_e_plane_renderer_exported_surface_release(E_Plane_Renderer *renderer, tbm_surface_h tsurface)
+{
+ E_Plane *plane = NULL;
+ tbm_surface_h tmp_tsurface = NULL;
+ Eina_List *l_s, *ll_s;
+
+ EINA_SAFETY_ON_NULL_RETURN(tsurface);
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN(plane);
+
+ EINA_LIST_FOREACH_SAFE(renderer->exported_surfaces, l_s, ll_s, tmp_tsurface)
+ {
+ if (!tmp_tsurface) continue;
+
+ if (tmp_tsurface == tsurface)
+ {
+ if (plane->tsurface != tsurface)
+ _e_plane_surface_queue_release(plane, tsurface);
+
+ renderer->exported_surfaces = eina_list_remove_list(renderer->exported_surfaces, l_s);
+ }
+ }
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Release exported Renderer(%p) tsurface(%p) tqueue(%p)",
+ NULL, NULL, renderer, tsurface, renderer->tqueue);
+}
+
+static void
+_e_plane_client_exported_surfaces_release(E_Plane_Client *plane_client, E_Plane_Renderer *renderer)
+{
+ Eina_List *l_s, *ll_s;
+ tbm_surface_h tsurface = NULL;
+ E_Plane *plane = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(plane_client);
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN(plane);
+
+ EINA_LIST_FOREACH_SAFE(plane_client->exported_surfaces, l_s, ll_s, tsurface)
+ {
+ if (!tsurface) continue;
+
+ if (tsurface == plane->previous_tsurface)
+ {
+ _e_plane_renderer_exported_surface_release(renderer, tsurface);
+ plane_client->exported_surfaces = eina_list_remove_list(plane_client->exported_surfaces, l_s);
+ break;
+ }
+
+ }
+
+ EINA_LIST_FOREACH_SAFE(plane_client->exported_surfaces, l_s, ll_s, tsurface)
+ {
+ if (!tsurface) continue;
+
+ if (tsurface == plane->tsurface)
+ {
+ _e_plane_renderer_exported_surface_release(renderer, tsurface);
+ plane_client->exported_surfaces = eina_list_remove_list(plane_client->exported_surfaces, l_s);
+ break;
+ }
+
+ }
+
+ EINA_LIST_FOREACH_SAFE(plane_client->exported_surfaces, l_s, ll_s, tsurface)
+ {
+ if (!tsurface) continue;
+
+ _e_plane_renderer_exported_surface_release(renderer, tsurface);
+ plane_client->exported_surfaces = eina_list_remove_list(plane_client->exported_surfaces, l_s);
+ }
+}
+
+static void
+_e_plane_client_del(void *data)
+{
+ E_Plane_Client *plane_client = data;
+ E_Plane_Renderer *renderer = NULL;
+
+ if (!plane_client) return;
+
+ if (plane_client->buffer)
+ wl_list_remove(&plane_client->buffer_destroy_listener.link);
+
+ if (plane_client->activated && plane_client->plane)
+ {
+ renderer = plane_client->plane->renderer;
+ if (renderer)
+ _e_plane_client_exported_surfaces_release(plane_client, renderer);
+ }
+
+ free(plane_client);
+}
+
+static uint32_t
+_e_plane_client_surface_flags_get(E_Plane_Client *plane_client)
+{
+ tbm_surface_h tsurface = NULL;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+ E_Client *ec = plane_client->ec;
+ E_Pixmap *pixmap = ec->pixmap;
+ uint32_t flags = 0;
+ E_Comp_Wl_Buffer *buffer = NULL;
+
+ buffer = e_pixmap_resource_get(pixmap);
+ if (!buffer) return 0;
+
+ switch (buffer->type)
+ {
+ case E_COMP_WL_BUFFER_TYPE_NATIVE:
+ case E_COMP_WL_BUFFER_TYPE_VIDEO:
+ tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tsurface, 0);
+
+ flags = wayland_tbm_server_get_buffer_flags(wl_comp_data->tbm.server, buffer->resource);
+ break;
+ default:
+ flags = 0;
+ break;
+ }
+
+ return flags;
+}
+
+static tbm_surface_h
+_e_plane_surface_queue_acquire(E_Plane *plane)
+{
+ tbm_surface_queue_h tqueue = NULL;
+ tbm_surface_h tsurface = NULL;
+ tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
+ E_Plane_Renderer *renderer = NULL;
+
+ renderer = plane->renderer;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, NULL);
+
+ tqueue = renderer->tqueue;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tqueue, NULL);
+
+ if (tbm_surface_queue_can_acquire(tqueue, 1))
+ {
+ tsq_err = tbm_surface_queue_acquire(tqueue, &tsurface);
+ if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
+ {
+ ERR("Failed to acquire tbm_surface from tbm_surface_queue(%p): tsq_err = %d", tqueue, tsq_err);
+ return NULL;
+ }
+ }
+
+ /* if not exist, add the surface to the renderer */
+ if (!_e_plane_renderer_disp_surface_find(renderer, tsurface))
+ renderer->disp_surfaces = eina_list_append(renderer->disp_surfaces, tsurface);
+
+ /* debug */
+ if (plane_trace_debug)
+ {
+ E_Client *ec = renderer->activated_ec;
+ if (ec)
+ ELOGF("E_PLANE", "Acquire Layer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) wl_buffer_ref(%p)",
+ ec->pixmap, ec, plane, _get_wl_buffer(ec), tsurface, tqueue, _get_wl_buffer_ref(ec));
+ else
+ ELOGF("E_PLANE", "Acquire Layer(%p) tsurface(%p) tqueue(%p)",
+ NULL, NULL, plane, tsurface, tqueue);
+ }
+
+ return tsurface;
+}
+
+static Eina_Bool
+_e_plane_surface_queue_enqueue(E_Plane *plane, tbm_surface_h tsurface)
+{
+ tbm_surface_queue_h tqueue = NULL;
+ E_Plane_Renderer *renderer = NULL;
+ tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
+
+ renderer = plane->renderer;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, EINA_FALSE);
+
+ tqueue = renderer->tqueue;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tqueue, EINA_FALSE);
+
+ /* debug */
+ if (plane_trace_debug)
+ {
+ E_Plane_Renderer *renderer = plane->renderer;
+ E_Client *ec = renderer->activated_ec;
+ ELOGF("E_PLANE", "Enqueue Renderer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) wl_buffer_ref(%p)",
+ ec->pixmap, ec, renderer, _get_wl_buffer(ec), tsurface, renderer->tqueue, _get_wl_buffer_ref(ec));
+ }
+
+ tsq_err = tbm_surface_queue_enqueue(tqueue, tsurface);
+ if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
+ {
+ ERR("tbm_surface_queue_enqueue failed. tbm_surface_queue(%p) tbm_surface(%p)", tqueue, tsurface);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static int
+_e_plane_surface_queue_can_dequeue(E_Plane *plane)
+{
+ tbm_surface_queue_h tqueue = NULL;
+ E_Plane_Renderer *renderer = NULL;
+ int num_free = 0;
+
+ renderer = plane->renderer;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, EINA_FALSE);
+
+ tqueue = renderer->tqueue;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tqueue, EINA_FALSE);
+
+ num_free = tbm_surface_queue_can_dequeue(tqueue, 0);
+
+ return num_free;
+}
+
+static tbm_surface_h
+_e_plane_surface_queue_dequeue(E_Plane *plane)
+{
+ E_Plane_Renderer *renderer = NULL;
+ tbm_surface_queue_h tqueue = NULL;
+ tbm_surface_h tsurface = NULL;
+ tbm_surface_queue_error_e tsq_err = TBM_SURFACE_QUEUE_ERROR_NONE;
+
+ renderer = plane->renderer;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, NULL);
+
+ tqueue = renderer->tqueue;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tqueue, NULL);
+
+ tsq_err = tbm_surface_queue_dequeue(tqueue, &tsurface);
+ if (tsq_err != TBM_SURFACE_QUEUE_ERROR_NONE)
+ {
+ ERR("fail to tbm_surface_queue_dequeue");
+ return NULL;
+ }
+
+ /* debug */
+ if (plane_trace_debug)
+ {
+ E_Plane_Renderer *renderer = plane->renderer;
+ E_Client *ec = renderer->activated_ec;
+ if (ec)
+ ELOGF("E_PLANE", "Dequeue Renderer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) wl_buffer_ref(%p)",
+ ec->pixmap, ec, renderer, _get_wl_buffer(ec), tsurface, renderer->tqueue, _get_wl_buffer_ref(ec));
+ else
+ ELOGF("E_PLANE", "Dequeue Renderer(%p) tsurface(%p) tqueue(%p)",
+ NULL, NULL, renderer, tsurface, renderer->tqueue);
+ }
+ return tsurface;
+}
+
+static Eina_Bool
+_e_plane_renderer_sent_surface_find(E_Plane_Renderer *renderer, tbm_surface_h tsurface)
+{
+ Eina_List *l_s;
+ tbm_surface_h tmp_tsurface = NULL;
+
+ EINA_LIST_FOREACH(renderer->sent_surfaces, l_s, tmp_tsurface)
+ {
+ if (!tmp_tsurface) continue;
+ if (tmp_tsurface == tsurface) return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_plane_renderer_exported_surface_find(E_Plane_Renderer *renderer, tbm_surface_h tsurface)
+{
+ Eina_List *l_s;
+ tbm_surface_h tmp_tsurface = NULL;
+
+ EINA_LIST_FOREACH(renderer->exported_surfaces, l_s, tmp_tsurface)
+ {
+ if (!tmp_tsurface) continue;
+ if (tmp_tsurface == tsurface) return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+static void
+_e_plane_renderer_exported_surface_destroy_cb(tbm_surface_h tsurface, void *data)
+{
+ E_Plane_Renderer *renderer = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(e_comp);
+ EINA_SAFETY_ON_NULL_RETURN(e_comp->e_comp_screen);
+ EINA_SAFETY_ON_NULL_RETURN(tsurface);
+ EINA_SAFETY_ON_NULL_RETURN(data);
+
+ renderer = (E_Plane_Renderer *)data;
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Destroy Renderer(%p) tsurface(%p) tqueue(%p)",
+ NULL, NULL, renderer, tsurface, renderer->tqueue);
+}
+
+static void
+_e_plane_ee_post_render_cb(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ E_Plane *plane = data;
+
+ if (!plane) return;
+
+ /* mark when the post_render is called */
+ plane->update_ee = EINA_TRUE;
+}
+
+static void
+_e_plane_renderer_all_disp_surfaces_release(E_Plane_Renderer *renderer)
+{
+ Eina_List *l_s;
+ tbm_surface_h tsurface = NULL;
+
+ EINA_LIST_FOREACH(renderer->disp_surfaces, l_s, tsurface)
+ {
+ if (!tsurface) continue;
+
+ _e_plane_surface_queue_release(renderer->plane, tsurface);
+
+ if (_e_plane_renderer_exported_surface_find(renderer, tsurface))
+ renderer->exported_surfaces = eina_list_remove(renderer->exported_surfaces, tsurface);
+ }
+}
+
+static void
+_e_plane_renderer_surface_export(E_Plane_Renderer *renderer, tbm_surface_h tsurface, E_Client *ec)
+{
+ struct wayland_tbm_client_queue * cqueue = NULL;
+ struct wl_resource *wl_buffer = NULL;
+ E_Plane_Client *plane_client = NULL;
+
+ plane_client = _e_plane_client_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN(plane_client);
+
+ cqueue = _e_plane_wayland_tbm_client_queue_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN(cqueue);
+
+ if (_e_plane_renderer_exported_surface_find(renderer, tsurface)) return;
+
+ /* export the tbm_surface(wl_buffer) to the client_queue */
+ wl_buffer = wayland_tbm_server_client_queue_export_buffer(cqueue, tsurface,
+ E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED, _e_plane_renderer_exported_surface_destroy_cb,
+ (void *)renderer);
+
+ renderer->exported_surfaces = eina_list_append(renderer->exported_surfaces, tsurface);
+
+ /* add a sent surface to the sent list in renderer if it is not in the list */
+ if (!_e_plane_renderer_sent_surface_find(renderer, tsurface))
+ renderer->sent_surfaces = eina_list_append(renderer->sent_surfaces, tsurface);
+
+ if (!_e_plane_client_exported_surface_find(plane_client, tsurface))
+ plane_client->exported_surfaces = eina_list_append(plane_client->exported_surfaces, tsurface);
+
+ if (wl_buffer && plane_trace_debug)
+ ELOGF("E_PLANE", "Export Renderer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p)",
+ ec->pixmap, ec, renderer, wl_buffer, tsurface, renderer->tqueue);
+}
+
+
+static void
+_e_plane_renderer_all_disp_surfaces_export(E_Plane_Renderer *renderer, E_Client *ec)
+{
+ struct wayland_tbm_client_queue * cqueue = NULL;
+ Eina_List *l_s, *ll_s;
+ tbm_surface_h tsurface = NULL;
+
+ cqueue = _e_plane_wayland_tbm_client_queue_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN(cqueue);
+
+ EINA_LIST_FOREACH_SAFE(renderer->disp_surfaces, l_s, ll_s, tsurface)
+ {
+ if (!tsurface) continue;
+
+ _e_plane_renderer_surface_export(renderer, tsurface, ec);
+ }
+}
+
+static void
+_e_plane_renderer_dequeuable_surfaces_export(E_Plane_Renderer *renderer, E_Client *ec)
+{
+ E_Plane *plane = NULL;
+ tbm_surface_h tsurface = NULL;
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN(plane);
+
+ /* export dequeuable surface */
+ while(_e_plane_surface_queue_can_dequeue(plane))
+ {
+ /* dequeue */
+ tsurface = _e_plane_surface_queue_dequeue(plane);
+ if (!tsurface) ERR("fail to dequeue surface");
+
+ /* export the surface */
+ if (!_e_plane_renderer_exported_surface_find(renderer, tsurface))
+ _e_plane_renderer_surface_export(renderer, tsurface, ec);
+ }
+}
+
+static tbm_surface_h
+_e_plane_renderer_surface_revice(E_Plane_Renderer *renderer, E_Client *ec)
+{
+ tbm_surface_h tsurface = NULL;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+ E_Pixmap *pixmap = ec->pixmap;
+ uint32_t flags = 0;
+ E_Comp_Wl_Buffer *buffer = NULL;
+
+ if (renderer->activated_ec != ec)
+ {
+ ERR("Renderer(%p) activated_ec(%p) != ec(%p)", renderer, renderer->activated_ec, ec);
+ return NULL;
+ }
+
+ buffer = e_pixmap_resource_get(pixmap);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buffer, NULL);
+
+ tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tsurface, NULL);
+
+ flags = wayland_tbm_server_get_buffer_flags(wl_comp_data->tbm.server, buffer->resource);
+
+ if (plane_trace_debug)
+ {
+ E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)renderer->activated_ec->comp_data;
+ E_Comp_Wl_Buffer_Ref *buffer_ref = &cdata ->buffer_ref;
+
+ ELOGF("E_PLANE", "Receive Renderer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) wl_buffer_ref(%p) flags(%d)",
+ ec->pixmap, ec, renderer, buffer->resource, tsurface, renderer->tqueue, buffer_ref->buffer->resource, flags);
+ }
+ if (flags != E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED)
+ {
+ ERR("the flags of the enqueuing surface is %d. need flags(%d).", flags, E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED);
+ return NULL;
+ }
+
+ /* remove a recieved surface from the sent list in renderer */
+ renderer->sent_surfaces = eina_list_remove(renderer->sent_surfaces, (const void *)tsurface);
+
+ return tsurface;
+}
+
+static void
+_e_plane_renderer_surface_send(E_Plane_Renderer *renderer, E_Client *ec, tbm_surface_h tsurface)
+{
+ /* debug */
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Send Renderer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) wl_buffer_ref(%p)",
+ ec->pixmap, ec, renderer, _get_wl_buffer(ec), tsurface, renderer->tqueue, _get_wl_buffer_ref(ec));
+
+ /* wl_buffer release */
+ e_pixmap_image_clear(ec->pixmap, 1);
+
+ /* add a sent surface to the sent list in renderer if it is not in the list */
+ if (!_e_plane_renderer_sent_surface_find(renderer, tsurface))
+ renderer->sent_surfaces = eina_list_append(renderer->sent_surfaces, tsurface);
+}
+
+static Eina_Bool
+_e_plane_renderer_deactivate(E_Plane_Renderer *renderer)
+{
+ struct wayland_tbm_client_queue * cqueue = NULL;
+ struct wl_resource *wl_surface = NULL;
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+ E_Client *ec = NULL;
+ E_Plane_Client *plane_client = NULL;
+ E_Plane_Client *candidate_plane_client = NULL;
+
+ if (renderer->activated_ec)
+ {
+ ec = renderer->activated_ec;
+ }
+ else if (renderer->candidate_ec)
+ {
+ ec = renderer->candidate_ec;
+ }
+ else
+ {
+ ERR("NEVER HERE.");
+ goto done;
+ }
+
+ EINA_SAFETY_ON_NULL_GOTO(wl_comp_data, done);
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Deactivate", ec->pixmap, ec);
+
+ plane_client = _e_plane_client_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane_client, EINA_FALSE);
+
+ wl_surface = _e_plane_wl_surface_get(ec);
+ EINA_SAFETY_ON_NULL_GOTO(wl_surface, done);
+
+ cqueue = wayland_tbm_server_client_queue_get(wl_comp_data->tbm.server, wl_surface);
+ EINA_SAFETY_ON_NULL_GOTO(cqueue, done);
+
+ /* deactive */
+ wayland_tbm_server_client_queue_deactivate(cqueue);
+
+ if (_e_plane_client_surface_flags_get(plane_client) == E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED)
+ {
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Set Backup Buffer wl_buffer(%p):Deactivate", ec->pixmap, ec, _get_wl_buffer(ec));
+
+ if (!_e_plane_client_backup_buffer_set(plane_client))
+ ERR("fail to _e_comp_hwc_set_backup_buffer");
+
+ /* force update */
+ e_pixmap_image_refresh(ec->pixmap);
+ e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
+ e_comp_object_dirty(ec->frame);
+ e_comp_object_render(ec->frame);
+ }
+
+done:
+ if (renderer->candidate_ec)
+ {
+ candidate_plane_client = _e_plane_client_get(renderer->candidate_ec);
+ if (candidate_plane_client)
+ _e_plane_client_exported_surfaces_release(candidate_plane_client, renderer);
+
+ renderer->candidate_ec = NULL;
+ }
+
+ if (renderer->activated_ec)
+ {
+ _e_plane_client_exported_surfaces_release(plane_client, renderer);
+ renderer->activated_ec = NULL;
+ }
+
+ plane_client->activated = EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static void
+_e_plane_renderer_queue_del(E_Plane_Renderer *renderer)
+{
+ tbm_surface_queue_h tqueue = NULL;
+
+ if (!renderer) return;
+
+ tqueue = renderer->tqueue;
+ EINA_SAFETY_ON_NULL_RETURN(tqueue);
+
+ tbm_surface_queue_destroy(tqueue);
+ renderer->tqueue = NULL;
+
+ renderer->disp_surfaces = eina_list_free(renderer->disp_surfaces);
+}
+
+static Eina_Bool
+_e_plane_renderer_queue_create(E_Plane_Renderer *renderer, int width, int height)
+{
+ E_Plane *plane = NULL;
+ tbm_surface_queue_h tqueue = NULL;
+ tbm_surface_h tsurface = NULL;
+ tdm_error tdm_err = TDM_ERROR_NONE;
+ unsigned int buffer_flags = -1;
+ int format = TBM_FORMAT_ARGB8888;
+ int queue_size = 3; /* query tdm ????? */
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, EINA_FALSE);
+
+ if (renderer->tqueue)
+ {
+ ERR("already create queue in renderer");
+ return EINA_FALSE;
+ }
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
+
+ tdm_err = tdm_layer_get_buffer_flags(plane->tlayer, &buffer_flags);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(tdm_err == TDM_ERROR_NONE, EINA_FALSE);
+
+ tqueue = tbm_surface_queue_create(queue_size, width, height, format, buffer_flags);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(tqueue, EINA_FALSE);
+
+ renderer->tqueue = tqueue;
+
+ /* dequeue the surfaces if the qeueue is available */
+ /* add the surface to the disp_surfaces list, if it is not in the disp_surfaces */
+ while (tbm_surface_queue_can_dequeue(renderer->tqueue, 0))
+ {
+ /* dequeue */
+ tsurface = _e_plane_surface_queue_dequeue(plane);
+ if (!tsurface)
+ {
+ ERR("fail to dequeue surface");
+ continue;
+ }
+
+ /* if not exist, add the surface to the renderer */
+ if (!_e_plane_renderer_disp_surface_find(renderer, tsurface))
+ renderer->disp_surfaces = eina_list_append(renderer->disp_surfaces, tsurface);
+ }
+
+ _e_plane_renderer_all_disp_surfaces_release(renderer);
+
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_plane_renderer_queue_set(E_Plane_Renderer *renderer, tbm_surface_queue_h tqueue)
+{
+ tbm_surface_h tsurface = NULL;
+ E_Plane *plane = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(tqueue, EINA_FALSE);
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
+
+ renderer->tqueue = tqueue;
+
+ if (renderer->disp_surfaces)
+ renderer->disp_surfaces = eina_list_free(renderer->disp_surfaces);
+
+ /* dequeue the surfaces if the qeueue is available */
+ /* add the surface to the disp_surfaces list, if it is not in the disp_surfaces */
+ while (tbm_surface_queue_can_dequeue(renderer->tqueue, 0))
+ {
+ /* dequeue */
+ tsurface = _e_plane_surface_queue_dequeue(plane);
+ if (!tsurface)
+ {
+ ERR("fail to dequeue surface");
+ continue;
+ }
+
+ /* if not exist, add the surface to the renderer */
+ if (!_e_plane_renderer_disp_surface_find(renderer, tsurface))
+ renderer->disp_surfaces = eina_list_append(renderer->disp_surfaces, tsurface);
+ }
+
+ _e_plane_renderer_all_disp_surfaces_release(renderer);
+
+ return EINA_TRUE;
+}
+
+static E_Plane_Renderer *
+_e_plane_renderer_new(E_Plane *plane)
+{
+ E_Plane_Renderer *renderer = NULL;
+ /* create a renderer */
+ renderer = E_NEW(E_Plane_Renderer, 1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, NULL);
+ renderer->plane = plane;
+
+ return renderer;
+}
+
+static void
+_e_plane_renderer_del(E_Plane_Renderer *renderer)
+{
+ E_Plane *plane = NULL;
+
+ if (!renderer) return;
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN(plane);
+
+ if (!plane->is_primary)
+ _e_plane_renderer_queue_del(renderer);
+
+ free(renderer);
+}
+
+static Eina_Bool
+_e_plane_renderer_activate(E_Plane_Renderer *renderer, E_Client *ec)
+{
+ struct wayland_tbm_client_queue * cqueue = NULL;
+ tbm_surface_h tsurface = NULL;
+ E_Plane_Client *plane_client = NULL;
+ E_Plane *plane = NULL;
+
+ plane = renderer->plane;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
+
+ /* deactivate the client of the layer before this call*/
+ if (renderer->activated_ec)
+ {
+ ERR("Previous activated client must be decativated.");
+ return EINA_FALSE;
+ }
+
+ cqueue = _e_plane_wayland_tbm_client_queue_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(cqueue, EINA_FALSE);
+
+ /* register the plane client */
+ plane_client = _e_plane_client_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane_client, EINA_FALSE);
+
+ if (renderer->candidate_ec)
+ {
+ if (renderer->candidate_ec != ec)
+ {
+ /* deactive the candidate_ec */
+ _e_plane_renderer_deactivate(renderer);
+
+ /* activate the client queue */
+ wayland_tbm_server_client_queue_activate(cqueue, 0);
+ plane_client->activated = EINA_TRUE;
+
+ if (_e_plane_client_surface_flags_get(plane_client) != E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED)
+ {
+ /* check dequeuable */
+ if (!_e_plane_surface_queue_can_dequeue(renderer->plane))
+ {
+ INF("There is any dequeuable surface.");
+ return EINA_FALSE;
+ }
+
+ /* dequeue */
+ tsurface = _e_plane_surface_queue_dequeue(renderer->plane);
+ if (!tsurface)
+ {
+ ERR("fail to dequeue surface");
+ return EINA_FALSE;
+ }/* export the surface */
+
+ /* export */
+ _e_plane_renderer_surface_export(renderer, tsurface, ec);
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Candidate Plane(%p)", ec->pixmap, ec, renderer->plane);
+
+ renderer->candidate_ec = ec;
+
+ return EINA_FALSE;
+ }
+ }
+ else
+ {
+ if (_e_plane_client_surface_flags_get(plane_client) != E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED)
+ {
+ INF("ec does not have the scanout surface yet.");
+ return EINA_FALSE;
+ }
+ }
+ }
+ else
+ {
+ wayland_tbm_server_client_queue_activate(cqueue, 0);
+ plane_client->activated = EINA_TRUE;
+
+ if (_e_plane_client_surface_flags_get(plane_client) != E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED)
+ {
+ /* check dequeuable */
+ if (!_e_plane_surface_queue_can_dequeue(renderer->plane))
+ {
+ INF("There is any dequeuable surface.");
+ return EINA_FALSE;
+ }
+
+ /* dequeue */
+ tsurface = _e_plane_surface_queue_dequeue(renderer->plane);
+ if (!tsurface)
+ {
+ ERR("fail to dequeue surface");
+ return EINA_FALSE;
+ }
+
+ /* export */
+ _e_plane_renderer_surface_export(renderer, tsurface, ec);
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Candidate Plane(%p)", ec->pixmap, ec, renderer->plane);
+
+ renderer->candidate_ec = ec;
+
+ INF("ec does not have the scanout surface.");
+
+ return EINA_FALSE;
+ }
+ }
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Activate Plane(%p)", ec->pixmap, ec, plane);
+
+ renderer->activated_ec = ec;
+ renderer->candidate_ec = NULL;
+
+ _e_plane_renderer_dequeuable_surfaces_export(renderer, ec);
+
+ return EINA_TRUE;
+}
+
+
+static Eina_Bool
+_e_plane_surface_set(E_Plane *plane, tbm_surface_h tsurface)
+{
+ tbm_surface_info_s surf_info;
+ tdm_error error;
+ tdm_layer *tlayer = plane->tlayer;
+ E_Output *output = plane->output;
+
+ /* set layer when the layer infomation is different from the previous one */
+ tbm_surface_get_info(tsurface, &surf_info);
+ if (plane->info.src_config.size.h != surf_info.planes[0].stride ||
+ plane->info.src_config.size.v != surf_info.height ||
+ plane->info.src_config.pos.x != 0 ||
+ plane->info.src_config.pos.y != 0 ||
+ plane->info.src_config.pos.w != surf_info.width ||
+ plane->info.src_config.pos.h != surf_info.height ||
+ plane->info.dst_pos.x != output->config.geom.x ||
+ plane->info.dst_pos.y != output->config.geom.y ||
+ plane->info.dst_pos.w != output->config.geom.w ||
+ plane->info.dst_pos.h != output->config.geom.h ||
+ plane->info.transform != TDM_TRANSFORM_NORMAL)
+ {
+ plane->info.src_config.size.h = surf_info.planes[0].stride;
+ plane->info.src_config.size.v = surf_info.height;
+ plane->info.src_config.pos.x = 0;
+ plane->info.src_config.pos.y = 0;
+ plane->info.src_config.pos.w = surf_info.width;
+ plane->info.src_config.pos.h = surf_info.height;
+ plane->info.dst_pos.x = output->config.geom.x;
+ plane->info.dst_pos.y = output->config.geom.y;
+ plane->info.dst_pos.w = output->config.geom.w;
+ plane->info.dst_pos.h = output->config.geom.h;
+ plane->info.transform = TDM_TRANSFORM_NORMAL;
+
+ error = tdm_layer_set_info(tlayer, &plane->info);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("fail to tdm_layer_set_info");
+ return EINA_FALSE;
+ }
+ }
+
+ if (plane_trace_debug)
+ {
+ ELOGF("E_PLANE", "Commit Layer(%p) tsurface(%p) (%dx%d,[%d,%d,%d,%d]=>[%d,%d,%d,%d])",
+ NULL, NULL, plane, tsurface,
+ plane->info.src_config.size.h, plane->info.src_config.size.h,
+ plane->info.src_config.pos.x, plane->info.src_config.pos.y,
+ plane->info.src_config.pos.w, plane->info.src_config.pos.h,
+ plane->info.dst_pos.x, plane->info.dst_pos.y,
+ plane->info.dst_pos.w, plane->info.dst_pos.h);
+ }
+
+ error = tdm_layer_set_buffer(tlayer, tsurface);
+ if (error != TDM_ERROR_NONE)
+ {
+ ERR("fail to tdm_layer_set_buffer");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
-/* local subsystem functions */
static void
-_e_plane_reconfigure_clients(E_Plane *plane,
- int dx,
- int dy,
- int dw,
- int dh)
+_e_plane_surface_on_client_reserved_release(E_Plane *plane, tbm_surface_h tsurface)
{
- EINA_SAFETY_ON_NULL_RETURN(plane->ec);
+ E_Plane_Renderer *renderer = plane->renderer;
+ E_Client *ec = plane->ec;
+
+ if (!ec)
+ {
+ ERR("no ec at plane.");
+ return;
+ }
- /* TODO: config ec refer to resolution */
+ /* release the tsurface */
+ _e_plane_renderer_surface_send(renderer, ec, tsurface);
}
-///////////////////////////////////////////
-EINTERN int
-e_plane_init(void)
+static tbm_surface_h
+_e_plane_surface_from_client_acquire_reserved(E_Plane *plane)
{
- _e_plane_ec_last_err = eina_stringshare_add("UNKNOWN");
- return 1;
+ E_Client *ec = plane->ec;
+ E_Pixmap *pixmap = ec->pixmap;
+ tbm_surface_h tsurface = NULL;
+ E_Plane_Client *plane_client = NULL;
+ E_Plane_Renderer *renderer = plane->renderer;
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Display Client", ec->pixmap, ec);
+
+ plane_client = _e_plane_client_get(ec);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane_client, NULL);
+
+ /* acquire the surface from the client_queue */
+ tsurface = _e_plane_renderer_surface_revice(renderer, ec);
+ if (!tsurface)
+ {
+ e_pixmap_image_clear(pixmap, 1);
+ ERR("fail to _e_plane_renderer_surface_revice");
+ return NULL;
+ }
+
+ /* enqueue the surface to the layer_queue */
+ if (!_e_plane_surface_queue_enqueue(plane, tsurface))
+ {
+ _e_plane_renderer_surface_send(renderer, ec, tsurface);
+ ERR("fail to _e_plane_surface_queue_enqueue");
+ return NULL;
+ }
+
+ /* aquire */
+ tsurface = _e_plane_surface_queue_acquire(plane);
+ if (!tsurface)
+ {
+ _e_plane_renderer_surface_send(renderer, ec, tsurface);
+ ERR("fail _e_plane_surface_queue_acquire");
+ return NULL;
+ }
+
+ return tsurface;
}
-EINTERN int
-e_plane_shutdown(void)
+static void
+_e_plane_surface_on_client_release(E_Plane *plane, tbm_surface_h tsurface)
{
- eina_stringshare_del(_e_plane_ec_last_err);
- return 1;
+ E_Client *ec = plane->ec;
+
+ if (!ec)
+ {
+ ERR("no ec at plane.");
+ return;
+ }
+
+ /* release the tsurface */
+ e_pixmap_image_clear(ec->pixmap, 1);
}
-EINTERN void
-e_plane_free(E_Plane *plane)
+static tbm_surface_h
+_e_plane_surface_from_client_acquire(E_Plane *plane)
{
- //printf("@@@@@@@@@@ e_plane_free: %i %i | %i %i %ix%i = %p\n", zone->num, zone->id, zone->x, zone->y, zone->w, zone->h, zone);
+ E_Client *ec = plane->ec;
+ E_Pixmap *pixmap = ec->pixmap;
+ E_Comp_Wl_Buffer *buffer = e_pixmap_resource_get(pixmap);
+ E_Comp_Wl_Data *wl_comp_data = (E_Comp_Wl_Data *)e_comp->wl_comp_data;
+ tbm_surface_h tsurface = NULL;
- if (!plane) return;
- if (plane->name) eina_stringshare_del(plane->name);
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Display Client", pixmap, ec);
- free(plane);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(buffer, NULL);
+
+ tsurface = wayland_tbm_server_get_surface(wl_comp_data->tbm.server, buffer->resource);
+ if (!tsurface)
+ {
+ ERR("fail to _e_plane_renderer_surface_revice");
+ e_pixmap_image_clear(pixmap, 1);
+ return NULL;
+ }
+
+ return tsurface;
}
-EINTERN E_Plane *
-e_plane_new(E_Output *eout,
- int zpos,
- Eina_Bool is_pri)
+static void
+_e_plane_surface_on_ecore_evas_release(E_Plane *plane, tbm_surface_h tsurface)
{
- E_Plane *plane;
+ /* release the tsurface */
+ _e_plane_surface_queue_release(plane, tsurface);
+}
+
+static tbm_surface_h
+_e_plane_surface_from_ecore_evas_acquire(E_Plane *plane)
+{
+ Evas_Engine_Info_GL_Drm *einfo = NULL;
+ E_Plane_Renderer *renderer = NULL;
+ tbm_surface_h tsurface = NULL;
+ E_Output *output = plane->output;
+
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(einfo, NULL);
+
+ renderer = plane->renderer;
+
+ if (renderer->gsurface != einfo->info.surface)
+ {
+ tbm_surface_queue_h tqueue = NULL;
+
+ renderer->gsurface = einfo->info.surface;
+ tqueue = gbm_tbm_get_surface_queue(renderer->gsurface);
+ if (!tqueue)
+ {
+ ERR("no renderer->tqueue");
+ return NULL;
+ }
+
+ if (!_e_plane_renderer_queue_set(renderer, tqueue))
+ {
+ ERR("fail to _e_plane_renderer_queue_set");
+ return NULL;
+ }
+
+ /* dpms on at the first */
+ if (!e_output_dpms_set(output, E_OUTPUT_DPMS_ON))
+ WRN("fail to set the dpms on.");
+ }
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Display Canvas Layer(%p)", NULL, NULL, plane);
+
+ /* aquire */
+ tsurface = _e_plane_surface_queue_acquire(plane);
+ if (!tsurface)
+ {
+ ERR("tsurface is NULL");
+ return NULL;
+ }
+
+ return tsurface;
+}
+
+static Eina_Bool
+_e_plane_cb_ec_buffer_change(void *data, int type, void *event)
+{
+ E_Client *ec = NULL;
+ E_Event_Client *ev = event;
+ E_Plane_Client *plane_client = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(ev->ec, ECORE_CALLBACK_PASS_ON);
+
+ ec = ev->ec;
+
+ if (e_object_is_del(E_OBJECT(ec))) return ECORE_CALLBACK_PASS_ON;
+
+ plane_client = _e_plane_client_get(ec);
+ if (!plane_client) return ECORE_CALLBACK_PASS_ON;
+
+ if (plane_client->activated) return ECORE_CALLBACK_PASS_ON;
+
+ if (_e_plane_client_surface_flags_get(plane_client) != E_PLANE_CLIENT_SURFACE_FLAGS_RESERVED)
+ return ECORE_CALLBACK_PASS_ON;
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Set Backup Buffer wl_buffer(%p):buffer_change", ec->pixmap, ec, _get_wl_buffer(ec));
+ if (!_e_plane_client_backup_buffer_set(plane_client))
+ ERR("fail to _e_comp_hwc_set_backup_buffer");
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+EINTERN Eina_Bool
+e_plane_init(void)
+{
+ if (client_hook_new) return EINA_TRUE;
+ if (client_hook_del) return EINA_TRUE;
+
+ client_hook_new = e_client_hook_add(E_CLIENT_HOOK_NEW_CLIENT, _e_plane_client_cb_new, NULL);
+ client_hook_del = e_client_hook_add(E_CLIENT_HOOK_DEL, _e_plane_client_cb_del, NULL);
+
+ plane_clients = eina_hash_pointer_new(_e_plane_client_del);
+
+ E_LIST_HANDLER_APPEND(plane_hdlrs, E_EVENT_CLIENT_BUFFER_CHANGE,
+ _e_plane_cb_ec_buffer_change, NULL);
+
+ // soolim debug
+ plane_trace_debug = EINA_TRUE;
+
+ return EINA_TRUE;
+}
+
+EINTERN void
+e_plane_shutdown(void)
+{
+ if (client_hook_new)
+ {
+ e_client_hook_del(client_hook_new);
+ client_hook_new = NULL;
+ }
+
+ if (client_hook_del)
+ {
+ e_client_hook_del(client_hook_del);
+ client_hook_del = NULL;
+ }
+}
+
+EINTERN E_Plane *
+e_plane_new(E_Output *output, int index)
+{
+ E_Plane *plane = NULL;
+ tdm_layer *tlayer = NULL;
+ tdm_output *toutput = NULL;
+ tdm_layer_capability layer_capabilities;
char name[40];
+ E_Plane_Renderer *renderer = NULL;
+ int zpos;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
- if (!eout) return NULL;
+ toutput = output->toutput;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(toutput, NULL);
plane = E_NEW(E_Plane, 1);
EINA_SAFETY_ON_NULL_RETURN_VAL(plane, NULL);
+ plane->index = index;
- snprintf(name, sizeof(name), "Plane %s", eout->id);
+ tlayer = tdm_output_get_layer(toutput, index, NULL);
+ if (!tlayer)
+ {
+ ERR("fail to get layer.");
+ free(plane);
+ return NULL;
+ }
+ plane->tlayer = tlayer;
+
+ snprintf(name, sizeof(name), "%s-plane-%d", output->id, index);
plane->name = eina_stringshare_add(name);
+ CLEAR(layer_capabilities);
+ tdm_layer_get_capabilities(plane->tlayer, &layer_capabilities);
+ /* check the layer is the primary layer */
+ if (layer_capabilities&TDM_LAYER_CAPABILITY_PRIMARY)
+ {
+ plane->is_primary = EINA_TRUE;
+ plane->is_fb = EINA_TRUE; // TODO: query from libtdm if it is fb target plane
+ }
+
+ /* check that the layer uses the reserve nd memory */
+ if (layer_capabilities&TDM_LAYER_CAPABILITY_RESEVED_MEMORY)
+ plane->reserved_memory = EINA_TRUE;
+
+ /* ????? */
plane->type = E_PLANE_TYPE_INVALID;
- plane->eout = eout;
+ tdm_layer_get_zpos(tlayer, &zpos);
plane->zpos = zpos;
- plane->is_primary = is_pri;
- if (plane->is_primary) plane->is_fb = EINA_TRUE; // FIXME: query from libtdm
- /* config default resolution with output size*/
- plane->geometry.x = eout->config.geom.x;
- plane->geometry.y = eout->config.geom.y;
- plane->geometry.w = eout->config.geom.w;
- plane->geometry.h = eout->config.geom.h;
+ renderer = _e_plane_renderer_new(plane);
+ if (!renderer)
+ {
+ ERR("fail to _e_plane_renderer_new");
+ free(plane);
+ return NULL;
+ }
- eout->planes = eina_list_append(eout->planes, plane);
+ plane->renderer = renderer;
+ plane->output = output;
- printf("@@@@@@@@@@ e_plane_new:| %i %i %ix%i\n", plane->geometry.x , plane->geometry.y, plane->geometry.w, plane->geometry.h);
+ INF("E_PLANE: (%d) name:%s zpos:%d capa:%s %s",
+ index, plane->name, plane->zpos,plane->is_primary?"primary":"", plane->reserved_memory?"reserved_memory":"");
return plane;
}
-E_API Eina_Bool
-e_plane_resolution_set(E_Plane *plane,
- int w,
- int h)
+EINTERN void
+e_plane_free(E_Plane *plane)
+{
+ if (!plane) return;
+
+ if (plane->name) eina_stringshare_del(plane->name);
+ if (plane->renderer) _e_plane_renderer_del(plane->renderer);
+
+ free(plane);
+}
+
+EINTERN Eina_Bool
+e_plane_hwc_setup(E_Plane *plane)
+{
+ Evas_Engine_Info_GL_Drm *einfo;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e_comp, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
+
+ /* we assume that the primary plane gets a ecore_evas */
+ if (!plane->is_primary) return EINA_FALSE;
+
+ /* get the evas_engine_gl_drm information */
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ if (!einfo) return EINA_FALSE;
+ /* enable hwc to evas engine gl_drm */
+ einfo->info.hwc_enable = EINA_TRUE;
+
+ plane->ee = e_comp->ee;
+ plane->evas = ecore_evas_get(plane->ee);
+ evas_event_callback_add(plane->evas, EVAS_CALLBACK_RENDER_POST, _e_plane_ee_post_render_cb, plane);
+ ecore_evas_manual_render_set(plane->ee, 1);
+
+ return EINA_TRUE;
+}
+
+EINTERN Eina_Bool
+e_plane_set(E_Plane *plane)
{
- int dx = 0, dy = 0, dw = 0, dh = 0;
+ tbm_surface_h tsurface = NULL;
+ Evas_Engine_Info_GL_Drm *einfo;
EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
- if (plane->is_primary) return EINA_FALSE;
+ if (plane->is_primary && !plane->ec)
+ {
+ ecore_evas_manual_render(plane->ee);
+
+ /* check the post_render is called */
+ if (!plane->update_ee)
+ {
+ ELOGF("E_PLANE", "Post Render callback does not called. Nothing Display.", NULL, NULL);
+ return EINA_FALSE;
+ }
+ plane->update_ee = EINA_FALSE;
+
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ if (!einfo) return EINA_FALSE;
+ /* check outbuf flushed or ont */
+ if (!einfo->info.outbuf_flushed)
+ {
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Commit Canvas outbuf flush nothing!. Nothing Display.", NULL, NULL);
+ if (plane->update_ee) plane->update_ee = EINA_FALSE;
+ return EINA_FALSE;
+ }
+
+ /* uncheck the outbuf_flushed flag */
+ einfo->info.outbuf_flushed = EINA_FALSE;
+
+ tsurface = _e_plane_surface_from_ecore_evas_acquire(plane);
+ }
+ else
+ {
+ E_Comp_Wl_Buffer *buffer = NULL;
+
+ if (!plane->ec) return EINA_FALSE;
+
+ if (!e_comp_object_hwc_update_exists(plane->ec->frame)) return EINA_FALSE;
+
+ e_comp_object_hwc_update_set(plane->ec->frame, EINA_FALSE);
- if ((w == plane->geometry.w) && (h == plane->geometry.h))
- return EINA_FALSE;
+ buffer = e_pixmap_resource_get(plane->ec->pixmap);
+ if (!buffer)
+ {
+ ERR("buffer is null.");
+ return EINA_FALSE;
+ }
- plane->geometry.w = w;
- plane->geometry.h = h;
+ if (plane->reserved_memory)
+ tsurface = _e_plane_surface_from_client_acquire_reserved(plane);
+ else
+ tsurface = _e_plane_surface_from_client_acquire(plane);
+ }
+
+ plane->previous_tsurface = plane->prepare_tsurface;
+ plane->prepare_tsurface = tsurface;
+
+ /* set plane info and set tsurface to the plane */
+ if (!_e_plane_surface_set(plane, tsurface))
+ {
+ ERR("fail: _e_plane_set_info.");
+ e_plane_unset(plane);
+ return EINA_FALSE;
+ }
- /* TODO: config clist refer to resolution */
- _e_plane_reconfigure_clients(plane, dx, dy, dw, dh);
return EINA_TRUE;
}
+EINTERN void
+e_plane_unset(E_Plane *plane)
+{
+ EINA_SAFETY_ON_NULL_RETURN(plane);
+ EINA_SAFETY_ON_NULL_RETURN(plane->prepare_tsurface);
+
+ if (plane->is_primary && !plane->ec)
+ _e_plane_surface_on_ecore_evas_release(plane, plane->prepare_tsurface);
+ else
+ {
+ if (!plane->ec) return;
+ if (plane->reserved_memory) _e_plane_surface_on_client_reserved_release(plane, plane->prepare_tsurface);
+ else _e_plane_surface_on_client_release(plane, plane->prepare_tsurface);
+ }
+
+ /* set plane info and set prevous tsurface to the plane */
+ if (!_e_plane_surface_set(plane, plane->tsurface))
+ {
+ ERR("fail: _e_plane_set_info.");
+ return;
+ }
+}
+
+EINTERN E_Plane_Commit_Data *
+e_plane_commit_data_aquire(E_Plane *plane)
+{
+ E_Plane_Commit_Data *data = NULL;
+ Evas_Engine_Info_GL_Drm *einfo = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, NULL);
+
+ if (plane->is_primary && !plane->ec)
+ {
+ data = E_NEW(E_Plane_Commit_Data, 1);
+ data->plane = plane;
+ data->tsurface = plane->prepare_tsurface;
+ tbm_surface_internal_ref(data->tsurface);
+ data->ec = NULL;
+
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ einfo->info.wait_for_showup = EINA_TRUE;
+
+ return data;
+ }
+ else
+ {
+ if (plane->ec)
+ {
+ data = E_NEW(E_Plane_Commit_Data, 1);
+ data->plane = plane;
+ data->tsurface = plane->prepare_tsurface;
+ tbm_surface_internal_ref(data->tsurface);
+ data->ec = plane->ec;
+ e_comp_wl_buffer_reference(&data->buffer_ref, e_pixmap_resource_get(plane->ec->pixmap));
+
+ /* send frame event enlightenment dosen't send frame evnet in nocomp */
+ e_pixmap_image_clear(plane->ec->pixmap, 1);
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+EINTERN void
+e_plane_commit_data_release(E_Plane_Commit_Data *data)
+{
+ E_Plane *plane = NULL;
+ E_Plane_Renderer *renderer = NULL;
+ Evas_Engine_Info_GL_Drm *einfo = NULL;
+ tbm_surface_h tsurface = NULL;
+ E_Client *ec = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN(data);
+
+ plane = data->plane;
+ tsurface = data->tsurface;
+ ec = data->ec;
+ renderer = plane->renderer;
+
+ if (plane->is_primary && !ec)
+ {
+ /* composite */
+ /* debug */
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Done Layer(%p) tsurface(%p) tqueue(%p) data(%p)::Canvas",
+ NULL, NULL, plane, tsurface, renderer->tqueue, data);
+
+ if (plane->reserved_memory)
+ {
+ if (!renderer->activated_ec)
+ {
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ einfo->info.wait_for_showup = EINA_FALSE;
+ }
+
+ /* initial setting of tsurface to the layer */
+ if (plane->tsurface == NULL)
+ plane->tsurface = tsurface;
+ else
+ {
+ _e_plane_surface_queue_release(plane, plane->tsurface);
+ e_comp_wl_buffer_reference(&plane->displaying_buffer_ref, NULL);
+ plane->tsurface = tsurface;
+ }
+
+ /* send the done surface to the client,
+ only when the renderer state is active(no composite) */
+ if (renderer->activated_ec)
+ _e_plane_renderer_dequeuable_surfaces_export(renderer, renderer->activated_ec);
+ }
+ else
+ {
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+ einfo->info.wait_for_showup = EINA_FALSE;
+
+ /* initial setting of tsurface to the layer */
+ if (plane->tsurface == NULL)
+ plane->tsurface = tsurface;
+ else
+ {
+ _e_plane_surface_queue_release(plane, plane->tsurface);
+ plane->tsurface = tsurface;
+ }
+ }
+
+ tbm_surface_internal_unref(tsurface);
+ free(data);
+ }
+ else
+ {
+ /* no composite */
+ /* debug */
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Done Layer(%p) wl_buffer(%p) tsurface(%p) tqueue(%p) data(%p) wl_buffer_ref(%p) ::Client",
+ ec->pixmap, ec, plane, _get_wl_buffer(ec), tsurface, renderer->tqueue, data, _get_wl_buffer_ref(ec));
+
+ if (plane->reserved_memory)
+ {
+ /* release */
+ if (plane->tsurface)
+ {
+ _e_plane_surface_queue_release(plane, plane->tsurface);
+ e_comp_wl_buffer_reference(&plane->displaying_buffer_ref, data->buffer_ref.buffer);
+ _e_plane_surface_on_client_reserved_release(plane, plane->tsurface);
+ plane->tsurface = tsurface;
+ }
+
+ /* send the done surface to the client,
+ only when the renderer state is active(no composite) */
+ if (renderer->activated_ec)
+ _e_plane_renderer_dequeuable_surfaces_export(renderer, renderer->activated_ec);
+ }
+ else
+ {
+ /* release wl_buffer */
+ e_pixmap_image_clear(ec->pixmap, 1);
+ }
+
+ tbm_surface_internal_unref(tsurface);
+ e_comp_wl_buffer_reference(&data->buffer_ref, NULL);
+ free(data);
+ }
+}
+
+EINTERN Eina_Bool
+e_plane_is_reserved(E_Plane *plane)
+{
+ return plane->is_reserved;
+}
+
+EINTERN void
+e_plane_reserved_set(E_Plane *plane, Eina_Bool set)
+{
+ plane->is_reserved = set;
+}
+
E_API Eina_Bool
e_plane_type_set(E_Plane *plane,
E_Plane_Type type)
return plane->ec;
}
+E_API Eina_Bool
+e_plane_ec_set(E_Plane *plane, E_Client *ec)
+{
+ E_Plane_Renderer *renderer = NULL;
+ Evas_Engine_Info_GL_Drm *einfo = NULL;
+ E_Plane_Client *plane_client = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
+
+ renderer = plane->renderer;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(renderer, EINA_FALSE);
+
+ einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(e_comp->evas);
+
+ if (!ec && renderer->candidate_ec)
+ {
+ if (!plane->is_primary)
+ _e_plane_renderer_queue_del(renderer);
+
+ if (!_e_plane_renderer_deactivate(renderer))
+ {
+ ERR("fail to _e_plane_renderer_deactivate.");
+ return EINA_FALSE;
+ }
+ }
+
+ if (!ec && !plane->ec) return EINA_FALSE;
+
+ /* activate/deactivate the client if the plane is the reserved memory */
+ if (plane->reserved_memory)
+ {
+ if (ec)
+ {
+ if (!plane->is_primary)
+ _e_plane_renderer_queue_create(renderer, ec->client.w, ec->client.h);
+
+ if (!_e_plane_renderer_activate(renderer, ec))
+ {
+ INF("can't activate ec:%p.", ec);
+
+ if (!_e_plane_surface_queue_can_dequeue(renderer->plane))
+ einfo->info.wait_for_showup = EINA_TRUE;
+
+ return EINA_FALSE;
+ }
+
+ einfo->info.wait_for_showup = EINA_TRUE;
+ e_comp_object_hwc_update_set(ec->frame, EINA_TRUE);
+ }
+ else
+ {
+ if (!plane->is_primary)
+ _e_plane_renderer_queue_del(renderer);
+
+ if (!_e_plane_renderer_deactivate(renderer))
+ {
+ ERR("fail to _e_plane_renderer_deactivate.");
+ return EINA_FALSE;
+ }
+
+ einfo->info.wait_for_showup = EINA_FALSE;
+ }
+ }
+
+ if (ec)
+ {
+ plane_client = _e_plane_client_get(ec);
+ if (plane_client) plane_client->plane = plane;
+ }
+
+ plane->ec = ec;
+
+ if (plane_trace_debug)
+ ELOGF("E_PLANE", "Plane(%p) ec Set", (ec ? ec->pixmap : NULL), ec, plane);
+
+ return EINA_TRUE;
+}
+
E_API E_Client *
e_plane_ec_prepare_get(E_Plane *plane)
{
}
E_API Eina_Bool
-e_plane_ec_prepare_set(E_Plane *plane,
- E_Client *ec)
+e_plane_ec_prepare_set(E_Plane *plane, E_Client *ec)
{
- if(!plane)
- {
- eina_stringshare_replace(&_e_plane_ec_last_err, "Invalid e_plane were passed");
- goto err;
- }
+ EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
- if (plane->type == E_PLANE_TYPE_OVERLAY)
- {
- eina_stringshare_replace(&_e_plane_ec_last_err, NULL);
- plane->prepare_ec = ec;
- return EINA_TRUE;
- }
- eina_stringshare_replace(&_e_plane_ec_last_err, "Type dismatch : ec not availabe on e_plane");
-err:
+ plane->prepare_ec = ec;
- return EINA_FALSE;
+ return EINA_TRUE;
}
E_API const char *
return plane->color;
}
-E_API void
-e_plane_geom_get(E_Plane *plane,
- int *x,
- int *y,
- int *w,
- int *h)
-{
- if (!plane) return;
- if (x) *x = plane->geometry.x;
- if (y) *y = plane->geometry.y;
- if (w) *w = plane->geometry.w;
- if (h) *h = plane->geometry.h;
-}
-
E_API Eina_Bool
e_plane_is_fb_target(E_Plane *plane)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(plane, EINA_FALSE);
if (plane->is_fb) return EINA_TRUE;
return EINA_FALSE;
-}
\ No newline at end of file
+}
#ifdef E_TYPEDEFS
-typedef enum _E_Plane_Type_State
+typedef enum _E_Plane_Type
{
E_PLANE_TYPE_INVALID,
E_PLANE_TYPE_VIDEO,
} E_Plane_Color;
typedef struct _E_Plane E_Plane;
-
+typedef struct _E_Plane_Renderer E_Plane_Renderer;
+typedef struct _E_Plane_Commit_Data E_Plane_Commit_Data;
#else
#ifndef E_PLANE_H
#define E_PLANE_H
#define E_PLANE_TYPE (int)0xE0b11001
+#include "e_comp_screen.h"
+#include "e_output.h"
+# include "e_comp_wl.h"
+
struct _E_Plane
{
+ int index;
int zpos;
- struct
- {
- int x, y, w, h;
- } geometry;
-
const char *name;
E_Plane_Type type;
E_Plane_Color color;
+ Eina_Bool is_primary;
+ Eina_Bool is_fb; // fb target
+ Eina_Bool is_reserved; // surface assignment reserved
E_Client *ec;
E_Client *prepare_ec;
- E_Output *eout;
- Eina_Bool is_primary;
- Eina_Bool is_fb; // fb target
+ Eina_Bool reserved_memory;
+
+ tdm_layer *tlayer;
+ tdm_info_layer info;
+ tbm_surface_h tsurface;
+ tbm_surface_h previous_tsurface;
+ tbm_surface_h prepare_tsurface;
+
+ unsigned int last_sequence;
+ E_Comp_Wl_Buffer_Ref displaying_buffer_ref;
+
+ E_Plane_Renderer *renderer;
+ E_Output *output;
+
+ Ecore_Evas *ee;
+ Evas *evas;
+ Eina_Bool update_ee;
+
+ Eina_Bool trace_debug;
+};
+
+struct _E_Plane_Renderer {
+ tbm_surface_queue_h tqueue;
+
+ E_Client *activated_ec;
+ E_Client *candidate_ec;
+
+ struct gbm_surface *gsurface;
+ Eina_List *disp_surfaces;
+ Eina_List *sent_surfaces;
+ Eina_List *exported_surfaces;
+
+ E_Plane *plane;
+};
+
+struct _E_Plane_Commit_Data {
+ tbm_surface_h tsurface;
+ E_Plane *plane;
+ E_Client *ec;
+ E_Comp_Wl_Buffer_Ref buffer_ref;
};
-EINTERN int e_plane_init(void);
-EINTERN int e_plane_shutdown(void);
-EINTERN E_Plane *e_plane_new(E_Output *eout, int zpos, Eina_Bool is_pri);
+EINTERN Eina_Bool e_plane_init(void);
+EINTERN void e_plane_shutdown(void);
+EINTERN E_Plane *e_plane_new(E_Output *output, int index);
EINTERN void e_plane_free(E_Plane *plane);
-E_API Eina_Bool e_plane_resolution_set(E_Plane *plane, int w, int h);
+EINTERN Eina_Bool e_plane_hwc_setup(E_Plane *plane);
+EINTERN Eina_Bool e_plane_set(E_Plane *plane);
+EINTERN void e_plane_unset(E_Plane *plane);
+EINTERN E_Plane_Commit_Data *e_plane_commit_data_aquire(E_Plane *plane);
+EINTERN void e_plane_commit_data_release(E_Plane_Commit_Data *data);
+EINTERN Eina_Bool e_plane_is_reserved(E_Plane *plane);
+EINTERN void e_plane_reserved_set(E_Plane *plane, Eina_Bool set);
E_API Eina_Bool e_plane_type_set(E_Plane *plane, E_Plane_Type type);
E_API E_Plane_Type e_plane_type_get(E_Plane *plane);
E_API E_Client *e_plane_ec_get(E_Plane *plane);
+E_API Eina_Bool e_plane_ec_set(E_Plane *plane, E_Client *ec);
E_API E_Client *e_plane_ec_prepare_get(E_Plane *plane);
E_API Eina_Bool e_plane_ec_prepare_set(E_Plane *plane, E_Client *ec);
E_API const char *e_plane_ec_prepare_set_last_error_get(E_Plane *plane);
E_API Eina_Bool e_plane_is_primary(E_Plane *plane);
E_API Eina_Bool e_plane_is_cursor(E_Plane *plane);
E_API E_Plane_Color e_plane_color_val_get(E_Plane *plane);
-E_API void e_plane_geom_get(E_Plane *plane, int *x, int *y, int *w, int *h);
E_API Eina_Bool e_plane_is_fb_target(E_Plane *plane);
#endif