ecore-evas-drm: Add initial code to make ecore_evas render using drm
authorChris Michael <cp.michael@samsung.com>
Mon, 10 Mar 2014 10:02:31 +0000 (10:02 +0000)
committerChris Michael <cp.michael@samsung.com>
Mon, 10 Mar 2014 12:40:31 +0000 (12:40 +0000)
NB: This is still a work-in-progress and not complete yet

Signed-off-by: Chris Michael <cp.michael@samsung.com>
src/modules/ecore_evas/engines/drm/ecore_evas_drm.c

index 4cf2370..78dc495 100644 (file)
 #include "ecore_evas_private.h"
 #include "ecore_evas_drm.h"
 
-#ifdef BUILD_ECORE_EVAS_DRM
+//#ifdef BUILD_ECORE_EVAS_DRM
 # include <Evas_Engine_Drm.h>
 # include <Ecore_Drm.h>
-#endif
+//#endif
 
 /* local structures */
 typedef struct _Ecore_Evas_Engine_Data_Drm Ecore_Evas_Engine_Data_Drm;
@@ -32,17 +32,27 @@ static int _ecore_evas_drm_init(void);
 static int _ecore_evas_drm_shutdown(void);
 static Ecore_Evas_Interface_Drm *_ecore_evas_drm_interface_new(void);
 
+static void _ecore_evas_drm_free(Ecore_Evas *ee);
+static void _ecore_evas_drm_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+static void _ecore_evas_drm_resize(Ecore_Evas *ee, int w, int h);
+static void _ecore_evas_drm_show(Ecore_Evas *ee);
+static void _ecore_evas_drm_hide(Ecore_Evas *ee);
+static int _ecore_evas_drm_render(Ecore_Evas *ee);
+static void _ecore_evas_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event);
+static int _ecore_evas_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates);
+
 /* local variables */
 static int _ecore_evas_init_count = 0;
+static Ecore_Drm_Device *dev = NULL;
 
 static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func = 
 {
-   NULL, //void (*fn_free) (Ecore_Evas *ee);
+   _ecore_evas_drm_free,
    NULL, //void (*fn_callback_resize_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
    NULL, //void (*fn_callback_move_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
    NULL, //void (*fn_callback_show_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
    NULL, //void (*fn_callback_hide_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
-   NULL, //void (*fn_callback_delete_request_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
+   _ecore_evas_drm_delete_request_set,
    NULL, //void (*fn_callback_destroy_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
    NULL, //void (*fn_callback_focus_in_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
    NULL, //void (*fn_callback_focus_out_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
@@ -54,12 +64,12 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
    NULL, //void (*fn_callback_post_render_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func);
    NULL, //void (*fn_move) (Ecore_Evas *ee, int x, int y);
    NULL, //void (*fn_managed_move) (Ecore_Evas *ee, int x, int y);
-   NULL, //void (*fn_resize) (Ecore_Evas *ee, int w, int h);
+   _ecore_evas_drm_resize,
    NULL, //void (*fn_move_resize) (Ecore_Evas *ee, int x, int y, int w, int h);
    NULL, //void (*fn_rotation_set) (Ecore_Evas *ee, int rot, int resize);
    NULL, //void (*fn_shaped_set) (Ecore_Evas *ee, int shaped);
-   NULL, //void (*fn_show) (Ecore_Evas *ee);
-   NULL, //void (*fn_hide) (Ecore_Evas *ee);
+   _ecore_evas_drm_show,
+   _ecore_evas_drm_hide,
    NULL, //void (*fn_raise) (Ecore_Evas *ee);
    NULL, //void (*fn_lower) (Ecore_Evas *ee);
    NULL, //void (*fn_activate) (Ecore_Evas *ee);
@@ -93,7 +103,8 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func =
    NULL, //void (*fn_demands_attention_set) (Ecore_Evas *ee, Eina_Bool on);
    NULL, //void (*fn_focus_skip_set) (Ecore_Evas *ee, Eina_Bool on);
    
-   NULL, //int (*fn_render) (Ecore_Evas *ee);
+   _ecore_evas_drm_render,
+
    NULL, //void (*fn_screen_geometry_get) (const Ecore_Evas *ee, int *x, int *y, int *w, int *h);
    NULL, //void (*fn_screen_dpi_get) (const Ecore_Evas *ee, int *xdpi, int *ydpi);
    NULL, //void (*fn_msg_parent_send) (Ecore_Evas *ee, int maj, int min, void *data, int size);
@@ -114,6 +125,8 @@ EAPI Ecore_Evas *
 ecore_evas_drm_new_internal(const char *device, unsigned int parent, int x, int y, int w, int h)
 {
    Ecore_Evas *ee;
+   Evas_Engine_Info_Drm *einfo;
+   Ecore_Evas_Interface_Drm *iface;
    int method;
 
    /* try to find the evas drm engine */
@@ -123,41 +136,329 @@ ecore_evas_drm_new_internal(const char *device, unsigned int parent, int x, int
         return NULL;
      }
 
+   /* try to init drm */
+   if (_ecore_evas_drm_init() < 1) return NULL;
+
    /* try to allocate space for new ecore_evas */
    if (!(ee = calloc(1, sizeof(Ecore_Evas))))
      {
         ERR("Failed to allocate space for new Ecore_Evas");
-        return NULL;
+        goto ee_err;
      }
 
    ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
 
-   /* try to init drm */
+   ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_evas_drm_engine_func;
+
+   iface = _ecore_evas_drm_interface_new();
+   ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
+
+   /* set some engine properties */
+   ee->driver = "drm";
+   if (device) ee->name = strdup(device);
+
+   if (w < 1) w = 1;
+   if (h < 1) h = 1;
+
+   ee->x = ee->req.x = x;
+   ee->y = ee->req.y = y;
+   ee->w = ee->req.w = w;
+   ee->h = ee->req.h = h;
+
+   ee->prop.max.w = 32767;
+   ee->prop.max.h = 32767;
+   ee->prop.layer = 4;
+   ee->prop.request_pos = 0;
+   ee->prop.sticky = 0;
+   ee->alpha = EINA_FALSE;
+
+   ee->can_async_render = 1;
+   if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER"))
+     ee->can_async_render = 0;
+
+   /* try to initialize evas */
+   ee->evas = evas_new();
+   evas_data_attach_set(ee->evas, ee);
+   evas_output_method_set(ee->evas, method);
+
+   /* FIXME: Support initial rotation ?? */
+   evas_output_size_set(ee->evas, w, h);
+   evas_output_viewport_set(ee->evas, 0, 0, w, h);
+
+   if (ee->can_async_render)
+     evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST, 
+                             _ecore_evas_drm_render_updates, ee);
+
+   if ((einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas)))
+     {
+        einfo->info.depth = 32; // FIXME
+        einfo->info.destination_alpha = ee->alpha;
+        einfo->info.rotation = ee->rotation;
+        einfo->info.vsync = EINA_FALSE;
+        einfo->info.use_hw_accel = EINA_FALSE;
+        einfo->info.fd = ecore_drm_device_fd_get(dev);
+        einfo->info.tty = ecore_drm_tty_get(dev);
+
+        if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
+          {
+             ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
+             goto eng_err;
+          }
+     }
+   else
+     {
+        ERR("Failed to get Evas Engine Info for '%s'", ee->driver);
+        goto eng_err;
+     }
+
+   _ecore_evas_register(ee);
+   ecore_evas_input_event_register(ee);
 
    return ee;
