e_display: add e_display
authorSooChan Lim <sc1.lim@samsung.com>
Thu, 13 Jun 2024 02:27:56 +0000 (11:27 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Wed, 3 Jul 2024 04:46:25 +0000 (13:46 +0900)
e_display initialize the Display and the Outputs in Enlightenemnt.
It initialize the tdm display and tdm output at start of the Enlightenment.

Change-Id: I8146130cdcd8b3670089b80787229292a300eaec

src/bin/Makefile.mk
src/bin/displaymgr/e_display.c [new file with mode: 0644]
src/bin/displaymgr/e_display_intern.h [new file with mode: 0644]

index b7f117b..bcefbc0 100644 (file)
@@ -235,6 +235,7 @@ src/bin/compmgr/e_comp_canvas.c \
 src/bin/compmgr/e_comp_object.c \
 src/bin/compmgr/e_egl_sync.c \
 src/bin/compmgr/e_alpha_mask_rect.c \
+src/bin/displaymgr/e_display.c \
 src/bin/displaymgr/e_output.c \
 src/bin/displaymgr/e_scale.c \
 src/bin/displaymgr/e_plane_renderer.c \
diff --git a/src/bin/displaymgr/e_display.c b/src/bin/displaymgr/e_display.c
new file mode 100644 (file)
index 0000000..f333781
--- /dev/null
@@ -0,0 +1,915 @@
+#include "e_display_intern.h"
+#include "e_hwc_intern.h"
+#include "e_hwc_windows_intern.h"
+#include "e_hwc_planes_intern.h"
+#include "e_utils_intern.h"
+#include "e_scale_intern.h"
+#include "e_comp_screen_intern.h"
+#include "e_comp_intern.h"
+
+#include <device/board-internal.h>
+#include <tbm_drm_helper.h>
+#include <gbm.h>
+
+#define NUM_SW_FORMAT   (sizeof(sw_formats) / sizeof(sw_formats[0]))
+
+typedef struct _E_Display E_Display;
+
+struct _E_Display
+{
+   tdm_display *tdisplay;
+   int          fd;
+
+   void        *gdevice;
+   int          gdevice_fd;
+
+   Eina_Bool  pp_enabled;
+   Eina_List *available_pp_formats;
+
+   Ecore_Fd_Handler *hdlr;
+
+   int          num_outputs;
+   Eina_List   *outputs; // available screens
+};
+
+static E_Display *g_display = NULL; // global e_display
+
+static tbm_format sw_formats[] = {
+     TBM_FORMAT_ARGB8888,
+     TBM_FORMAT_XRGB8888,
+     TBM_FORMAT_YUV420,
+     TBM_FORMAT_YVU420,
+};
+
+static char *
+_e_display_dpms_to_string(E_OUTPUT_DPMS dpms)
+{
+   switch (dpms)
+     {
+        case E_OUTPUT_DPMS_ON:
+          return "DPMS_ON";
+          break;
+        case E_OUTPUT_DPMS_STANDBY:
+          return "DPMS_STANDBY";
+          break;
+        case E_OUTPUT_DPMS_SUSPEND:
+          return "DPMS_SUSPEND";
+          break;
+        case E_OUTPUT_DPMS_OFF:
+          return "DPMS_OFF";
+          break;
+        default:
+          return "Unknown";
+     }
+}
+
+static tdm_layer *
+_e_display_video_tdm_layer_get(tdm_output *output)
+{
+   int i, count = 0;
+#ifdef CHECKING_PRIMARY_ZPOS
+   int primary_idx = 0, primary_zpos = 0;
+   tdm_layer *primary_layer;
+#endif
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
+
+   tdm_output_get_layer_count(output, &count);
+   for (i = 0; i < count; i++)
+     {
+        tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+        tdm_layer_capability capabilities = 0;
+        EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+        tdm_layer_get_capabilities(layer, &capabilities);
+        if (capabilities & TDM_LAYER_CAPABILITY_VIDEO)
+          return layer;
+     }
+
+#ifdef CHECKING_PRIMARY_ZPOS
+   tdm_output_get_primary_index(output, &primary_idx);
+   primary_layer = tdm_output_get_layer(output, primary_idx, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(primary_layer, NULL);
+   tdm_layer_get_zpos(primary_layer, &primary_zpos);
+#endif
+
+   for (i = 0; i < count; i++)
+     {
+        tdm_layer *layer = tdm_output_get_layer(output, i, NULL);
+        tdm_layer_capability capabilities = 0;
+        EINA_SAFETY_ON_NULL_RETURN_VAL(layer, NULL);
+
+        tdm_layer_get_capabilities(layer, &capabilities);
+        if (capabilities & TDM_LAYER_CAPABILITY_OVERLAY)
+          {
+#ifdef CHECKING_PRIMARY_ZPOS
+             int zpos = 0;
+             tdm_layer_get_zpos(layer, &zpos);
+             if (zpos >= primary_zpos) continue;
+#endif
+             return layer;
+          }
+     }
+
+   return NULL;
+}
+
+static E_Output *
+_e_display_eoutput_get_by_toutput(tdm_output *output)
+{
+   Eina_List *l;
+   E_Output *eo;
+
+   EINA_LIST_FOREACH(e_display_outputs_get(), l, eo)
+      if (eo->toutput == output)
+        return eo;
+
+   return NULL;
+}
+
+static char *
+_layer_cap_to_str(tdm_layer_capability caps, tdm_layer_capability cap)
+{
+   if (caps & cap)
+     {
+        if (cap == TDM_LAYER_CAPABILITY_CURSOR) return "cursor ";
+        else if (cap == TDM_LAYER_CAPABILITY_PRIMARY) return "primary ";
+        else if (cap == TDM_LAYER_CAPABILITY_OVERLAY) return "overlay ";
+        else if (cap == TDM_LAYER_CAPABILITY_GRAPHIC) return "graphics ";
+        else if (cap == TDM_LAYER_CAPABILITY_VIDEO) return "video ";
+        else if (cap == TDM_LAYER_CAPABILITY_TRANSFORM) return "transform ";
+        else if (cap == TDM_LAYER_CAPABILITY_RESEVED_MEMORY) return "reserved_memory ";
+        else if (cap == TDM_LAYER_CAPABILITY_NO_CROP) return "no_crop ";
+        else return "unkown";
+     }
+   return "";
+}
+
+static void
+_display_output_mode_change_cb(tdm_output *toutput, unsigned int index, void *user_data)
+{
+   E_Display *display = user_data;
+   E_Output *output = NULL;
+   Eina_Bool find = EINA_FALSE;
+   int count, num;
+   E_Output_Mode *set_emode = NULL, *current_emode = NULL;
+   E_Output_Mode *emode = NULL;
+   Eina_List *modelist = NULL, *l, *ll;
+
+   EINA_SAFETY_ON_NULL_RETURN(display);
+
+   EINA_LIST_FOREACH_SAFE(display->outputs, l, ll, output)
+     {
+        if (output->toutput == toutput)
+          {
+             find = EINA_TRUE;
+             break;
+          }
+     }
+   EINA_SAFETY_ON_FALSE_RETURN(find == EINA_TRUE);
+
+   current_emode = e_output_current_mode_get(output);
+   EINA_SAFETY_ON_NULL_RETURN(current_emode);
+
+   modelist = e_output_mode_list_get(output);
+   if (modelist)
+     {
+        num = eina_list_count(modelist);
+        EINA_SAFETY_ON_FALSE_RETURN(index < num);
+
+        count = 0;
+        EINA_LIST_FOREACH(modelist, l, emode)
+          {
+             if (count == index)
+               {
+                  set_emode = emode;
+                  break;
+               }
+             count++;
+          }
+
+        if (set_emode)
+          {
+             EINA_SAFETY_ON_TRUE_RETURN(current_emode == set_emode);
+
+             ELOGF("COMP_SCREEN","request mode change(%d) (%dx%d, %lf) -> (%dx%d, %lf)\n",
+                   NULL, index, current_emode->w, current_emode->h, current_emode->refresh,
+                   set_emode->w, set_emode->h, set_emode->refresh);
+
+             e_output_external_mode_change(output, set_emode);
+          }
+     }
+}
+
+static void
+_display_output_destroy_cb(tdm_output *toutput, void *user_data)
+{
+   E_Display *display = user_data;
+   E_Output *output = NULL;
+   Eina_List *l, *ll;
+
+   EINA_SAFETY_ON_NULL_RETURN(display);
+
+   tdm_output_remove_destroy_handler(toutput, _display_output_destroy_cb, display);
+
+   EINA_LIST_FOREACH_SAFE(display->outputs, l, ll, output)
+     {
+        if (output->toutput == toutput)
+          {
+             display->num_outputs--;
+             display->outputs = eina_list_remove_list(display->outputs, l);
+             e_output_del(output);
+          }
+     }
+}
+
+static void
+_e_display_cb_output_created(tdm_display *dpy, tdm_output *toutput, void *user_data)
+{
+   E_Display *display = user_data;
+   E_Output *output = NULL;
+   tdm_error ret = TDM_ERROR_NONE;
+
+   EINA_SAFETY_ON_NULL_RETURN(display);
+
+   TRACE_DS_BEGIN(OUTPUT:NEW);
+   output = e_output_new1(display->num_outputs);
+   EINA_SAFETY_ON_NULL_GOTO(output, fail);
+   if (output->toutput != toutput) goto fail;
+   TRACE_DS_END();
+
+   TRACE_DS_BEGIN(OUTPUT:UPDATE);
+   if (!e_output_update(output))
+     {
+        ERR("fail to e_output_update.");
+        e_output_del(output);
+        goto fail;
+     }
+   TRACE_DS_END();
+
+   /* todo : add tdm_output_add_mode_change_request_handler()*/
+   ret = tdm_output_add_mode_change_request_handler(toutput, _display_output_mode_change_cb, display);
+   if (ret != TDM_ERROR_NONE)
+     {
+        ERR("fail to add output mode change handler.");
+        e_output_del(output);
+        return;
+     }
+
+   ret = tdm_output_add_destroy_handler(toutput, _display_output_destroy_cb, display);
+   if (ret != TDM_ERROR_NONE)
+     {
+        ERR("fail to add output destroy handler.");
+        e_output_del(output);
+        return;
+     }
+
+   display->outputs = eina_list_append(display->outputs, output);
+   display->num_outputs++;
+
+   return;
+
+fail:
+   TRACE_DS_END();
+}
+
+static Eina_Bool
+_display_fake_output_set(E_Display *display)
+{
+   E_Output *primary_output = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(display, EINA_FALSE);
+
+   primary_output = e_display_primary_output_get();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(primary_output, EINA_FALSE);
+
+   if (!e_output_hwc_setup(primary_output))
+     {
+        ERR("fail to e_output_hwc_setup.");
+        return EINA_FALSE;
+     }
+
+   if (!e_output_fake_config_set(primary_output, 2, 1))
+     {
+        ERR("Fail to set the fake output config!");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_display_deinit_outputs(E_Display *display)
+{
+   E_Output *output;
+   Eina_List *l, *ll;
+
+   tdm_display_remove_output_create_handler(display->tdisplay, _e_display_cb_output_created, display);
+
+   // free up e_outputs
+   EINA_LIST_FOREACH_SAFE(display->outputs, l, ll, output)
+     {
+        display->outputs = eina_list_remove_list(display->outputs, l);
+        e_output_del(output);
+     }
+
+   e_hwc_ecore_evas_deinit();
+   e_hwc_deinit();
+   e_hwc_windows_deinit();
+   e_hwc_planes_deinit();
+
+   e_output_shutdown();
+}
+
+static Eina_Bool
+_e_display_init_outputs(E_Display *display)
+{
+   E_Output *output = NULL;
+   E_Output_Mode *mode = NULL;
+   tdm_display *tdisplay = display->tdisplay;
+   int num_outputs;
+   int i;
+   Eina_Bool scale_updated = EINA_FALSE;
+   Eina_Bool connection_check = EINA_FALSE;
+   tdm_error err = TDM_ERROR_NONE;
+   char bootmode[32];
+   int ret;
+
+   /* init e_output */
+   if (!e_output_init())
+     {
+        ERR("fail to e_output_init.");
+        return EINA_FALSE;
+     }
+
+   /* get the num of outputs */
+   err = tdm_display_get_output_count(tdisplay, &num_outputs);
+   if ((err != TDM_ERROR_NONE) ||
+       (num_outputs < 1))
+     {
+        ERR("fail to get tdm_display_get_output_count\n");
+        return EINA_FALSE;
+     }
+   display->num_outputs = num_outputs;
+
+   ELOGF("COMP_SCREEN","num_outputs = %i", NULL, display->num_outputs);
+
+   if (!e_hwc_init())
+     {
+        ERR("e_hwc_init failed");
+        goto fail;
+     }
+
+   if (!e_hwc_planes_init())
+     {
+        ERR("e_hwc_planes_init failed");
+        goto fail;
+     }
+
+   if (!e_hwc_windows_init())
+     {
+        ERR("e_hwc_windows_init failed");
+        goto fail;
+     }
+
+   for (i = 0; i < num_outputs; i++)
+     {
+        e_main_ts_begin("\tE_Output New");
+        output = e_output_new1(i);
+        if (!output)
+          {
+             e_main_ts_end("\tE_Output New Failed");
+             goto fail;
+          }
+
+        e_main_ts_begin("\tE_Output Update");
+        if (!e_output_update(output))
+          {
+            e_main_ts_end("\tE_Output Update Failed");
+            ERR("fail to e_output_update.");
+            goto fail;
+          }
+        e_main_ts_end("\tE_Output Update Done");
+
+        display->outputs = eina_list_append(display->outputs, output);
+
+        if (!e_output_connected(output)) continue;
+
+        connection_check = EINA_TRUE;
+
+        /* setting with the best mode and enable the output */
+        e_main_ts_begin("\tE_Output Find Best Mode");
+        mode = e_output_best_mode_find(output);
+        if (!mode)
+          {
+             e_main_ts_end("\tE_Output Find Best Mode Failed");
+             ERR("fail to get best mode.");
+             goto fail;
+          }
+        e_main_ts_end("\tE_Output Find Best Mode Done");
+
+        e_main_ts_begin("\tE_Output Mode Apply");
+        if (!e_output_mode_apply(output, mode))
+          {
+             e_main_ts_end("\tE_Output Mode Apply Failed");
+             ERR("fail to e_output_mode_apply.");
+             goto fail;
+          }
+        e_main_ts_end("\tE_Output Mode Apply Done");
+
+        e_main_ts_begin("\tE_Output Set DPMS ON");
+        ret = device_board_get_boot_mode(bootmode, sizeof(bootmode));
+        if (!ret && !e_util_strcmp(bootmode, "silent"))
+          {
+             INF("silent reboot. do not set dpms");
+          }
+        else
+          {
+             if (!e_output_dpms_set(output, E_OUTPUT_DPMS_ON))
+               {
+                  e_main_ts_end("\tE_Output Set DPMS ON Failed");
+                  ERR("fail to e_output_dpms.");
+                  goto fail;
+               }
+          }
+
+        e_main_ts_end("\tE_Output Set DPMS ON Done");
+
+        e_main_ts_begin("\tE_Output Hwc Setup");
+        if (!e_output_hwc_setup(output))
+          {
+             e_main_ts_end("\tE_Output Hwc Setup Failed");
+             ERR("fail to e_output_hwc_setup.");
+             goto fail;
+          }
+        e_main_ts_end("\tE_Output Hwc Setup Done");
+
+        /* update e_scale with first available output size */
+        if ((e_config->scale.for_tdm) && (!scale_updated))
+          {
+             double target_inch;
+             int dpi;
+
+             target_inch = (round((sqrt(output->info.size.w * output->info.size.w + output->info.size.h * output->info.size.h) / 25.4) * 10) / 10);
+             dpi = (round((sqrt(mode->w * mode->w + mode->h * mode->h) / target_inch) * 10) / 10);
+
+             e_scale_manual_update(dpi);
+             scale_updated = EINA_TRUE;
+          }
+     }
+
+   //TODO: if there is no output connected, make the fake output which is connected.
+   if (!connection_check)
+     {
+        if (!_display_fake_output_set(display))
+          goto fail;
+     }
+
+   // FIXME: donot call e_comp_screen function at e_display. move this function to other plane, need refactoring
+   e_comp_screen_size_update(e_comp->e_comp_screen);
+
+   e_main_ts_begin("\tE_Hwc Ecore_Evas Init");
+   if (!e_hwc_ecore_evas_init())
+     {
+        e_main_ts_end("\ttE_Hwc Ecore_Evas Init Failed");
+        ERR("fail to e_hwc_ecore_evas_init");
+        goto fail;
+     }
+   e_main_ts_end("\tE_Hwc Ecore_Evas Init Done");
+
+   if (tdm_display_add_output_create_handler(tdisplay, _e_display_cb_output_created, display))
+     goto fail;
+
+   return EINA_TRUE;
+
+fail:
+   _display_deinit_outputs(display);
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_e_display_cb_tdm_display_interrupt(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+   E_Display *display;
+   tdm_error ret;
+
+   if (!(display = data)) return ECORE_CALLBACK_RENEW;
+
+   ret = tdm_display_handle_events(display->tdisplay);
+   if (ret != TDM_ERROR_NONE)
+     ERR("tdm_display_handle_events failed");
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+EINTERN Eina_Bool
+e_display_init(void)
+{
+   E_Display *display;
+   tdm_display_capability capabilities;
+   const tbm_format *pp_formats;
+   tdm_error error = TDM_ERROR_NONE;
+   int count, i;
+   int fd;
+
+   if (g_display) return EINA_TRUE;
+
+   display = E_NEW(E_Display, 1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(display, EINA_FALSE);
+
+   g_display = display;
+
+   display->tdisplay = tdm_display_init(&error);
+   if (!display->tdisplay)
+     {
+        ERR("fail to tdm_display_init");
+        goto fail;
+     }
+
+   display->gdevice_fd = -1;
+   display->fd = -1;
+
+   tdm_display_get_fd(display->tdisplay, &fd);
+   if (fd < 0)
+     {
+        ERR("fail to get tdm_display fd");
+        goto fail;
+     }
+
+   display->fd = dup(fd);
+
+   error = tdm_display_get_capabilities(display->tdisplay, &capabilities);
+   if (error != TDM_ERROR_NONE)
+     {
+        ERR("tdm get_capabilities failed");
+        goto fail;
+     }
+
+   /* check the pp_support */
+   if (capabilities & TDM_DISPLAY_CAPABILITY_PP)
+     {
+        error = tdm_display_get_pp_available_formats(display->tdisplay,
+                        &pp_formats, &count);
+        if (error != TDM_ERROR_NONE)
+          ERR("fail to get available pp formats");
+        else
+          {
+             display->pp_enabled = EINA_TRUE;
+             for (i = 0 ; i < count ; i++)
+              {
+                 display->available_pp_formats =
+                        eina_list_append(display->available_pp_formats,
+                        &pp_formats[i]);
+              }
+          }
+     }
+
+   display->hdlr = ecore_main_fd_handler_add(display->fd, ECORE_FD_READ,
+            _e_display_cb_tdm_display_interrupt, display, NULL, NULL);
+
+   if (e_comp_socket_init("tdm-socket"))
+     PRCTL("[Winsys] change permission and create sym link for %s", "tdm-socket");
+
+   if (!_e_display_init_outputs(display))
+     {
+        ERR("tdm get_capabilities failed");
+        goto fail;
+     }
+
+   return EINA_TRUE;
+
+fail:
+   if (display->hdlr) ecore_main_fd_handler_del(display->hdlr);
+   if (display->fd >= 0) close(display->fd);
+   if (display->tdisplay) tdm_display_deinit(display->tdisplay);
+
+   E_FREE(display);
+   g_display = NULL;
+
+   return EINA_FALSE;
+}
+
+
+EINTERN void
+e_display_shutdown(void)
+{
+   Eina_List *l, *ll;
+   tbm_format *formats;
+
+   if (!g_display) return;
+
+   _display_deinit_outputs(g_display);
+
+   if (g_display->pp_enabled)
+     {
+        EINA_LIST_FOREACH_SAFE(g_display->available_pp_formats, l, ll, formats)
+          {
+             if (!formats) continue;
+             g_display->available_pp_formats = eina_list_remove(g_display->available_pp_formats, l);
+          }
+     }
+   if (g_display->gdevice) gbm_device_destroy(g_display->gdevice);
+   if (g_display->gdevice_fd >= 0) close(g_display->gdevice_fd);
+   if (g_display->fd >= 0) close(g_display->fd);
+   if (g_display->hdlr) ecore_main_fd_handler_del(g_display->hdlr);
+   if (g_display->tdisplay) tdm_display_deinit(g_display->tdisplay);
+
+   E_FREE(g_display);
+   g_display = NULL;
+}
+
+
+EINTERN E_Output *
+e_display_primary_output_get(void)
+{
+   E_Output *output = NULL, *o;
+   const Eina_List *l;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, NULL);
+
+   EINA_LIST_FOREACH(g_display->outputs, l, o)
+     {
+        unsigned int pipe = 0;
+        tdm_error error;
+
+        error = tdm_output_get_pipe(o->toutput, &pipe);
+        if (error != TDM_ERROR_NONE || pipe != 0)
+          continue;
+
+        output = o;
+        break;
+     }
+
+   if (!output)
+     {
+        ERR("couldn't find the primary output");
+        return NULL;
+     }
+
+   return output;
+}
+
+EINTERN void *
+e_display_tdm_display_get(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, NULL);
+
+   return (void *)g_display->tdisplay;
+}
+
+EINTERN void *
+e_display_gbm_device_get(void)
+{
+   int fd;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, NULL);
+
+   if (g_display->gdevice) return g_display->gdevice;
+
+   fd = tbm_drm_helper_get_master_fd();
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(fd >= 0, NULL);
+
+   g_display->gdevice = gbm_create_device(fd);
+   if (!g_display->gdevice)
+     {
+        ERR("fail to create gbm device");
+        close(fd);
+        return NULL;
+     }
+
+   g_display->gdevice_fd = fd;
+
+   return g_display->gdevice;
+}
+
+EINTERN Eina_List *
+e_display_outputs_get(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, NULL);
+
+   return g_display->outputs;
+}
+
+EINTERN int
+e_display_num_outputs_get(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, -1);
+
+   return g_display->num_outputs;
+}
+
+EINTERN Eina_Bool
+e_display_pp_support(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, EINA_TRUE);
+
+   return g_display->pp_enabled;
+}
+
+EINTERN Eina_Bool
+e_display_available_video_formats_get(const tbm_format **formats, int *count)
+{
+   E_Output *output;
+   tdm_output *toutput;
+   tdm_layer *layer;
+   tdm_error error;
+
+   *count = 0;
+
+   if (e_display_pp_support())
+     {
+        error = tdm_display_get_pp_available_formats(g_display->tdisplay, formats, count);
+        if (error == TDM_ERROR_NONE)
+          return EINA_TRUE;
+     }
+
+   /* get the first output */
+   toutput = tdm_display_get_output(g_display->tdisplay, 0, NULL);
+   if (!toutput)
+     return EINA_FALSE;
+
+   output = _e_display_eoutput_get_by_toutput(toutput);
+   if (!output)
+     return EINA_FALSE;
+
+   if (e_hwc_policy_get(output->hwc) != E_HWC_POLICY_WINDOWS)
+     {
+        /* get the first suitable layer */
+        layer = _e_display_video_tdm_layer_get(toutput);
+        if (layer)
+          {
+             tdm_layer_get_available_formats(layer, formats, count);
+          }
+        else
+          {
+             *formats = sw_formats;
+             *count = NUM_SW_FORMAT;
+          }
+     }
+   else
+     {
+        error = tdm_hwc_get_video_supported_formats(output->hwc->thwc, formats, count);
+        if (error != TDM_ERROR_NONE)
+          {
+             *formats = sw_formats;
+             *count = NUM_SW_FORMAT;
+          }
+     }
+
+   return EINA_TRUE;
+}
+
+
+EINTERN Eina_List *
+e_display_pp_available_formats_get(void)
+{
+  EINA_SAFETY_ON_NULL_RETURN_VAL(g_display, EINA_FALSE);
+
+  if (!g_display->pp_enabled)
+    {
+       ERR("pp does not support.");
+       return NULL;
+    }
+
+   return g_display->available_pp_formats;
+}
+
+EINTERN void
+e_display_pp_available_size_get(int *minw, int *minh, int *maxw, int *maxh, int *align)
+{
+   EINA_SAFETY_ON_NULL_RETURN(g_display);
+
+   tdm_display_get_pp_available_size(g_display->tdisplay,
+             minw, minh, maxw, maxh, align);
+}
+
+EINTERN void
+e_display_hwc_info_debug(void)
+{
+   EINA_SAFETY_ON_NULL_RETURN(g_display);
+
+   E_Display *display = g_display;
+   E_Output *output = NULL;
+   E_Plane *plane = NULL;
+   Eina_List *l_o, *ll_o;
+   Eina_List *l_l, *ll_l;
+   tdm_output_conn_status conn_status;
+   int output_idx = 0;
+   tdm_layer_capability layer_capabilities;
+   char layer_cap[4096] = {0, };
+   int i;
+   const tdm_prop *tprops;
+   int count;
+
+   INF("HWC: HWC Information ==========================================================");
+   EINA_LIST_FOREACH_SAFE(display->outputs, l_o, ll_o, output)
+     {
+        tdm_error err = TDM_ERROR_NONE;
+
+        if (!output) continue;
+
+        if (e_hwc_policy_get(output->hwc) == E_HWC_POLICY_PLANES)
+          {
+             err = tdm_output_get_conn_status(output->toutput, &conn_status);
+             if (err != TDM_ERROR_NONE) continue;
+             if (conn_status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) continue;
+
+             INF("HWC: HWC Output(%d):(x, y, w, h)=(%d, %d, %d, %d) Information.",
+                 ++output_idx,
+                 output->config.geom.x, output->config.geom.y, output->config.geom.w, output->config.geom.h);
+             INF("HWC:  num_layers=%d", output->plane_count);
+             EINA_LIST_FOREACH_SAFE(output->planes, l_l, ll_l, plane)
+               {
+                   if (!plane) continue;
+                   /* FIXME: hwc extension doesn't provide thing like layer */
+                   tdm_layer_get_capabilities(plane->tlayer, &layer_capabilities);
+                   snprintf(layer_cap, sizeof(layer_cap), "%s%s%s%s%s%s%s%s",
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_CURSOR),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_PRIMARY),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_OVERLAY),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_GRAPHIC),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_VIDEO),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_TRANSFORM),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_RESEVED_MEMORY),
+                            _layer_cap_to_str(layer_capabilities, TDM_LAYER_CAPABILITY_NO_CROP));
+                   INF("HWC:  index=%d zpos=%d ec=%p %s",
+                       plane->index, plane->zpos,
+                       plane->ec?plane->ec:NULL,
+                       layer_cap);
+               }
+          }
+        else
+          {
+             /* TODO: construct debug info for outputs managed by the hwc-wins */
+             INF("HWC: HWC Output(%d) managed by hwc-wins.", ++output_idx);
+
+             if (!e_hwc_windows_get_available_properties(output->hwc, &tprops, &count))
+               {
+                  ERR("e_hwc_windows_get_video_available_properties failed");
+                  return;
+               }
+             INF(">>>>>>>> Available UI props : count = %d", count);
+             for (i = 0; i < count; i++)
+               INF("   [%d] %s, %u", i, tprops[i].name, tprops[i].id);
+
+             if (!e_hwc_windows_get_video_available_properties(output->hwc, &tprops, &count))
+               {
+                  ERR("e_hwc_windows_get_video_available_properties failed");
+                  return;
+               }
+             INF(">>>>>>>> Available VIDEO props : count = %d", count);
+             for (i = 0; i < count; i++)
+               INF("   [%d] %s, %u", i, tprops[i].name, tprops[i].id);
+          }
+     }
+   INF("HWC: =========================================================================");
+}
+
+EINTERN void
+e_display_debug_info_get(Eldbus_Message_Iter *iter)
+{
+   Eldbus_Message_Iter *line_array;
+   E_Output *output = NULL;
+   E_Hwc *hwc = NULL;
+   Eina_List *l;
+   char info_str[1024];
+
+   eldbus_message_iter_arguments_append(iter, "as", &line_array);
+
+   eldbus_message_iter_basic_append(line_array, 's',
+   "===========================================================================================");
+   eldbus_message_iter_basic_append(line_array, 's',
+   " idx      id           status       dpms     (   x  ,   y  ) ( w    x    h ) ");
+   eldbus_message_iter_basic_append(line_array, 's',
+   "===========================================================================================");
+
+
+#ifdef E_DISPLAY
+   EINA_LIST_FOREACH(e_display_outputs_get(), l, output)
+#else
+   E_Comp_Screen *e_comp_screen = NULL;
+   e_comp_screen = e_comp->e_comp_screen;
+   EINA_LIST_FOREACH(e_comp_screen->outputs, l, output)
+#endif
+     {
+        if (!output) continue;
+        hwc = output->hwc;
+        if (!output->hwc) continue;
+        if (e_hwc_policy_get(hwc) == E_HWC_POLICY_NONE) continue;
+
+        snprintf(info_str, sizeof(info_str), "%2d %12s %15s %10s   (%5d , %5d) (%5d x %5d)",
+                 output->index, output->id,
+                 output->info.connected ? "connected" : "disconnected",
+                 _e_display_dpms_to_string(output->dpms),
+                 output->config.geom.x, output->config.geom.y,
+                 output->config.geom.w, output->config.geom.h);
+
+        eldbus_message_iter_basic_append(line_array, 's', info_str);
+     }
+
+   eldbus_message_iter_basic_append(line_array, 's',
+   "===========================================================================================");
+
+   eldbus_message_iter_container_close(iter, line_array);
+}
diff --git a/src/bin/displaymgr/e_display_intern.h b/src/bin/displaymgr/e_display_intern.h
new file mode 100644 (file)
index 0000000..4245322
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef E_DISPLAY_INTERN_H
+#define E_DISPLAY_INTERN_H
+
+#include "e_intern.h"
+#include "e_output_intern.h"
+
+#include <Eldbus.h>
+
+EINTERN Eina_Bool e_display_init(void);
+EINTERN void      e_display_shutdown(void);
+
+EINTERN E_Output  *e_display_primary_output_get(void);
+EINTERN void      *e_display_tdm_display_get(void);
+EINTERN void      *e_display_gbm_device_get(void);
+EINTERN Eina_List *e_display_outputs_get(void);
+EINTERN int        e_display_num_outputs_get(void);
+
+EINTERN Eina_Bool  e_display_available_video_formats_get(const tbm_format **formats, int *count);
+
+EINTERN Eina_Bool  e_display_pp_support(void);
+EINTERN Eina_List *e_display_pp_available_formats_get(void);
+EINTERN void       e_display_pp_available_size_get(int *minw, int *minh, int *maxw, int *maxh, int *align);
+
+EINTERN void      e_display_hwc_info_debug(void);
+EINTERN void      e_display_debug_info_get(Eldbus_Message_Iter *iter);
+
+#endif