diff --git a/src/modules/evas/engines/drm/Evas_Engine_Drm.h b/src/modules/evas/engines/drm/Evas_Engine_Drm.h index d149e609ac..e056694903 100644 --- a/src/modules/evas/engines/drm/Evas_Engine_Drm.h +++ b/src/modules/evas/engines/drm/Evas_Engine_Drm.h @@ -11,6 +11,9 @@ struct _Evas_Engine_Info_Drm struct { + void *gbm; + unsigned int format; + unsigned int rotation, depth; Eina_Bool destination_alpha : 1; } info; diff --git a/src/modules/evas/engines/drm/evas_engine.c b/src/modules/evas/engines/drm/evas_engine.c index cc5e86fbd7..e018a9fb83 100644 --- a/src/modules/evas/engines/drm/evas_engine.c +++ b/src/modules/evas/engines/drm/evas_engine.c @@ -1,6 +1,3 @@ -#include "evas_common_private.h" -#include "evas_private.h" -#include "Evas_Engine_Drm.h" #include "evas_engine.h" /* local structures */ @@ -9,112 +6,207 @@ typedef struct _Render_Engine Render_Engine; struct _Render_Engine { Evas_Engine_Info_Drm *info; - + Outbuf *ob; Tilebuf *tb; + Tilebuf_Rect *rects; Tilebuf_Rect *prev_rects[3]; - - Outbuf *ob; + Eina_Inlist *cur_rect; short mode; - Eina_Inlist *cur_rect; - Eina_Bool end : 1; Eina_Bool lost_back : 1; + + /* function pointers for output buffer functions that we can + * override based on if we are swapping or not */ + void (*outbuf_free)(Outbuf *ob); + void (*outbuf_reconfigure)(Outbuf *ob, int x, int y, int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha); + RGBA_Image *(*outbuf_update_region_new)(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch); + void (*outbuf_update_region_push)(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h); + void (*outbuf_update_region_free)(Outbuf *ob, RGBA_Image *update); + void (*outbuf_flush)(Outbuf *ob); + void (*outbuf_idle_flush)(Outbuf *ob); }; /* local function prototypes */ -static void *_output_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha, int swap); +static void *_output_engine_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool destination_alpha, int try_swap); +static Tilebuf_Rect *_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3); -/* function tables - filled in later (func and parent func) */ +/* engine function prototypes */ +static void *eng_info(Evas *eo_evas EINA_UNUSED); +static void eng_info_free(Evas *eo_evas EINA_UNUSED, void *einfo); +static int eng_setup(Evas *eo_evas, void *einfo); +static void eng_output_free(void *data); +static void eng_output_resize(void *data, int w, int h); +static void eng_output_tile_size_set(void *data, int w, int h); +static void eng_output_redraws_rect_add(void *data, int x, int y, int w, int h); +static void eng_output_redraws_rect_del(void *data, int x, int y, int w, int h); +static void eng_output_redraws_clear(void *data); +static void *eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch); +static void eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h, Evas_Render_Mode render_mode); +static void eng_output_flush(void *data, Evas_Render_Mode render_mode); +static void eng_output_idle_flush(void *data); + +/* local variables */ static Evas_Func func, pfunc; /* external variables */ -int _evas_engine_drm_log_dom; +int _evas_engine_drm_log_dom = -1; /* local functions */ static void * -_output_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha, int swap) +_output_engine_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool destination_alpha, int try_swap) { - Render_Engine *re; + Render_Engine *re = NULL; - /* try to allocate space for our render engine structure */ - if (!(re = calloc(1, sizeof(Render_Engine)))) + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* try to allocate a new render engine */ + if (!(re = calloc(1, sizeof(Render_Engine)))) return NULL; - /* try to create a new tilebuffer */ + /* try to create a new tilebuf first */ if (!(re->tb = evas_common_tilebuf_new(w, h))) { free(re); return NULL; } - /* set tilesize */ + /* set tile size for the tile buffer */ evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE); - if (swap) + if (try_swap) { - /* free any existing outbuf */ - if (re->ob) evas_outbuf_free(re->ob); - - /* try to create new outbuf */ - if (!(re->ob = evas_outbuf_setup(w, h, rotation, depth, alpha))) + if ((re->ob = evas_swapbuf_setup(w, h, rotation, depth, + destination_alpha))) { - if (re->tb) evas_common_tilebuf_free(re->tb); - free(re); - return NULL; + re->outbuf_free = evas_swapbuf_free; + re->outbuf_reconfigure = evas_swapbuf_reconfigure; + re->outbuf_update_region_new = evas_swapbuf_update_region_new; + re->outbuf_update_region_push = evas_swapbuf_update_region_push; + re->outbuf_update_region_free = evas_swapbuf_update_region_free; + re->outbuf_flush = evas_swapbuf_flush; + re->outbuf_idle_flush = evas_swapbuf_idle_flush; } } - /* return the allocated render_engine structure */ + /* if creating an output buffer failed, then return NULL */ + if (!re->ob) + { + if (re->tb) evas_common_tilebuf_free(re->tb); + free(re); + return NULL; + } + + /* return allocated render engine */ return re; } -/* engine api functions */ +static Tilebuf_Rect * +_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3) +{ + Tilebuf_Rect *r, *rects; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (r1) + { + EINA_INLIST_FOREACH(EINA_INLIST_GET(r1), r) + evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h); + } + if (r2) + { + EINA_INLIST_FOREACH(EINA_INLIST_GET(r2), r) + evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h); + } + if (r3) + { + EINA_INLIST_FOREACH(EINA_INLIST_GET(r3), r) + evas_common_tilebuf_add_redraw(tb, r->x, r->y, r->w, r->h); + } + rects = evas_common_tilebuf_get_render_rects(tb); + +/* + // bounding box -> make a bounding box single region update of all regions. + // yes we could try and be smart and figure out size of regions, how far + // apart etc. etc. to try and figure out an optimal "set". this is a tradeoff + // between multiple update regions to render and total pixels to render. + if (rects) + { + px1 = rects->x; py1 = rects->y; + px2 = rects->x + rects->w; py2 = rects->y + rects->h; + EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r) + { + if (r->x < x1) px1 = r->x; + if (r->y < y1) py1 = r->y; + if ((r->x + r->w) > x2) px2 = r->x + r->w; + if ((r->y + r->h) > y2) py2 = r->y + r->h; + } + evas_common_tilebuf_free_render_rects(rects); + rects = calloc(1, sizeof(Tilebuf_Rect)); + if (rects) + { + rects->x = px1; + rects->y = py1; + rects->w = px2 - px1; + rects->h = py2 - py1; + } + } + */ + evas_common_tilebuf_clear(tb); + return rects; +} + +/* engine functions */ static void * -eng_info(Evas *evas EINA_UNUSED) +eng_info(Evas *eo_evas EINA_UNUSED) { Evas_Engine_Info_Drm *info; - /* try to allocate space for our engine info structure */ + /* try to allocate space for engine info */ if (!(info = calloc(1, sizeof(Evas_Engine_Info_Drm)))) return NULL; - /* set some engine default properties */ + /* fill in default engine info fields */ info->magic.magic = rand(); info->render_mode = EVAS_RENDER_MODE_BLOCKING; + /* return allocated engine info */ return info; } static void -eng_info_free(Evas *evas EINA_UNUSED, void *einfo) +eng_info_free(Evas *eo_evas EINA_UNUSED, void *einfo) { Evas_Engine_Info_Drm *info; - /* free the engine info */ + /* try to free previously allocated engine info */ if ((info = (Evas_Engine_Info_Drm *)einfo)) free(info); } static int -eng_setup(Evas *evas, void *einfo) +eng_setup(Evas *eo_evas, void *einfo) { Evas_Engine_Info_Drm *info; Evas_Public_Data *epd; - Render_Engine *re; + Render_Engine *re = NULL; - /* try to cast to our engine info structure */ - if (!(info = (Evas_Engine_Info_Drm *)einfo)) return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - /* try to get the evas public data */ - if (!(epd = eo_data_scope_get(evas, EVAS_CLASS))) return 0; + /* try to cast the engine info to our engine info */ + if (!(info = (Evas_Engine_Info_Drm *)einfo)) + return 0; - /* check for valid engine output */ + /* try to get evas public data from the canvas */ + if (!(epd = eo_data_scope_get(eo_evas, EVAS_CLASS))) + return 0; + + /* test for valid engine output */ if (!(re = epd->engine.data.output)) { - static int swap = -1; + static int try_swap = -1; /* NB: If we have no valid output then assume we have not been * initialized yet and call any needed common init routines */ @@ -130,47 +222,66 @@ eng_setup(Evas *evas, void *einfo) evas_common_draw_init(); evas_common_tilebuf_init(); - /* check if swapping is disabled */ - if (swap == -1) + if (try_swap == -1) { - if (getenv("EVAS_DRM_NO_SWAP")) swap = 0; - else swap = 1; + /* check for env var to see if we should try swapping */ + if (getenv("EVAS_NO_DRM_SWAPBUF")) try_swap = 0; + else try_swap = 1; } - /* try to create a new render_engine */ - if (!(re = _output_setup(epd->output.w, epd->output.h, - info->info.rotation, info->info.depth, - info->info.destination_alpha, swap))) + if (!(re = + _output_engine_setup(epd->output.w, epd->output.h, + info->info.rotation, info->info.depth, + info->info.destination_alpha, + try_swap))) return 0; + re->info = info; } else { - /* if we have an existing outbuf, free it */ - if (re->ob) evas_outbuf_free(re->ob); + int ponebuf = 0; - /* try to create a new outbuf */ - if (!(re->ob = - evas_outbuf_setup(epd->output.w, epd->output.h, - info->info.rotation, info->info.depth, - info->info.destination_alpha))) - return 0; + if ((re) && (re->ob)) ponebuf = re->ob->onebuf; + + /* free any existing tile buffer */ + if (re->tb) evas_common_tilebuf_free(re->tb); + + /* we have an existing output buffer, free it */ + if (re->ob) re->outbuf_free(re->ob); + + /* create new tile buffer */ + if ((re->tb = evas_common_tilebuf_new(epd->output.w, epd->output.h))) + evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE); + + if ((re->ob = evas_swapbuf_setup(epd->output.w, epd->output.h, + info->info.rotation, + info->info.depth, + info->info.destination_alpha))) + { + re->outbuf_free = evas_swapbuf_free; + re->outbuf_reconfigure = evas_swapbuf_reconfigure; + re->outbuf_update_region_new = evas_swapbuf_update_region_new; + re->outbuf_update_region_push = evas_swapbuf_update_region_push; + re->outbuf_update_region_free = evas_swapbuf_update_region_free; + re->outbuf_flush = evas_swapbuf_flush; + re->outbuf_idle_flush = evas_swapbuf_idle_flush; + } + + re->info = info; + if ((re) && (re->ob)) re->ob->onebuf = ponebuf; } - /* update the info structure pointer */ - re->info = info; - - /* reassign engine output */ + /* reassign render engine to output */ epd->engine.data.output = re; if (!epd->engine.data.output) return 0; - /* check for valid engine context */ if (!epd->engine.data.context) { - /* create a context if needed */ epd->engine.data.context = epd->engine.func->context_new(epd->engine.data.output); } + /* return success */ return 1; } @@ -179,16 +290,19 @@ eng_output_free(void *data) { Render_Engine *re; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if ((re = data)) { - if (re->ob) evas_outbuf_free(re->ob); - if (re->tb) evas_common_tilebuf_free(re->tb); - if (re->rects) evas_common_tilebuf_free_render_rects(re->rects); - if (re->prev_rects[0]) + re->outbuf_free(re->ob); + evas_common_tilebuf_free(re->tb); + if (re->rects) + evas_common_tilebuf_free_render_rects(re->rects); + if (re->prev_rects[0]) evas_common_tilebuf_free_render_rects(re->prev_rects[0]); - if (re->prev_rects[1]) + if (re->prev_rects[1]) evas_common_tilebuf_free_render_rects(re->prev_rects[1]); - if (re->prev_rects[2]) + if (re->prev_rects[2]) evas_common_tilebuf_free_render_rects(re->prev_rects[2]); free(re); } @@ -197,52 +311,305 @@ eng_output_free(void *data) evas_common_image_shutdown(); } -/* module api functions */ -static int +static void +eng_output_resize(void *data, int w, int h) +{ + Render_Engine *re; + Evas_Engine_Info_Drm *info; + /* int dx = 0, dy = 0; */ + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(re = (Render_Engine *)data)) return; + + if (!(info = re->info)) return; + + /* if (info->info.edges & 4) */ + /* { */ + /* if ((info->info.rotation == 90) || (info->info.rotation == 270)) */ + /* dx = re->ob->h - h; */ + /* else */ + /* dx = re->ob->w - w; */ + /* } */ + + /* if (info->info.edges & 1) */ + /* { */ + /* if ((info->info.rotation == 90) || (info->info.rotation == 270)) */ + /* dy = re->ob->w - w; */ + /* else */ + /* dy = re->ob->h - h; */ + /* } */ + + re->outbuf_reconfigure(re->ob, 0, 0, w, h, + info->info.rotation, info->info.depth, + info->info.destination_alpha); + + evas_common_tilebuf_free(re->tb); + if ((re->tb = evas_common_tilebuf_new(w, h))) + evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE); +} + +static void +eng_output_tile_size_set(void *data, int w, int h) +{ + Render_Engine *re; + + if (!(re = (Render_Engine *)data)) return; + if (re->tb) evas_common_tilebuf_set_tile_size(re->tb, w, h); +} + +static void +eng_output_redraws_rect_add(void *data, int x, int y, int w, int h) +{ + Render_Engine *re; + + if (!(re = (Render_Engine *)data)) return; + evas_common_tilebuf_add_redraw(re->tb, x, y, w, h); +} + +static void +eng_output_redraws_rect_del(void *data, int x, int y, int w, int h) +{ + Render_Engine *re; + + if (!(re = (Render_Engine *)data)) return; + if (re->tb) evas_common_tilebuf_del_redraw(re->tb, x, y, w, h); +} + +static void +eng_output_redraws_clear(void *data) +{ + Render_Engine *re; + + if (!(re = (Render_Engine *)data)) return; + if (re->tb) evas_common_tilebuf_clear(re->tb); +} + +static void * +eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, int *cx, int *cy, int *cw, int *ch) +{ + Render_Engine *re; + RGBA_Image *surface; + Tilebuf_Rect *rect; + Eina_Bool first_rect = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + +#define CLEAR_PREV_RECTS(x) \ + do { \ + if (re->prev_rects[x]) \ + evas_common_tilebuf_free_render_rects(re->prev_rects[x]); \ + re->prev_rects[x] = NULL; \ + } while (0) + + re = (Render_Engine *)data; + if (re->end) + { + re->end = 0; + return NULL; + } + + if (!re->rects) + { + re->mode = evas_swapbuf_state_get(re->ob); + re->rects = evas_common_tilebuf_get_render_rects(re->tb); + if (re->rects) + { + if ((re->lost_back) || (re->mode == MODE_FULL)) + { + /* if we lost our backbuffer since the last frame redraw all */ + re->lost_back = 0; + evas_common_tilebuf_add_redraw(re->tb, 0, 0, re->ob->w, re->ob->h); + evas_common_tilebuf_free_render_rects(re->rects); + re->rects = evas_common_tilebuf_get_render_rects(re->tb); + } + /* ensure we get rid of previous rect lists we dont need if mode + * changed/is appropriate */ + evas_common_tilebuf_clear(re->tb); + CLEAR_PREV_RECTS(2); + re->prev_rects[2] = re->prev_rects[1]; + re->prev_rects[1] = re->prev_rects[0]; + re->prev_rects[0] = re->rects; + re->rects = NULL; + switch (re->mode) + { + case MODE_FULL: + case MODE_COPY: // no prev rects needed + re->rects = + _merge_rects(re->tb, re->prev_rects[0], NULL, NULL); + break; + case MODE_DOUBLE: // double mode - only 1 level of prev rect + re->rects = + _merge_rects(re->tb, re->prev_rects[0], re->prev_rects[1], NULL); + break; + case MODE_TRIPLE: // keep all + re->rects = + _merge_rects(re->tb, re->prev_rects[0], re->prev_rects[1], re->prev_rects[2]); + break; + default: + break; + } + first_rect = EINA_TRUE; + } + evas_common_tilebuf_clear(re->tb); + re->cur_rect = EINA_INLIST_GET(re->rects); + } + if (!re->cur_rect) return NULL; + rect = (Tilebuf_Rect *)re->cur_rect; + if (re->rects) + { + switch (re->mode) + { + case MODE_COPY: + case MODE_DOUBLE: + case MODE_TRIPLE: + rect = (Tilebuf_Rect *)re->cur_rect; + *x = rect->x; + *y = rect->y; + *w = rect->w; + *h = rect->h; + *cx = rect->x; + *cy = rect->y; + *cw = rect->w; + *ch = rect->h; + re->cur_rect = re->cur_rect->next; + break; + case MODE_FULL: + re->cur_rect = NULL; + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = re->ob->w; + if (h) *h = re->ob->h; + if (cx) *cx = 0; + if (cy) *cy = 0; + if (cw) *cw = re->ob->w; + if (ch) *ch = re->ob->h; + break; + default: + break; + } + if (first_rect) + { + // do anything needed for the first frame + } + surface = + re->outbuf_update_region_new(re->ob, + *x, *y, *w, *h, + cx, cy, cw, ch); + if (!re->cur_rect) re->end = EINA_TRUE; + return surface; + } + + return NULL; +} + +static void +eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int w, int h, Evas_Render_Mode render_mode) +{ + Render_Engine *re; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return; + + if (!(re = (Render_Engine *)data)) return; +#if defined(BUILD_PIPE_RENDER) + evas_common_pipe_map_begin(surface); +#endif + re->outbuf_update_region_push(re->ob, surface, x, y, w, h); + re->outbuf_update_region_free(re->ob, surface); + evas_common_cpu_end_opt(); +} + +static void +eng_output_flush(void *data, Evas_Render_Mode render_mode) +{ + Render_Engine *re; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return; + + if (!(re = (Render_Engine *)data)) return; + re->outbuf_flush(re->ob); + if (re->rects) + { + evas_common_tilebuf_free_render_rects(re->rects); + re->rects = NULL; + } +} + +static void +eng_output_idle_flush(void *data) +{ + Render_Engine *re; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(re = (Render_Engine *)data)) return; + re->outbuf_idle_flush(re->ob); +} + +/* module functions */ +static int module_open(Evas_Module *em) { /* check for valid evas module */ if (!em) return 0; - /* try to inherit functions from software_generic engine */ - if (!_evas_module_engine_inherit(&pfunc, "software_generic")) return 0; - - /* try to create eina logging domain */ + /* try to create our logging domain */ _evas_engine_drm_log_dom = eina_log_domain_register("evas-drm", EVAS_DEFAULT_LOG_COLOR); - - /* if we could not create a logging domain, error out */ if (_evas_engine_drm_log_dom < 0) { - EINA_LOG_ERR("Can not create a module log domain."); + /* creating the logging domain failed. notify user */ + EINA_LOG_ERR("Could not create a module log domain."); + + /* return failure */ return 0; } - /* store parent functions */ + /* try to inherit base functions from the software generic engine */ + if (!_evas_module_engine_inherit(&pfunc, "software_generic")) + return 0; + + /* copy base functions from the software_generic engine */ func = pfunc; - /* override the methods we provide */ - EVAS_API_OVERRIDE(info, &func, eng_); - EVAS_API_OVERRIDE(info_free, &func, eng_); - EVAS_API_OVERRIDE(setup, &func, eng_); - EVAS_API_OVERRIDE(output_free, &func, eng_); + /* override any engine specific functions that we provide */ +#define ORD(f) EVAS_API_OVERRIDE(f, &func, eng_) + ORD(info); + ORD(info_free); + ORD(setup); + ORD(output_free); + ORD(output_resize); + ORD(output_tile_size_set); + ORD(output_redraws_rect_add); + ORD(output_redraws_rect_del); + ORD(output_redraws_clear); + ORD(output_redraws_next_update_get); + ORD(output_redraws_next_update_push); + ORD(output_flush); + ORD(output_idle_flush); - /* advertise our engine functions */ + /* advertise out our own api */ em->functions = (void *)(&func); + /* return success */ return 1; } static void module_close(Evas_Module *em EINA_UNUSED) { - /* unregister the eina log domain for this engine */ - eina_log_domain_unregister(_evas_engine_drm_log_dom); + /* if we have the log domain, unregister it */ + if (_evas_engine_drm_log_dom > -1) + eina_log_domain_unregister(_evas_engine_drm_log_dom); } -static Evas_Module_Api evas_modapi = +static Evas_Module_Api evas_modapi = { - EVAS_MODULE_API_VERSION, "drm", "none", { module_open, module_close } + EVAS_MODULE_API_VERSION, "drm", "none", {module_open, module_close} }; EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_ENGINE, engine, drm); diff --git a/src/modules/evas/engines/drm/evas_engine.h b/src/modules/evas/engines/drm/evas_engine.h index 3cfbbeeb6a..cb61dffd8a 100644 --- a/src/modules/evas/engines/drm/evas_engine.h +++ b/src/modules/evas/engines/drm/evas_engine.h @@ -1,5 +1,29 @@ -#ifndef EVAS_ENGINE_H -# define EVAS_ENGINE_H +#ifndef _EVAS_ENGINE_H +# define _EVAS_ENGINE_H + +# define LOGFNS 1 + +# ifdef LOGFNS +# include +# define LOGFN(fl, ln, fn) printf("-EVAS-DRM: %25s: %5i - %s\n", fl, ln, fn); +# else +# define LOGFN(fl, ln, fn) +# endif + +# include "evas_common_private.h" +# include "evas_macros.h" +# include "evas_private.h" +# include "Evas.h" +# include "Evas_Engine_Drm.h" + +# include +# include +# include + +# ifdef GL_GLES +# include +# define GL_GLEXT_PROTOTYPES +# endif extern int _evas_engine_drm_log_dom; @@ -28,9 +52,19 @@ extern int _evas_engine_drm_log_dom; # endif # define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__) +typedef enum _Outbuf_Depth Outbuf_Depth; +typedef struct _Wl_Swapper Wl_Swapper; typedef struct _Outbuf Outbuf; -enum +enum _Outbuf_Depth +{ + OUTBUF_DEPTH_NONE, + OUTBUF_DEPTH_ARGB_32BPP_8888_8888, + OUTBUF_DEPTH_RGB_32BPP_8888_8888, + OUTBUF_DEPTH_LAST +}; + +enum { MODE_FULL, MODE_COPY, @@ -41,12 +75,49 @@ enum struct _Outbuf { int w, h; - unsigned int rotation, depth; - Eina_Bool destination_alpha : 1; + unsigned int rotation; + Outbuf_Depth depth; + int onebuf; + + struct + { + /* struct gbm_device *gbm; */ + /* unsigned int format; */ + + /* swapper */ + void *swapper; + + /* one big buffer for updates. flushed on idle_flush */ + RGBA_Image *onebuf; + Eina_Array onebuf_regions; + + /* a list of pending regions to write out */ + Eina_List *pending_writes; + + /* list of previous frame pending regions to write out */ + Eina_List *prev_pending_writes; + + Eina_Bool destination_alpha : 1; + } priv; }; -Outbuf *evas_outbuf_setup(int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha); -void evas_outbuf_free(Outbuf *ob); -void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, unsigned int rotation, unsigned int depth, Eina_Bool alpha); +Outbuf *evas_swapbuf_setup(int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha); +void evas_swapbuf_free(Outbuf *ob); +void evas_swapbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha); +RGBA_Image *evas_swapbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch); +void evas_swapbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h); +void evas_swapbuf_update_region_free(Outbuf *ob, RGBA_Image *update); +void evas_swapbuf_flush(Outbuf *ob); +void evas_swapbuf_idle_flush(Outbuf *ob EINA_UNUSED); +int evas_swapbuf_state_get(Outbuf *ob); + +Wl_Swapper *evas_swapper_setup(int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha, int fd); +Wl_Swapper *evas_swapper_reconfigure(Wl_Swapper *ws, int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha); +void evas_swapper_swap(Wl_Swapper *ws, Eina_Rectangle *rects, unsigned int count); +void evas_swapper_free(Wl_Swapper *ws); +void *evas_swapper_buffer_map(Wl_Swapper *ws, int *w, int *h); +void evas_swapper_buffer_unmap(Wl_Swapper *ws); +int evas_swapper_buffer_state_get(Wl_Swapper *ws); +void evas_swapper_buffer_idle_flush(Wl_Swapper *ws); #endif diff --git a/src/modules/evas/engines/drm/evas_swapbuf.c b/src/modules/evas/engines/drm/evas_swapbuf.c new file mode 100644 index 0000000000..feee7e8d5e --- /dev/null +++ b/src/modules/evas/engines/drm/evas_swapbuf.c @@ -0,0 +1,521 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +//#include + +#ifdef EVAS_CSERVE2 +# include "evas_cs2_private.h" +#endif + +#include "evas_engine.h" + +#define RED_MASK 0x00ff0000 +#define GREEN_MASK 0x0000ff00 +#define BLUE_MASK 0x000000ff + +/* local function prototypes */ + +Outbuf * +evas_swapbuf_setup(int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha) +{ + Outbuf *ob = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* try to allocate a new Outbuf */ + if (!(ob = calloc(1, sizeof(Outbuf)))) + return NULL; + + /* set some properties */ + ob->w = w; + ob->h = h; + ob->rotation = rotation; + ob->depth = depth; + ob->priv.destination_alpha = alpha; + + if ((ob->rotation == 0) || (ob->rotation == 180)) + { + ob->priv.swapper = + evas_swapper_setup(0, 0, w, h, depth, alpha); + } + else if ((ob->rotation == 90) || (ob->rotation == 270)) + { + ob->priv.swapper = + evas_swapper_setup(0, 0, h, w, depth, alpha); + } + + /* check that a swapper was created */ + if (!ob->priv.swapper) + { + /* free the Outbuf structure allocation */ + free(ob); + + return NULL; + } + + /* set step size of regions array */ + eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8); + + /* return allocated Outbuf */ + return ob; +} + +void +evas_swapbuf_free(Outbuf *ob) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid output buffer */ + if (!ob) return; + + /* flush the output buffer */ + evas_swapbuf_flush(ob); + evas_swapbuf_idle_flush(ob); + evas_swapper_free(ob->priv.swapper); + eina_array_flush(&ob->priv.onebuf_regions); + + /* free the allocated structure */ + free(ob); +} + +void +evas_swapbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, unsigned int rotation, Outbuf_Depth depth, Eina_Bool alpha) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid output buffer */ + if (!ob) return; + + /* check that something was actually changed */ + if ((ob->w == w) && (ob->h == h) && + (ob->rotation == rotation) && (ob->depth == depth)) + return; + + /* set some properties */ + ob->w = w; + ob->h = h; + ob->rotation = rotation; + ob->depth = depth; + ob->priv.destination_alpha = alpha; + + /* check for valid swapper */ + if (ob->priv.swapper) + { + if ((ob->rotation == 0) || (ob->rotation == 180)) + ob->priv.swapper = evas_swapper_reconfigure(ob->priv.swapper, + x, y, w, h, depth, + alpha); + else if ((ob->rotation == 90) || (ob->rotation == 270)) + ob->priv.swapper = evas_swapper_reconfigure(ob->priv.swapper, + x, y, h, w, depth, + alpha); + return; + } + + /* create new swapper */ + if ((ob->rotation == 0) || (ob->rotation == 180)) + { + ob->priv.swapper = + evas_swapper_setup(x, y, w, h, depth, alpha); + } + else if ((ob->rotation == 90) || (ob->rotation == 270)) + { + ob->priv.swapper = + evas_swapper_setup(x, y, h, w, depth, alpha); + } +} + +RGBA_Image * +evas_swapbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch) +{ + RGBA_Image *img; + Eina_Rectangle *rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h); + if ((w <= 0) || (h <= 0)) return NULL; + + if (ob->rotation == 0) + { + if (!(img = ob->priv.onebuf)) + { + int bpl = 0; + int bw = 0, bh = 0; + void *data; + + if (!(data = evas_swapper_buffer_map(ob->priv.swapper, &bw, &bh))) + { + ERR("NO BUFFER DATA !!"); + return NULL; + } + + bpl = (bw * sizeof(int)); + +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + img = (RGBA_Image *)evas_cache2_image_data(evas_common_image_cache2_get(), + bpl / sizeof(int), bh, + data, + ob->priv.destination_alpha, + EVAS_COLORSPACE_ARGB8888); + else +#endif + img = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(), + bpl / sizeof(int), bh, + data, + ob->priv.destination_alpha, + EVAS_COLORSPACE_ARGB8888); + + ob->priv.onebuf = img; + if (!img) return NULL; + } + + if (!(rect = eina_rectangle_new(x, y, w, h))) + return NULL; + + if (!eina_array_push(&ob->priv.onebuf_regions, rect)) + { +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&img->cache_entry); + else +#endif + evas_cache_image_drop(&img->cache_entry); + + eina_rectangle_free(rect); + + return NULL; + } + + /* clip the region to the onebuf region */ + if (cx) *cx = x; + if (cy) *cy = y; + if (cw) *cw = w; + if (ch) *ch = h; + return img; + } + else + { + if (!(rect = eina_rectangle_new(x, y, w, h))) + return NULL; + +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + img = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get()); + else +#endif + img = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get()); + + if (!img) + { + eina_rectangle_free(rect); + return NULL; + } + + img->cache_entry.flags.alpha |= ob->priv.destination_alpha; + +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_surface_alloc(&img->cache_entry, w, h); + else +#endif + evas_cache_image_surface_alloc(&img->cache_entry, w, h); + + img->extended_info = rect; + + ob->priv.pending_writes = + eina_list_append(ob->priv.pending_writes, img); + + if (cx) *cx = 0; + if (cy) *cy = 0; + if (cw) *cw = w; + if (ch) *ch = h; + return img; + } + + return NULL; +} + +void +evas_swapbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h) +{ + Gfx_Func_Convert func = NULL; + Eina_Rectangle rect = {0, 0, 0, 0}, pr; + DATA32 *src; + DATA8 *dst; + int depth = 32, bpp = 0, bpl = 0, wid = 0; + int ww = 0, hh = 0; + int rx = 0, ry = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid output buffer */ + if (!ob) return; + + /* check for pending writes */ + if (!ob->priv.pending_writes) return; + + if ((ob->rotation == 0) || (ob->rotation == 180)) + { + func = + evas_common_convert_func_get(0, w, h, depth, + RED_MASK, GREEN_MASK, BLUE_MASK, + PAL_MODE_NONE, ob->rotation); + } + else if ((ob->rotation == 90) || (ob->rotation == 270)) + { + func = + evas_common_convert_func_get(0, h, w, depth, + RED_MASK, GREEN_MASK, BLUE_MASK, + PAL_MODE_NONE, ob->rotation); + } + + /* make sure we have a valid convert function */ + if (!func) return; + + /* based on rotation, set rectangle position */ + if (ob->rotation == 0) + { + rect.x = x; + rect.y = y; + } + else if (ob->rotation == 90) + { + rect.x = y; + rect.y = (ob->w - x - w); + } + else if (ob->rotation == 180) + { + rect.x = (ob->w - x - w); + rect.y = (ob->h - y - h); + } + else if (ob->rotation == 270) + { + rect.x = (ob->h - y - h); + rect.y = x; + } + + /* based on rotation, set rectangle size */ + if ((ob->rotation == 0) || (ob->rotation == 180)) + { + rect.w = w; + rect.h = h; + } + else if ((ob->rotation == 90) || (ob->rotation == 270)) + { + rect.w = h; + rect.h = w; + } + + /* check for valid update image data */ + if (!(src = update->image.data)) return; + + bpp = depth / 8; + if (bpp <= 0) return; + + /* check for valid desination data */ + if (!(dst = evas_swapper_buffer_map(ob->priv.swapper, &ww, &hh))) return; + + bpl = (ww * sizeof(int)); + + if (ob->rotation == 0) + { + RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); + dst += (bpl * rect.y) + (rect.x + bpp); + w -= rx; + } + else if (ob->rotation == 180) + { + pr = rect; + RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); + rx = pr.w - rect.w; + ry = pr.h - rect.h; + src += (update->cache_entry.w * ry) + rx; + w -= rx; + } + else if (ob->rotation == 90) + { + pr = rect; + RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); + rx = pr.w - rect.w; ry = pr.h - rect.h; + src += ry; + w -= ry; + } + else if (ob->rotation == 270) + { + pr = rect; + RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h, 0, 0, ww, hh); + rx = pr.w - rect.w; ry = pr.h - rect.h; + src += (update->cache_entry.w * rx); + w -= ry; + } + + if ((rect.w <= 0) || (rect.h <= 0)) return; + + wid = bpl / bpp; + + dst += (bpl * rect.y) + (rect.x * bpp); + + func(src, dst, (update->cache_entry.w - w), (wid - rect.w), + rect.w, rect.h, x + rx, y + ry, NULL); +} + +void +evas_swapbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED) +{ + /* NB: nothing to do, they are cleaned up on flush */ +} + +void +evas_swapbuf_flush(Outbuf *ob) +{ + Eina_Rectangle *rects; + RGBA_Image *img; + unsigned int n = 0, i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid output buffer */ + if (!ob) return; + + /* check for pending writes */ + if (!ob->priv.pending_writes) + { + Eina_Rectangle *rect; + Eina_Array_Iterator it; + + /* get number of buffer regions */ + n = eina_array_count_get(&ob->priv.onebuf_regions); + if (n == 0) return; + + /* allocate rectangles */ + if (!(rects = alloca(n * sizeof(Eina_Rectangle)))) return; + + /* loop the buffer regions and assign to rects */ + EINA_ARRAY_ITER_NEXT(&ob->priv.onebuf_regions, i, rect, it) + rects[i] = *rect; + + /* unmap the buffer */ + evas_swapper_buffer_unmap(ob->priv.swapper); + + /* force a buffer swap */ + evas_swapper_swap(ob->priv.swapper, rects, n); + + /* clean array */ + eina_array_clean(&ob->priv.onebuf_regions); + + img = ob->priv.onebuf; + ob->priv.onebuf = NULL; + if (img) + { +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&img->cache_entry); + else +#endif + evas_cache_image_drop(&img->cache_entry); + } + } + else + { + /* get number of pending writes */ + n = eina_list_count(ob->priv.pending_writes); + if (n == 0) return; + + /* allocate rectangles */ + if (!(rects = alloca(n * sizeof(Eina_Rectangle)))) return; + + /* loop the pending writes */ + EINA_LIST_FREE(ob->priv.pending_writes, img) + { + Eina_Rectangle *rect; + int x = 0, y = 0, w = 0, h = 0; + + if (!(rect = img->extended_info)) continue; + + x = rect->x; y = rect->y; w = rect->w; h = rect->h; + + /* based on rotation, set rectangle position */ + if (ob->rotation == 0) + { + rects[i].x = x; + rects[i].y = y; + } + else if (ob->rotation == 90) + { + rects[i].x = y; + rects[i].y = (ob->w - x - w); + } + else if (ob->rotation == 180) + { + rects[i].x = (ob->w - x - w); + rects[i].y = (ob->h - y - h); + } + else if (ob->rotation == 270) + { + rects[i].x = (ob->h - y - h); + rects[i].y = x; + } + + /* based on rotation, set rectangle size */ + if ((ob->rotation == 0) || (ob->rotation == 180)) + { + rects[i].w = w; + rects[i].h = h; + } + else if ((ob->rotation == 90) || (ob->rotation == 270)) + { + rects[i].w = h; + rects[i].h = w; + } + + eina_rectangle_free(rect); + +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&img->cache_entry); + else +#endif + evas_cache_image_drop(&img->cache_entry); + + i++; + } + + /* unmap the buffer */ + evas_swapper_buffer_unmap(ob->priv.swapper); + + /* force a buffer swap */ + evas_swapper_swap(ob->priv.swapper, rects, n); + } +} + +void +evas_swapbuf_idle_flush(Outbuf *ob EINA_UNUSED) +{ +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid output buffer */ + /* if (!ob) return; */ + + /* check for valid swapper */ + /* if (!ob->priv.swapper) return; */ + + /* tell the swapper to release any buffers that have been rendered */ + /* evas_swapper_buffer_idle_flush(ob->priv.swapper); */ +} + +int +evas_swapbuf_state_get(Outbuf *ob) +{ + int mode = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ob->priv.swapper) return MODE_FULL; + mode = evas_swapper_buffer_state_get(ob->priv.swapper); + return mode; +} + +/* local functions */ diff --git a/src/modules/evas/engines/drm/evas_swapper.c b/src/modules/evas/engines/drm/evas_swapper.c new file mode 100644 index 0000000000..4465d1c63b --- /dev/null +++ b/src/modules/evas/engines/drm/evas_swapper.c @@ -0,0 +1,380 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#ifdef EVAS_CSERVE2 +# include "evas_cs2_private.h" +#endif + +#include "evas_engine.h" + +/* local structures */ +typedef struct _Wl_Buffer Wl_Buffer; +struct _Wl_Buffer +{ + Wl_Swapper *ws; + int w, h; + /* struct gbm_bo *bo; */ + void *data; + int offset; + size_t size; + Eina_Bool valid : 1; +}; + +struct _Wl_Swapper +{ + Wl_Buffer buff[3]; + Wl_Buffer *buffer_sent; + + int in_use, drm_fd; + int dx, dy, w, h, depth; + int buff_cur, buff_num; + + /* struct gbm_device *gbm; */ + /* unsigned int format; */ + + /* void *data; */ + + Eina_Bool alpha : 1; + Eina_Bool mapped : 1; + Eina_Bool delete_me : 1; +}; + +/* local function prototypes */ +/* static Eina_Bool _evas_swapper_shm_pool_new(Wl_Swapper *ws); */ +/* static void _evas_swapper_shm_pool_free(Wl_Swapper *ws); */ +static Eina_Bool _evas_swapper_buffer_new(Wl_Swapper *ws, Wl_Buffer *wb); +static void _evas_swapper_buffer_free(Wl_Buffer *wb); +static void _evas_swapper_buffer_put(Wl_Swapper *ws, Wl_Buffer *wb, Eina_Rectangle *rects, unsigned int count); + +/* local variables */ + +Wl_Swapper * +evas_swapper_setup(int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha, int fd) +{ + Wl_Swapper *ws; + int i = 0; + char *num_buffers; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* try to allocate a new swapper */ + if (!(ws = calloc(1, sizeof(Wl_Swapper)))) + return NULL; + + /* set some properties */ + ws->dx = dx; + ws->dy = dy; + ws->w = w; + ws->h = h; + ws->depth = depth; + ws->alpha = alpha; + ws->drm_fd = fd; + + /* double buffer by default */ + ws->buff_num = 2; + + /* check for buffer override number */ + if ((num_buffers = getenv("EVAS_DRM_BUFFERS"))) + { + int num = 0; + + num = atoi(num_buffers); + + if (num <= 0) num = 1; + if (num > 3) num = 3; + + ws->buff_num = num; + } + + for (i = 0; i < ws->buff_num; i++) + { + /* try to create new internal Wl_Buffer */ + if (!_evas_swapper_buffer_new(ws, &(ws->buff[i]))) + { + /* failed to create wl_buffer. free the swapper */ + evas_swapper_free(ws); + return NULL; + } + } + + /* return allocated swapper */ + return ws; +} + +Wl_Swapper * +evas_swapper_reconfigure(Wl_Swapper *ws, int dx, int dy, int w, int h, Outbuf_Depth depth, Eina_Bool alpha) +{ + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!ws) + { + ERR("No swapper to reconfigure."); + return NULL; + } + + /* loop the swapper's buffers and free them */ + for (i = 0; i < ws->buff_num; i++) + _evas_swapper_buffer_free(&(ws->buff[i])); + + ws->dx += dx; + ws->dy += dy; + ws->w = w; + ws->h = h; + ws->depth = depth; + ws->alpha = alpha; + + for (i = 0; i < ws->buff_num; i++) + { + /* try to create new internal Wl_Buffer */ + if (!_evas_swapper_buffer_new(ws, &(ws->buff[i]))) + { + ERR("failed to create wl_buffer. free the swapper."); + evas_swapper_free(ws); + return NULL; + } + } + + /* return reconfigured swapper */ + return ws; +} + +void +evas_swapper_swap(Wl_Swapper *ws, Eina_Rectangle *rects, unsigned int count) +{ + int n = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid swapper */ + if (!ws) return; + + n = ws->buff_cur; + _evas_swapper_buffer_put(ws, &(ws->buff[n]), rects, count); + ws->buff[n].valid = EINA_TRUE; + ws->in_use++; + ws->buff_cur = (ws->buff_cur + 1) % ws->buff_num; +} + +void +evas_swapper_free(Wl_Swapper *ws) +{ + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid swapper */ + if (!ws) return; + + /* loop the swapper's buffers and free them */ + for (i = 0; i < ws->buff_num; i++) + _evas_swapper_buffer_free(&(ws->buff[i])); + + if (ws->in_use) + { + ws->delete_me = EINA_TRUE; + return; + } + + /* free the allocated structure */ + free(ws); +} + +void * +evas_swapper_buffer_map(Wl_Swapper *ws, int *w, int *h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid swapper */ + if (!ws) return NULL; + + /* set mapped property */ + ws->mapped = EINA_TRUE; + if (w) *w = ws->w; + if (h) *h = ws->h; + + /* return wl_buffer data */ + return ws->buff[ws->buff_cur].data; +} + +void +evas_swapper_buffer_unmap(Wl_Swapper *ws) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid swapper */ + if (!ws) return; + + ws->mapped = EINA_FALSE; +} + +int +evas_swapper_buffer_state_get(Wl_Swapper *ws) +{ + int i = 0, n = 0, count = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + for (i = 0; i < ws->buff_num; i++) + { + n = (ws->buff_num + ws->buff_cur - (i)) % ws->buff_num; + if (ws->buff[n].valid) count++; + else break; + } + + if (count == ws->buff_num) + { + if (count == 1) return MODE_COPY; + else if (count == 2) return MODE_DOUBLE; + else if (count == 3) return MODE_TRIPLE; + } + + return MODE_FULL; +} + +void +evas_swapper_buffer_idle_flush(Wl_Swapper *ws) +{ + int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid swapper */ + if (!ws) return; + + /* loop the swapper's buffers and free them */ + for (i = 0; i < ws->buff_num; i++) + { + Wl_Buffer *wb = NULL; + + /* try to get out Wl_Buffer struct */ + if (!(wb = (&(ws->buff[i])))) continue; + + /* if this buffer is not valid, then unmap data */ + if (!wb->valid) _evas_swapper_buffer_free(wb); + } +} + +/* local functions */ +static Eina_Bool +_evas_swapper_buffer_new(Wl_Swapper *ws, Wl_Buffer *wb) +{ + int id; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + wb->w = ws->w; + wb->h = ws->h; + + struct drm_mode_create_dumb carg; + struct drm_mode_destroy_dumb darg; + struct drm_mode_map_dump marg; + + memset(&carg, 0, sizeof(struct drm_mode_create_dumb)); + carb.bpp = 32; + carg.width = wb->w; + carg.height = wb->h; + + drmIoctl(ws->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg); + drmModeAddFB(ws->drm_fd, wb->w, wb->h, 24, 32, carg.pitch, carg.handle, &id); + + memset(&marg, 0, sizeof(struct drm_mode_map_dumb)); + marg.handle = carg.handle; + drmIoctl(ws->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &marg); + wb->data = mmap(0, carg.size, PROT_WRITE, MAP_SHARED, + ws->drm_fd, marg.offset); + memset(wb->data, 0, carg.size); + + /* create actual wl_buffer */ + /* wb->buffer = */ + /* wl_shm_pool_create_buffer(ws->pool, ws->used_size, wb->w, wb->h, */ + /* (wb->w * sizeof(int)), format); */ + + /* add wayland buffer listener */ + /* wl_buffer_add_listener(wb->buffer, &_evas_swapper_buffer_listener, wb); */ + + /* wb->data = (char *)ws->data + ws->used_size; */ + + wb->ws = ws; + + /* return allocated buffer */ + return EINA_TRUE; +} + +static void +_evas_swapper_buffer_free(Wl_Buffer *wb) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid buffer */ + if ((!wb) || (wb->valid)) return; + + /* kill the wl_buffer */ + /* if (wb->buffer) wl_buffer_destroy(wb->buffer); */ + /* wb->buffer = NULL; */ + + /* unmap the buffer data */ + /* if (wb->data) munmap(wb->data, wb->size); */ + /* wb->data = NULL; */ +} + +static void +_evas_swapper_buffer_put(Wl_Swapper *ws, Wl_Buffer *wb, Eina_Rectangle *rects, unsigned int count) +{ + Eina_Rectangle *rect; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* check for valid swapper */ + if (!ws) return; + + /* make sure swapper has a surface */ + /* if (!ws->surface) return; */ + + /* check for valid buffer */ + if (!wb) return; + + /* make sure buffer has mapped data */ + if ((!wb->data)) + { + /* call function to mmap buffer data */ + if (!_evas_swapper_buffer_new(ws, wb)) + return; + } + + rect = eina_rectangle_new(0, 0, 0, 0); + if ((rects) && (count > 0)) + { + unsigned int i = 0; + + for (i = 0; i < count; i++) + eina_rectangle_union(rect, &rects[i]); + } + else + { + Eina_Rectangle r; + + r.x = 0; r.y = 0; + r.w = wb->w; r.h = wb->h; + + eina_rectangle_union(rect, &r); + } + + /* surface attach */ + if (ws->buffer_sent != wb) + { + /* wl_surface_attach(ws->surface, wb->buffer, ws->dx, ws->dy); */ + ws->dx = 0; + ws->dy = 0; + ws->buffer_sent = wb; + } + + /* wl_surface_damage(ws->surface, rect->x, rect->y, rect->w, rect->h); */ + + /* surface commit */ + /* wl_surface_commit(ws->surface); */ +}