+
+eng_err:
+   ecore_evas_free(ee);
+ee_err:
+   _ecore_evas_drm_shutdown();
+   return NULL;
 }
 
 /* local functions */
 static int 
 _ecore_evas_drm_init(void)
 {
-   _ecore_evas_init_count++;
-   if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
+   if (++_ecore_evas_init_count != 1) return _ecore_evas_init_count;
+
+   /* try to init ecore_drm */
+   if (!ecore_drm_init())
+     {
+        ERR("Could not initialize Ecore_Drm");
+        return --_ecore_evas_init_count;
+     }
+
+   /* try to find the device */
+   if (!(dev = ecore_drm_device_find(NULL, NULL)))
+     {
+        ERR("Could not find default drm device");
+        goto dev_err;
+     }
+
+   /* try to open the graphics card */
+   if (!ecore_drm_device_open(dev))
+     {
+        ERR("Could not open drm device");
+        goto dev_open_err;
+     }
+
+   /* try to open the tty */
+   if (!ecore_drm_tty_open(dev, NULL))
+     {
+        ERR("Could not open tty: %m");
+        goto tty_open_err;
+     }
+
+   /* FIXME: Init egl/software renderer here ?? */
+
+   /* try to create sprites */
+   if (!ecore_drm_sprites_create(dev))
+     {
+        ERR("Could not create sprites: %m");
+        goto sprite_err;
+     }
+
+   /* try to create outputs */
+   if (!ecore_drm_outputs_create(dev))
+     {
+        ERR("Could not create outputs: %m");
+        goto output_err;
+     }
+
+   /* try to create inputs */
+   if (!ecore_drm_inputs_create(dev))
+     {
+        ERR("Could not create inputs: %m");
+        goto output_err;
+     }
 
    ecore_event_evas_init();
 
    return _ecore_evas_init_count;
+
+output_err:
+   ecore_drm_sprites_destroy(dev);
+sprite_err:
+   ecore_drm_tty_close(dev);
+tty_open_err:
+   ecore_drm_device_close(dev);
+dev_open_err:
+   ecore_drm_device_free(dev);
+dev_err:
+   ecore_drm_shutdown();
+   return --_ecore_evas_init_count;
 }
 
 static int 
 _ecore_evas_drm_shutdown(void)
 {
-   _ecore_evas_init_count--;
-   if (_ecore_evas_init_count == 0)
+   if (--_ecore_evas_init_count != 0) return _ecore_evas_init_count;
+
+   ecore_drm_sprites_destroy(dev);
+   /* NB: No need to free outputs here. Is done in device free */
+   ecore_drm_inputs_destroy(dev);
+   ecore_drm_tty_close(dev);
+   ecore_drm_device_close(dev);
+   ecore_drm_device_free(dev);
+   ecore_drm_shutdown();
+
+   ecore_event_evas_shutdown();
+
+   return _ecore_evas_init_count;
+}
+
+static Ecore_Evas_Interface_Drm *
+_ecore_evas_drm_interface_new(void)
+{
+   Ecore_Evas_Interface_Drm *iface;
+
+   if (!(iface = calloc(1, sizeof(Ecore_Evas_Interface_Drm))))
+     return NULL;
+
+   iface->base.name = "drm";
+   iface->base.version = 1;
+
+   /* iface->pixmap_visual_get; */
+   /* iface->pixmap_colormap_get; */
+   /* iface->pixmap_depth_get; */
+
+   return iface;
+}
+
+/* local ecore_evas functions */
+static void 
+_ecore_evas_drm_free(Ecore_Evas *ee)
+{
+   ecore_evas_input_event_unregister(ee);
+   _ecore_evas_drm_shutdown();
+}
+
+static void 
+_ecore_evas_drm_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
+{
+   ee->func.fn_delete_request = func;
+}
+
+static void 
+_ecore_evas_drm_resize(Ecore_Evas *ee, int w, int h)
+{
+   ee->req.w = w;
+   ee->req.h = h;
+   if ((ee->w == w) && (ee->h == h)) return;
+   ee->w = w;
+   ee->h = h;
+   evas_output_size_set(ee->evas, w, h);
+   evas_output_viewport_set(ee->evas, 0, 0, w, h);
+   if (ee->func.fn_resize) ee->func.fn_resize(ee);
+}
+
+static void 
+_ecore_evas_drm_show(Ecore_Evas *ee)
+{
+   if ((!ee) || (ee->visible)) return;
+   evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
+   ee->visible = 1;
+   if (ee->func.fn_show) ee->func.fn_show(ee);
+}
+
+static void 
+_ecore_evas_drm_hide(Ecore_Evas *ee)
+{
+   if ((!ee) || (!ee->visible)) return;
+   evas_sync(ee->evas);
+   ee->visible = 0;
+   ee->should_be_visible = 0;
+   if (ee->func.fn_hide) ee->func.fn_hide(ee);
+}
+
+static int 
+_ecore_evas_drm_render(Ecore_Evas *ee)
+{
+   int rend = 0;
+   Eina_List *l;
+   Ecore_Evas *ee2;
+
+   if (ee->in_async_render) return 0;
+
+   if (!ee->visible)
      {
-        ecore_event_evas_shutdown();
+        evas_norender(ee->evas);
+        return 0;
      }
 
-   if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
-   return _ecore_evas_init_count;
+   EINA_LIST_FOREACH(ee->sub_ecore_evas, l, ee2)
+     {
+        if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2);
+        if (ee2->engine.func->fn_render)
+          rend |= ee2->engine.func->fn_render(ee2);
+        if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2);
+     }
+
+   if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
+
+   if (!ee->can_async_render)
+     {
+        Eina_List *updates;
+
+        updates = evas_render_updates(ee->evas);
+        rend = _ecore_evas_drm_render_updates_process(ee, updates);
+        evas_render_updates_free(updates);
+     }
+   else if (evas_render_async(ee->evas))
+     {
+        ee->in_async_render = EINA_TRUE;
+        rend = 1;
+     }
+
+   return rend;
+}
+
+static void 
+_ecore_evas_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event)
+{
+   Evas_Event_Render_Post *ev;
+   Ecore_Evas *ee;
+
+   if (!(ev = event)) return;
+   if (!(ee = data)) return;
+
+   ee->in_async_render = EINA_FALSE;
+
+   _ecore_evas_drm_render_updates_process(ee, ev->updated_area);
+
+   /* TODO: handle delayed changes */
+}
+
+static int 
+_ecore_evas_drm_render_updates_process(Ecore_Evas *ee, Eina_List *updates)
+{
+   int rend = 0;
+
+   if ((ee->visible) && (updates))
+     {
+        Eina_List *l = NULL;
+        Eina_Rectangle *r;
+
+        EINA_LIST_FOREACH(updates, l, r)
+          {
+             /* TODO */
+          }
+
+        _ecore_evas_idle_timeout_update(ee);
+        rend = 1;
+     }
+   else
+     evas_norender(ee->evas);
+
+   if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
+
+   return rend;
 }