diff options
author | Chris Michael <cp.michael@samsung.com> | 2017-11-02 12:34:27 -0400 |
---|---|---|
committer | Christopher Michael <cp.michael@samsung.com> | 2019-02-25 13:19:16 -0500 |
commit | b45b621330001e43a765ceb89f86cf9f0f4d280f (patch) | |
tree | d55c7caebaf687fb309ab7175b4bf22d1ea13359 | |
parent | 46aae64b3404d2cb24ee2d7735804d5a2c145a22 (diff) | |
download | efl-devs/devilhorns/multi-output.tar.gz |
ecore-evas-drm: Refactor ecore-evas drm engine to work with multiple outputsdevs/devilhorns/multi-output
This patch refactors the Ecore_Evas drm engine code to support
multiple outputs in software mode. This does NOT include support
for gl-drm yet...
@feature
Signed-off-by: Chris Michael <cp.michael@samsung.com>
-rw-r--r-- | src/modules/ecore_evas/engines/drm/ecore_evas_drm.c | 1138 |
1 files changed, 516 insertions, 622 deletions
diff --git a/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c b/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c index 5668b416d1..19a89c8183 100644 --- a/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c +++ b/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c @@ -20,7 +20,7 @@ #include "elput_private.h" #ifdef BUILD_ECORE_EVAS_GL_DRM -# include <Evas_Engine_GL_Drm.h> +/* # include <Evas_Engine_GL_Drm.h> */ # include <dlfcn.h> #endif @@ -46,346 +46,126 @@ # endif #endif /* ! _WIN32 */ +typedef struct _Ecore_Evas_Engine_Drm_Tick +{ + Ecore_Drm2_Output *output; + Efl_Canvas_Output *canvas; + double offset, timestamp; +} Ecore_Evas_Engine_Drm_Tick; + typedef struct _Ecore_Evas_Engine_Drm_Data { - int cw, ch; - int clockid; - int x, y, w, h; - int depth, bpp; - unsigned int format; - double offset; - double tick_job_timestamp; + Ecore_Drm2_Device *dev; Ecore_Drm2_Context ctx; + Ecore_Fd_Handler *hdlr; - Ecore_Drm2_Device *dev; - Ecore_Drm2_Output *output; + Evas_Device *seat; + + Ecore_Job *tick_job; + + Eina_List *ticks; + Eina_Bool ticking : 1; Eina_Bool once : 1; - Ecore_Job *tick_job; - Ecore_Job *focus_job; } Ecore_Evas_Engine_Drm_Data; +static int _drm_shutdown(Ecore_Evas_Engine_Drm_Data *edata); + static int _drm_init_count = 0; -static Eina_List *handlers; -static Eina_List *canvases; +static Eina_List *canvases, *outputs; +static Ecore_Event_Handler *devhdlr; -static Eina_Bool -_drm_device_change(void *d EINA_UNUSED, int t EINA_UNUSED, void *event) +static void +_cb_tick(void *data) { - Elput_Event_Device_Change *ev = event; - const Eina_List *l; Ecore_Evas *ee; Ecore_Evas_Engine_Drm_Data *edata; - Elput_Seat *seat; - Elput_Manager *manager; - Eina_Bool found = EINA_FALSE; - Elput_Device_Caps caps; - Evas_Device_Class devclass = EVAS_DEVICE_CLASS_NONE; - Eo *dev; - - seat = elput_device_seat_get(ev->device); - manager = elput_seat_manager_get(seat); - caps = elput_device_caps_get(ev->device); - - EINA_LIST_FOREACH(canvases, l, ee) - { - edata = ee->engine.data; - found = edata->dev->em == manager; - if (found) break; - } - - if (!found) return ECORE_CALLBACK_RENEW; - if (caps & ELPUT_DEVICE_CAPS_TABLET_TOOL) - devclass = EVAS_DEVICE_CLASS_PEN; // idk how "pen" is a device class? - else if (caps & ELPUT_DEVICE_CAPS_POINTER) - devclass = EVAS_DEVICE_CLASS_MOUSE; - else if (caps & ELPUT_DEVICE_CAPS_TOUCH) - devclass = EVAS_DEVICE_CLASS_TOUCH; - else if (caps & ELPUT_DEVICE_CAPS_KEYBOARD) - devclass = EVAS_DEVICE_CLASS_KEYBOARD; - switch (ev->type) - { - case ELPUT_DEVICE_ADDED: - { - if (!edata->seat) - { - Eina_Stringshare *name = elput_seat_name_get(seat); - edata->seat = evas_device_add_full(ee->evas, name, - "drm seat", NULL, NULL, EVAS_DEVICE_CLASS_SEAT, EVAS_DEVICE_SUBCLASS_NONE); - evas_device_seat_id_set(edata->seat, strtol(name, NULL, 10)); - } - - dev = evas_device_add_full(ee->evas, elput_device_output_name_get(ev->device), - "drm device", edata->seat, NULL, devclass, EVAS_DEVICE_SUBCLASS_NONE); - ev->device->evas_device = dev; - break; - } - case ELPUT_DEVICE_REMOVED: - { - EINA_LIST_FOREACH(evas_device_list(ee->evas, edata->seat), l, dev) - { - if (dev != ev->device->evas_device) continue; - evas_device_del(dev); - ev->device->evas_device = NULL; - break; - } - break; - } - } - - return ECORE_CALLBACK_RENEW; -} - -static int -_ecore_evas_drm_init(Ecore_Evas *ee, Ecore_Evas_Engine_Drm_Data *edata, const char *device) -{ - if (++_drm_init_count != 1) return _drm_init_count; + Ecore_Evas_Engine_Drm_Tick *etick; + Eina_List *l; - if (!ecore_drm2_init()) - { - ERR("Failed to init Ecore_Drm2 library"); - goto init_err; - } - - /* NB: No seat name passed in, try to get from env */ - if (!device) device = getenv("XDG_SEAT"); - - /* NB: fallback to seat0 if env var is not set */ - if (!device) device = "seat0"; - - edata->dev = ecore_drm2_device_open(device, 0); - if (!edata->dev) - { - ERR("Failed to open device"); - goto open_err; - } - - edata->clockid = ecore_drm2_device_clock_id_get(edata->dev); - ecore_drm2_device_cursor_size_get(edata->dev, &edata->cw, &edata->ch); + ee = data; + edata = ee->engine.data; + edata->tick_job = NULL; - if (!ecore_drm2_outputs_create(edata->dev)) + EINA_LIST_FOREACH(edata->ticks, l, etick) { - ERR("Could not create outputs"); - goto output_err; - } - - edata->output = ecore_drm2_output_find(edata->dev, edata->x, edata->y); - if (edata->output) ecore_drm2_output_user_data_set(edata->output, ee); - else WRN("Could not find output at %d %d", edata->x, edata->y); + Eina_Rectangle rect; + int ox, oy, ow, oh; - ecore_event_evas_init(); - if (!handlers) - { - handlers = - eina_list_append(handlers, - ecore_event_handler_add(ELPUT_EVENT_DEVICE_CHANGE, - _drm_device_change, NULL)); + ecore_drm2_output_info_get(etick->output, &ox, &oy, &ow, &oh, NULL); + EINA_RECTANGLE_SET(&rect, ox, oy, ow, oh); + /* efl_canvas_output_unlock(etick->canvas); */ + ecore_evas_animator_tick(ee, &rect, etick->timestamp); } - - return _drm_init_count; - -output_err: - ecore_drm2_device_close(edata->dev); -open_err: - ecore_drm2_shutdown(); -init_err: - return --_drm_init_count; } -static int -_ecore_evas_drm_shutdown(Ecore_Evas_Engine_Drm_Data *edata) +static inline Ecore_Evas_Engine_Drm_Tick * +_drm_tick_get(Ecore_Evas_Engine_Drm_Data *edata, Ecore_Drm2_Output *output) { - Ecore_Event_Handler *h; - if (--_drm_init_count != 0) return _drm_init_count; + Ecore_Evas_Engine_Drm_Tick *etick; + Eina_List *l; - if (edata->focus_job) - { - ecore_job_del(edata->focus_job); - edata->focus_job = NULL; - } - ecore_drm2_outputs_destroy(edata->dev); - ecore_drm2_device_close(edata->dev); - ecore_drm2_shutdown(); - ecore_event_evas_shutdown(); - EINA_LIST_FREE(handlers, h) - ecore_event_handler_del(h); + EINA_LIST_FOREACH(edata->ticks, l, etick) + if (etick->output == output) return etick; - return _drm_init_count; + return NULL; } static void _drm_free(Ecore_Evas *ee) { Ecore_Evas_Engine_Drm_Data *edata; - - ecore_evas_input_event_unregister(ee); - - edata = ee->engine.data; - canvases = eina_list_remove(canvases, ee); - _ecore_evas_drm_shutdown(edata); - free(edata); -} - -static void -_drm_rotation_do(Ecore_Evas *ee, int rotation, int resize) -{ - Evas_Engine_Info_Drm *einfo; - Ecore_Evas_Engine_Drm_Data *edata; - Eina_Bool use_hw = EINA_FALSE; - int diff, rotations = 0, orient = 0; - - if (ee->rotation == rotation) return; - - einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas); - if (!einfo) return; + Ecore_Evas_Engine_Drm_Tick *etick; edata = ee->engine.data; - rotations = ecore_drm2_output_supported_rotations_get(edata->output); - if (rotations >= 0) - { - if (rotations & ECORE_DRM2_ROTATION_NORMAL) - { - if (rotation == 0) - { - use_hw = EINA_TRUE; - orient = ECORE_DRM2_ROTATION_NORMAL; - } - } - - if (rotations & ECORE_DRM2_ROTATION_90) - { - if (rotation == 90) - { - use_hw = EINA_TRUE; - orient = ECORE_DRM2_ROTATION_90; - } - } - - if (rotations & ECORE_DRM2_ROTATION_180) - { - if (rotation == 180) - { - use_hw = EINA_TRUE; - orient = ECORE_DRM2_ROTATION_180; - } - } - - if (rotations & ECORE_DRM2_ROTATION_270) - { - if (rotation == 270) - { - use_hw = EINA_TRUE; - orient = ECORE_DRM2_ROTATION_270; - } - } - } - - if (use_hw) - { - ecore_drm2_output_rotation_set(edata->output, orient); - ee->rotation = rotation; - return; - } - - einfo->info.rotation = rotation; - if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) - ERR("evas_engine_info_set() for engine '%s' failed", ee->driver); - - diff = ee->rotation - rotation; - if (diff < 0) diff = -diff; + EINA_LIST_FREE(edata->ticks, etick) + free(etick); - if (diff != 180) - { - if (!resize) - { - int ww, hh; - - if (ECORE_EVAS_PORTRAIT(ee)) - evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); - else - evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.h, ee->req.w); - - ww = ee->h; - hh = ee->w; - ee->w = ww; - ee->h = hh; - ee->req.w = ww; - ee->req.h = hh; - } - else - { - if ((rotation == 0) || (rotation == 180)) - { - evas_output_size_set(ee->evas, ee->w, ee->h); - evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); - } - else - { - evas_output_size_set(ee->evas, ee->h, ee->w); - evas_output_viewport_set(ee->evas, 0, 0, ee->h, ee->w); - } - } - } - - ee->rotation = rotation; - - if (ee->func.fn_resize) ee->func.fn_resize(ee); + ecore_job_del(edata->tick_job); + ecore_evas_input_event_unregister(ee); - if (ECORE_EVAS_PORTRAIT(ee)) - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - else - evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); -} + ecore_main_fd_handler_del(edata->hdlr); + edata->hdlr = NULL; -static void -_drm_render_updates(void *data, Evas *evas EINA_UNUSED, void *event EINA_UNUSED) -{ - Ecore_Evas *ee = data; + canvases = eina_list_remove(canvases, ee); - if (ee->delayed.rotation_changed) - { - _drm_rotation_do(ee, ee->delayed.rotation, ee->delayed.rotation_resize); - ee->delayed.rotation_changed = EINA_FALSE; - } + _drm_shutdown(edata); + free(edata); } static void -_drm_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h) +_drm_move(Ecore_Evas *ee, int x, int y) { - Ecore_Evas_Engine_Drm_Data *edata; - - edata = ee->engine.data; - ecore_drm2_output_info_get(edata->output, x, y, w, h, NULL); + ee->req.x = x; + ee->req.y = y; + if ((ee->x == x) && (ee->y == y)) return; + ee->x = x; + ee->y = y; + if (ee->func.fn_move) ee->func.fn_move(ee); } static void -_drm_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) +_drm_resize(Ecore_Evas *ee, int w, int h) { - Ecore_Evas_Engine_Drm_Data *edata; - - edata = ee->engine.data; - ecore_drm2_output_dpi_get(edata->output, xdpi, ydpi); + 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 -_drm_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) -{ - Ecore_Evas_Engine_Drm_Data *edata; - - edata = ee->engine.data; - ecore_drm2_device_pointer_xy_get(edata->dev, x, y); -} - -static Eina_Bool -_drm_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) +_drm_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) { - Ecore_Evas_Engine_Drm_Data *edata; - - edata = ee->engine.data; - ecore_drm2_device_pointer_warp(edata->dev, x, y); - return EINA_TRUE; + if ((ee->x != x) || (ee->y != y)) + _drm_move(ee, x, y); + if ((ee->w != w) || (ee->h != h)) + _drm_resize(ee, w, h); } static void @@ -402,10 +182,15 @@ _drm_show_focus_job(void *data) static void _drm_show(Ecore_Evas *ee) { + /* Ecore_Drm2_Output *output; */ + Ecore_Evas_Engine_Drm_Tick *etick; Ecore_Evas_Engine_Drm_Data *edata; + Eina_List *l; if ((!ee) || (ee->visible)) return; + edata = ee->engine.data; + ee->should_be_visible = 1; if (ee->prop.avoid_damage) @@ -420,19 +205,28 @@ _drm_show(Ecore_Evas *ee) if (ee->func.fn_state_change) ee->func.fn_state_change(ee); } - if (ee->visible) return; - ee->visible = 1; + if (ee->prop.fullscreen) + { + evas_focus_in(ee->evas); + if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); + } + if (ee->func.fn_show) ee->func.fn_show(ee); - edata = ee->engine.data; - edata->focus_job = ecore_job_add(_drm_show_focus_job, ee); /* HACK: sometimes we still have an animator ticking when we vc switch * so for now we just fire off a flip here to kick it when we come back. * This is just papering over a bug for now until I have time to track * it down properly. :( */ - ecore_drm2_fb_flip(NULL, edata->output); + /* EINA_LIST_FOREACH(outputs, l, output) */ + /* ecore_drm2_fb_flip(NULL, output); */ + + EINA_LIST_FOREACH(edata->ticks, l, etick) + { + /* efl_canvas_output_lock(etick->canvas); */ + ecore_drm2_fb_flip(NULL, etick->output); + } } static void @@ -455,54 +249,6 @@ _drm_hide(Ecore_Evas *ee) } static void -_drm_move(Ecore_Evas *ee, int x, int y) -{ - ee->req.x = x; - ee->req.y = y; - if ((ee->x == x) && (ee->y == y)) return; - ee->x = x; - ee->y = y; - if (ee->func.fn_move) ee->func.fn_move(ee); -} - -static void -_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 -_drm_move_resize(Ecore_Evas *ee, int x, int y, int w, int h) -{ - if ((ee->x != x) || (ee->y != y)) - _drm_move(ee, x, y); - if ((ee->w != w) || (ee->h != h)) - _drm_resize(ee, w, h); -} - -static void -_drm_rotation_set(Ecore_Evas *ee, int rotation, int resize) -{ - if (ee->rotation == rotation) return; - - if (ee->in_async_render) - { - ee->delayed.rotation = rotation; - ee->delayed.rotation_resize = resize; - ee->delayed.rotation_changed = EINA_TRUE; - } - else - _drm_rotation_do(ee, rotation, resize); -} - -static void _drm_title_set(Ecore_Evas *ee, const char *title) { if (eina_streq(ee->prop.title, title)) return; @@ -592,53 +338,6 @@ _drm_maximized_set(Ecore_Evas *ee, Eina_Bool on) } static void -_drm_fullscreen_set(Ecore_Evas *ee, Eina_Bool on) -{ - Eina_Bool resized = EINA_FALSE; - Ecore_Evas_Engine_Drm_Data *edata; - - edata = ee->engine.data; - if (ee->prop.fullscreen == on) return; - ee->prop.fullscreen = on; - - if (on) - { - int ow = 0, oh = 0; - - edata->w = ee->w; - edata->h = ee->h; - - ecore_drm2_output_info_get(edata->output, NULL, NULL, &ow, &oh, NULL); - if ((ow == 0) || (oh == 0)) - { - ow = ee->w; - oh = ee->h; - } - if ((ow != ee->w) || (oh != ee->h)) resized = EINA_TRUE; - ee->w = ow; - ee->h = oh; - } - else - { - if ((edata->w != ee->w) || (edata->h != ee->h)) resized = EINA_TRUE; - ee->w = edata->w; - ee->h = edata->h; - } - - ee->req.w = ee->w; - ee->req.h = ee->h; - ee->prop.fullscreen = on; - evas_output_size_set(ee->evas, ee->w, ee->h); - evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - - if (resized) - { - if (ee->func.fn_resize) ee->func.fn_resize(ee); - } -} - -static void _drm_withdrawn_set(Ecore_Evas *ee, Eina_Bool on) { if (ee->prop.withdrawn == on) return; @@ -681,161 +380,135 @@ _drm_aspect_set(Ecore_Evas *ee, double aspect) ee->prop.aspect = aspect; } -static Ecore_Evas_Interface_Drm * -_ecore_evas_drm_interface_new(void) +static void +_drm_screen_geometry_get(const Ecore_Evas *ee EINA_UNUSED, int *x, int *y, int *w, int *h) { - Ecore_Evas_Interface_Drm *iface; - - iface = calloc(1, sizeof(Ecore_Evas_Interface_Drm)); - if (!iface) return NULL; - - iface->base.name = "drm"; - iface->base.version = 1; - - return iface; -} + Ecore_Drm2_Output *output; + Eina_List *l; + int ox, oy, ow, oh; -static Eina_Bool -_cb_drm_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED) -{ - Ecore_Evas *ee; - Ecore_Evas_Engine_Drm_Data *edata; - int ret; + if (x) *x = 0; + if (y) *y = 0; - ee = data; - edata = ee->engine.data; - ret = ecore_drm2_event_handle(edata->dev, &edata->ctx); - if (ret) + EINA_LIST_FOREACH(outputs, l, output) { - WRN("drmHandleEvent failed to read an event"); - return EINA_FALSE; + ecore_drm2_output_info_get(output, &ox, &oy, &ow, &oh, NULL); + if (w) *w += MAX(*w, ow); + if (h) *h = MAX(*h, oh); } - - return EINA_TRUE; } static void -_cb_pageflip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec, unsigned int usec, void *data) +_drm_screen_dpi_get(const Ecore_Evas *ee EINA_UNUSED, int *xdpi, int *ydpi) { - Ecore_Evas *ee; Ecore_Drm2_Output *output; - Ecore_Evas_Engine_Drm_Data *edata; - int ret; - - output = data; - - ee = ecore_drm2_output_user_data_get(output); - if (!ee) return; - - edata = ee->engine.data; - ret = ecore_drm2_fb_flip_complete(output); + if (xdpi) *xdpi = 0; + if (ydpi) *ydpi = 0; - if (edata->ticking) - { - int x, y, w, h; - double t = (double)sec + ((double)usec / 1000000); + output = eina_list_data_get(outputs); + if (!output) return; - ecore_drm2_output_info_get(output, &x, &y, &w, &h, NULL); - - if (!edata->once) t = ecore_time_get(); - ecore_evas_animator_tick(ee, &(Eina_Rectangle){x, y, w, h}, - t - edata->offset); - } - else if (ret) - ecore_drm2_fb_flip(NULL, output); + ecore_drm2_output_dpi_get(output, xdpi, ydpi); } static void -_drm_evas_changed(Ecore_Evas *ee, Eina_Bool changed) +_drm_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { Ecore_Evas_Engine_Drm_Data *edata; - if (changed) return; - edata = ee->engine.data; - if (edata->ticking && !ecore_drm2_output_pending_get(edata->output)) - ecore_drm2_fb_flip(NULL, edata->output); + ecore_drm2_device_pointer_xy_get(edata->dev, x, y); } -static void -_tick_job(void *data) +static Eina_Bool +_drm_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { Ecore_Evas_Engine_Drm_Data *edata; - Ecore_Evas *ee; - int x, y, w, h; - ee = data; edata = ee->engine.data; - edata->tick_job = NULL; - - ecore_drm2_output_info_get(edata->output, &x, &y, &w, &h, NULL); - - ecore_evas_animator_tick(ee, &(Eina_Rectangle){x, y, w, h}, - edata->tick_job_timestamp - edata->offset); + ecore_drm2_device_pointer_warp(edata->dev, x, y); + return EINA_TRUE; } static void _drm_animator_register(Ecore_Evas *ee) { - double t; - long sec, usec; Ecore_Evas_Engine_Drm_Data *edata; - Eina_Bool r; + Ecore_Evas_Engine_Drm_Tick *etick; + Ecore_Drm2_Output *output; + Eina_List *l; if (ee->manual_render) - ERR("Attempt to schedule tick for manually rendered canvas"); + { + ERR("Attempt to schedule tick for manually rendered canvas"); + /* return; */ + } edata = ee->engine.data; - /* Some graphics stacks appear to lie about their clock sources - * so attempt to measure the difference between our clock and the - * GPU's source of timestamps once at startup and apply that. - * If it's tiny, just assume they're the same clock and it's - * measurement error. - * - * <cedric> what happen when you suspend ? - * <cedric> what about drift ? - * - * If someone could relay the message to cedric that I'm not - * talking to him anymore, that would be helpful. - */ if (!edata->once) { - r = ecore_drm2_output_blanktime_get(edata->output, 1, &sec, &usec); - if (r) + EINA_LIST_FOREACH(outputs, l, output) { - t = (double)sec + ((double)usec / 1000000.0); - edata->offset = t - ecore_time_get(); - if (fabs(edata->offset) < 0.010) - edata->offset = 0.0; + Eina_Bool r = EINA_FALSE; + double t = 0.0; + long sec, usec; + + r = ecore_drm2_output_blanktime_get(output, 1, &sec, &usec); + if (!r) continue; + + etick = _drm_tick_get(edata, output); + if (!etick) continue; - edata->once = EINA_TRUE; + t = (double)sec + ((double)usec / 1000000.0); + etick->offset = t - ecore_time_get(); + if (fabs(etick->offset) < 0.010) + etick->offset = 0.0; } + edata->once = EINA_TRUE; } - if (ee->animator_ticked || ee->animator_ran) + if (edata->tick_job) { - edata->ticking = EINA_TRUE; + ERR("Double animator register"); return; } - if (edata->tick_job) ERR("Double animator register"); - else - if (!edata->ticking && - !(ecore_drm2_output_pending_get(edata->output) || ee->in_async_render)) + EINA_LIST_FOREACH(outputs, l, output) { - r = ecore_drm2_output_blanktime_get(edata->output, 0, &sec, &usec); - if (r) + Eina_Bool r = EINA_FALSE; + long sec, usec; + + if (!edata->ticking && + !(ecore_drm2_output_pending_get(output) || ee->in_async_render)) { - edata->tick_job_timestamp = (double)sec - + ((double)usec / 1000000); - edata->tick_job = ecore_job_add(_tick_job, ee); + r = ecore_drm2_output_blanktime_get(output, 0, &sec, &usec); + if (r) + { + etick = _drm_tick_get(edata, output); + if (!etick) continue; + + etick->timestamp = (double)sec + ((double)usec / 1000000.0); + } } else ecore_drm2_fb_flip(NULL, edata->output); } + if (!edata->ticking) + edata->tick_job = ecore_job_add(_cb_tick, ee); + + EINA_LIST_FOREACH(edata->ticks, l, etick) + { + if ((!ecore_drm2_output_pending_get(etick->output)) && + !ee->in_async_render) + { + /* efl_canvas_output_lock(etick->canvas); */ + ecore_drm2_fb_flip(NULL, etick->output); + } + } + edata->ticking = EINA_TRUE; } @@ -846,28 +519,59 @@ _drm_animator_unregister(Ecore_Evas *ee) edata = ee->engine.data; edata->ticking = EINA_FALSE; + if (edata->tick_job) { - ERR("Animator unregister before first tick"); ecore_job_del(edata->tick_job); edata->tick_job = NULL; } } -static double -_drm_last_tick_get(Ecore_Evas *ee) +static void +_drm_evas_changed(Ecore_Evas *ee, Eina_Bool changed) { Ecore_Evas_Engine_Drm_Data *edata; - long sec, usec; + Ecore_Evas_Engine_Drm_Tick *etick; + Eina_List *l; + + if (changed) return; edata = ee->engine.data; - if (!ecore_drm2_output_blanktime_get(edata->output, 0, &sec, &usec)) - return -1.0; + if (!edata->ticking) return; - return sec + usec / 1000000.0; + EINA_LIST_FOREACH(edata->ticks, l, etick) + { + if (!ecore_drm2_output_pending_get(etick->output)) + { + /* efl_canvas_output_lock(etick->canvas); */ + ecore_drm2_fb_flip(NULL, etick->output); + } + } } -static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func = +static double +_drm_last_tick_get(Ecore_Evas *ee EINA_UNUSED) +{ + Ecore_Drm2_Output *output; + Eina_List *l; + long sec, usec; + double tmp = 0.0; + + EINA_LIST_FOREACH(outputs, l, output) + { + if (!ecore_drm2_output_blanktime_get(output, 0, &sec, &usec)) + tmp = -1.0; + else + { + if ((sec + usec / 1000000.0) > tmp) + tmp = sec + usec / 1000000.0; + } + } + + return tmp; +} + +static Ecore_Evas_Engine_Func _drm_engine_func = { _drm_free, NULL, //void (*fn_callback_resize_set) (Ecore_Evas *ee, Ecore_Evas_Event_Cb func); @@ -888,7 +592,7 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func = NULL, //void (*fn_managed_move) (Ecore_Evas *ee, int x, int y); _drm_resize, _drm_move_resize, - _drm_rotation_set, + NULL, //_drm_rotation_set, NULL, //void (*fn_shaped_set) (Ecore_Evas *ee, int shaped); _drm_show, _drm_hide, @@ -909,7 +613,7 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func = _drm_borderless_set, NULL, //void (*fn_override_set) (Ecore_Evas *ee, Eina_Bool on); _drm_maximized_set, - _drm_fullscreen_set, + NULL, //_drm_fullscreen_set, NULL, //void (*fn_avoid_damage_set) (Ecore_Evas *ee, int on); _drm_withdrawn_set, NULL, //void (*fn_sticky_set) (Ecore_Evas *ee, Eina_Bool on); @@ -918,35 +622,27 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func = _drm_transparent_set, NULL, //void (*fn_profiles_set) (Ecore_Evas *ee, const char **profiles, int count); NULL, //void (*fn_profile_set) (Ecore_Evas *ee, const char *profile); - NULL, //void (*fn_window_group_set) (Ecore_Evas *ee, const Ecore_Evas *ee_group); _drm_aspect_set, NULL, //void (*fn_urgent_set) (Ecore_Evas *ee, Eina_Bool on); NULL, //void (*fn_modal_set) (Ecore_Evas *ee, Eina_Bool on); 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, - _drm_screen_geometry_get, _drm_screen_dpi_get, NULL, //void (*fn_msg_parent_send) (Ecore_Evas *ee, int maj, int min, void *data, int size); NULL, //void (*fn_msg_send) (Ecore_Evas *ee, int maj, int min, void *data, int size); - _drm_pointer_xy_get, _drm_pointer_warp, - NULL, // wm_rot_preferred_rotation_set NULL, // wm_rot_available_rotations_set NULL, // wm_rot_manual_rotation_done_set NULL, // wm_rot_manual_rotation_done - NULL, // aux_hints_set - - _drm_animator_register, // animator_register - _drm_animator_unregister, // animator_unregister - - _drm_evas_changed, // evas_changed + _drm_animator_register, + _drm_animator_unregister, + _drm_evas_changed, NULL, //fn_focus_device_set NULL, //fn_callback_focus_device_in_set NULL, //fn_callback_focus_device_out_set @@ -957,186 +653,384 @@ static Ecore_Evas_Engine_Func _ecore_evas_drm_engine_func = _drm_last_tick_get, }; -#ifdef BUILD_ECORE_EVAS_GL_DRM -static void * -_drm_gl_canvas_setup(Ecore_Evas *ee, Ecore_Evas_Engine_Drm_Data *edata) +static Eina_Bool +_cb_drm_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED) { - Evas_Engine_Info_GL_Drm *einfo; - char *num; + Ecore_Evas *ee; + Ecore_Evas_Engine_Drm_Data *edata; + int ret = 0; + + ee = data; + edata = ee->engine.data; + + ret = ecore_drm2_event_handle(edata->dev, &edata->ctx); + if (ret) + { + WRN("drmHandleEvent failed to read an event"); + return EINA_FALSE; + } - einfo = (Evas_Engine_Info_GL_Drm *)evas_engine_info_get(ee->evas); - if (!einfo) return NULL; + return EINA_TRUE; +} - einfo->info.vsync = EINA_TRUE; +static void +_cb_pageflip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec, unsigned int usec, void *data) +{ + Ecore_Evas *ee; + Ecore_Evas_Engine_Drm_Data *edata; + Ecore_Drm2_Output *output; + int ret = 0; - num = getenv("EVAS_DRM_VSYNC"); - if ((num) && (!atoi(num))) - einfo->info.vsync = EINA_FALSE; + output = data; + ee = ecore_drm2_output_user_data_get(output); + edata = ee->engine.data; - einfo->info.dev = edata->dev; - einfo->info.bpp = edata->bpp; - einfo->info.depth = edata->depth; - einfo->info.format = edata->format; - einfo->info.rotation = ee->rotation; - einfo->info.output = edata->output; + fprintf(stderr, "Pageflip Complete For Output %s\n", + ecore_drm2_output_name_get(output)); - return einfo; + ret = ecore_drm2_fb_flip_complete(output); + if (edata->ticking) + { + Ecore_Evas_Engine_Drm_Tick *etick; + double t; + + t = (double)sec + ((double)usec / 1000000); + if (!edata->once) t = ecore_time_get(); + + etick = _drm_tick_get(edata, output); + if (etick) + { + Eina_Rectangle rect; + int ox, oy, ow, oh; + + ecore_drm2_output_info_get(output, &ox, &oy, &ow, &oh, NULL); + EINA_RECTANGLE_SET(&rect, ox, oy, ow, oh); + /* efl_canvas_output_unlock(etick->canvas); */ + ecore_evas_animator_tick(ee, &rect, t - etick->offset); + } + } + else if (ret) + { + Ecore_Evas_Engine_Drm_Tick *etick; + + etick = _drm_tick_get(edata, output); + if (etick) + { + /* efl_canvas_output_lock(etick->canvas); */ + ecore_drm2_fb_flip(NULL, etick->output); + } + } +} + +static Eina_Bool +_cb_device_change(void *d EINA_UNUSED, int t EINA_UNUSED, void *event) +{ + Elput_Event_Device_Change *ev = event; + const Eina_List *l; + Ecore_Evas *ee; + Ecore_Evas_Engine_Drm_Data *edata; + Elput_Seat *seat; + Elput_Manager *manager; + Eina_Bool found = EINA_FALSE; + Elput_Device_Caps caps; + Evas_Device_Class devclass = EVAS_DEVICE_CLASS_NONE; + Eo *dev; + + seat = elput_device_seat_get(ev->device); + manager = elput_seat_manager_get(seat); + caps = elput_device_caps_get(ev->device); + + EINA_LIST_FOREACH(canvases, l, ee) + { + edata = ee->engine.data; + found = edata->dev->em == manager; + if (found) break; + } + + if (!found) return ECORE_CALLBACK_RENEW; + if (caps & ELPUT_DEVICE_CAPS_TABLET_TOOL) + devclass = EVAS_DEVICE_CLASS_PEN; // idk how "pen" is a device class? + else if (caps & ELPUT_DEVICE_CAPS_POINTER) + devclass = EVAS_DEVICE_CLASS_MOUSE; + else if (caps & ELPUT_DEVICE_CAPS_TOUCH) + devclass = EVAS_DEVICE_CLASS_TOUCH; + else if (caps & ELPUT_DEVICE_CAPS_KEYBOARD) + devclass = EVAS_DEVICE_CLASS_KEYBOARD; + switch (ev->type) + { + case ELPUT_DEVICE_ADDED: + { + if (!edata->seat) + { + Eina_Stringshare *name; + + name = elput_seat_name_get(seat); + edata->seat = + evas_device_add_full(ee->evas, name, "drm seat", NULL, NULL, + EVAS_DEVICE_CLASS_SEAT, + EVAS_DEVICE_SUBCLASS_NONE); + evas_device_seat_id_set(edata->seat, strtol(name, NULL, 10)); + } + + dev = + evas_device_add_full(ee->evas, + elput_device_output_name_get(ev->device), + "drm device", edata->seat, NULL, devclass, + EVAS_DEVICE_SUBCLASS_NONE); + ev->device->evas_device = dev; + break; + } + case ELPUT_DEVICE_REMOVED: + { + EINA_LIST_FOREACH(evas_device_list(ee->evas, edata->seat), l, dev) + { + if (dev != ev->device->evas_device) continue; + evas_device_del(dev); + ev->device->evas_device = NULL; + break; + } + break; + } + } + + return ECORE_CALLBACK_RENEW; } -#endif -static void * -_drm_canvas_setup(Ecore_Evas *ee, Ecore_Evas_Engine_Drm_Data *edata) +static int +_drm_init(Ecore_Evas_Engine_Drm_Data *edata, const char *device) { - Evas_Engine_Info_Drm *einfo; + if (++_drm_init_count != 1) return _drm_init_count; + + if (!ecore_drm2_init()) + { + ERR("Failed to init Ecore_Drm2 library"); + goto init_err; + } + + if (!device) device = "seat0"; + + edata->dev = ecore_drm2_device_open(device, 0); + if (!edata->dev) + { + ERR("Failed to open drm device"); + goto open_err; + } + + if (!ecore_drm2_outputs_create(edata->dev)) + { + ERR("Failed to create drm outputs"); + goto output_err; + } + + ecore_event_evas_init(); - einfo = (Evas_Engine_Info_Drm *)evas_engine_info_get(ee->evas); - if (!einfo) return NULL; + if (!devhdlr) + { + devhdlr = + ecore_event_handler_add(ELPUT_EVENT_DEVICE_CHANGE, + _cb_device_change, NULL); + } - einfo->info.dev = edata->dev; - einfo->info.bpp = edata->bpp; - einfo->info.depth = edata->depth; - einfo->info.format = edata->format; - einfo->info.rotation = ee->rotation; - einfo->info.output = edata->output; + return _drm_init_count; - return einfo; +output_err: + ecore_drm2_device_close(edata->dev); +open_err: + ecore_drm2_shutdown(); +init_err: + return --_drm_init_count; +} + +static int +_drm_shutdown(Ecore_Evas_Engine_Drm_Data *edata) +{ + if (--_drm_init_count != 0) return _drm_init_count; + + ecore_event_handler_del(devhdlr); + + ecore_event_evas_shutdown(); + ecore_drm2_outputs_destroy(edata->dev); + ecore_drm2_device_close(edata->dev); + ecore_drm2_shutdown(); + + return _drm_init_count; +} + +static Ecore_Evas_Interface_Drm * +_drm_interface_new(void) +{ + Ecore_Evas_Interface_Drm *iface; + + iface = calloc(1, sizeof(Ecore_Evas_Interface_Drm)); + if (!iface) return NULL; + + iface->base.name = "drm"; + iface->base.version = 1; + + return iface; +} + +static void +_ecore_evas_drm_canvas_setup(Ecore_Evas *ee, Ecore_Evas_Engine_Drm_Data *edata) +{ + Ecore_Drm2_Output *output; + Eina_List *outs, *l; + + outs = (Eina_List *)ecore_drm2_outputs_get(edata->dev); + EINA_LIST_FOREACH(outs, l, output) + { + Efl_Canvas_Output *eout; + Evas_Engine_Info_Drm *einfo; + Ecore_Evas_Engine_Drm_Tick *etick; + int ox, oy, ow, oh; + + if (!ecore_drm2_output_connected_get(output)) continue; + if (!ecore_drm2_output_enabled_get(output)) continue; + + eout = efl_canvas_output_add(ee->evas); + if (!eout) continue; + + /* efl_canvas_output_lock(eout); */ + + einfo = (Evas_Engine_Info_Drm *)efl_canvas_output_engine_info_get(eout); + if (!einfo) + { + efl_canvas_output_del(eout); + continue; + } + + einfo->info.dev = edata->dev; + einfo->info.bpp = 32; + einfo->info.depth = 24; + einfo->info.alpha = ee->alpha; + einfo->info.rotation = ee->rotation; + einfo->info.format = DRM_FORMAT_XRGB8888; + einfo->info.output = output; + + ecore_drm2_output_info_get(output, &ox, &oy, &ow, &oh, NULL); + + fprintf(stderr, "Ecore_Evas_Drm: Adding Canvas for Output %s At %d %d %d %d\n", + ecore_drm2_output_name_get(output), ox, oy, ow, oh); + + efl_canvas_output_view_set(eout, ox, oy, ow, oh); + efl_canvas_output_engine_info_set(eout, (Evas_Engine_Info *)einfo); + + ecore_drm2_output_user_data_set(output, ee); + + if (ecore_drm2_output_primary_get(output)) + { + ee->prop.window = ecore_drm2_output_crtc_get(output); + ecore_drm2_device_window_set(edata->dev, ee->prop.window); + } + + outputs = eina_list_append(outputs, output); + + etick = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Tick)); + if (!etick) continue; + + etick->canvas = eout; + etick->output = output; + if (edata->once) etick->offset = 0.0; + + edata->ticks = eina_list_append(edata->ticks, etick); + } } static Ecore_Evas * _ecore_evas_new_internal(const char *device, int x, int y, int w, int h, Eina_Bool gl) { Ecore_Evas *ee; - Ecore_Evas_Interface_Drm *iface; Ecore_Evas_Engine_Drm_Data *edata; - int method, mw, mh; - void *tinfo; + int method = 0; if (gl) method = evas_render_method_lookup("gl_drm"); else method = evas_render_method_lookup("drm"); - if (!method) return NULL; + if (!method) + { + ERR("Could not find evas render method"); + return NULL; + } ee = calloc(1, sizeof(Ecore_Evas)); if (!ee) return NULL; edata = calloc(1, sizeof(Ecore_Evas_Engine_Drm_Data)); - if (!edata) - { - free(ee); - return NULL; - } + if (!edata) goto edata_err; + + if (_drm_init(edata, device) < 1) + goto init_err; if (!getenv("ECORE_EVAS_DRM_GPU_CLOCK_WRONG")) - { - edata->once = EINA_TRUE; - edata->offset = 0.0; - } - edata->x = x; - edata->y = y; - edata->w = w; - edata->h = h; - edata->depth = 24; // FIXME: Remove hardcode - edata->bpp = 32; // FIXME: Remove hardcode - edata->format = DRM_FORMAT_XRGB8888; - - if (_ecore_evas_drm_init(ee, edata, device) < 1) - { - free(edata); - free(ee); - return NULL; - } + edata->once = EINA_TRUE; ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); - if (gl) ee->driver = "gl_drm"; - else ee->driver = "drm"; + if (gl) + ee->driver = "gl_drm"; + else + ee->driver = "drm"; - ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_evas_drm_engine_func; + ee->engine.func = (Ecore_Evas_Engine_Func *)&_drm_engine_func; ee->engine.data = edata; - - /* FIXME */ - /* if (edata->device) ee->name = strdup(edata->device); */ - - iface = _ecore_evas_drm_interface_new(); - ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface); + ee->engine.ifaces = + eina_list_append(ee->engine.ifaces, _drm_interface_new()); 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->alpha = EINA_FALSE; - ee->prop.max.w = 32767; - ee->prop.max.h = 32767; ee->prop.layer = 4; - ee->prop.request_pos = 0; - ee->prop.sticky = 0; + ee->prop.max.w = ee->prop.max.h = 32767; + ee->prop.request_pos = EINA_FALSE; + ee->prop.sticky = EINA_FALSE; ee->prop.withdrawn = EINA_TRUE; - ee->alpha = EINA_FALSE; ee->can_async_render = !gl; if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER")) - ee->can_async_render = 0; + ee->can_async_render = EINA_FALSE; if (!ecore_evas_evas_new(ee, w, h)) { ERR("Can not create a Canvas."); +>>>>>>> ecore-evas-drm: Refactor ecore-evas drm engine to work with multiple outputs goto eng_err; } evas_output_method_set(ee->evas, method); - if (ee->can_async_render) - evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST, - _drm_render_updates, ee); - -#ifdef BUILD_ECORE_EVAS_GL_DRM - if (gl) - tinfo = _drm_gl_canvas_setup(ee, edata); - else -#endif - tinfo = _drm_canvas_setup(ee, edata); + /* TODO */ + /* if (ee->can_async_render) */ + /* evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST, */ + /* _cb_render_updates, ee); */ - if (!tinfo) - { - ERR("evas_engine_info_get() for engine '%s' failed", ee->driver); - goto eng_err; - } - - if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)tinfo)) - { - ERR("evas_engine_info_set() for engine '%s' failed", ee->driver); - goto eng_err; - } - - ee->prop.window = ecore_drm2_output_crtc_get(edata->output); - ecore_drm2_device_window_set(edata->dev, ee->prop.window); + /* TODO: setup efl_canvas outputs */ + if (!gl) + _ecore_evas_drm_canvas_setup(ee, edata); ecore_evas_data_set(ee, "device", edata->dev); ecore_evas_done(ee, EINA_FALSE); - ecore_drm2_output_info_get(edata->output, NULL, NULL, &mw, &mh, NULL); - - ecore_drm2_device_calibrate(edata->dev, mw, mh); - ecore_drm2_device_pointer_max_set(edata->dev, mw, mh); - ecore_drm2_device_pointer_warp(edata->dev, mw / 2, mh / 2); - - /* setup vblank handler */ - memset(&edata->ctx, 0, sizeof(edata->ctx)); + memset(&edata->ctx, 0, sizeof(Ecore_Drm2_Context)); edata->ctx.page_flip_handler = _cb_pageflip; edata->hdlr = ecore_main_fd_handler_add(ecore_drm2_device_fd_get(edata->dev), - ECORE_FD_READ, _cb_drm_event, ee, - NULL, NULL); + ECORE_FD_READ, _cb_drm_event, ee, NULL, NULL); canvases = eina_list_append(canvases, ee); + return ee; -eng_err: - ecore_evas_free(ee); +init_err: + free(edata); +edata_err: + free(ee); return NULL; } |