summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Michael <cp.michael@samsung.com>2014-01-10 07:28:43 +0000
committerChris Michael <cp.michael@samsung.com>2014-01-29 15:27:23 +0000
commit1984303de12e3f489dac8daeb3b054792d194ba7 (patch)
tree4106db5ff37d79e1c3eedc09270df6620bfc540d
parenta7376722f73b12aac32db296437515aa3674424c (diff)
downloadefl-1984303de12e3f489dac8daeb3b054792d194ba7.tar.gz
Begin work on getting evas drm engine to actually render
Signed-off-by: Chris Michael <cp.michael@samsung.com>
-rw-r--r--src/modules/evas/engines/drm/Evas_Engine_Drm.h3
-rw-r--r--src/modules/evas/engines/drm/evas_engine.c549
-rw-r--r--src/modules/evas/engines/drm/evas_engine.h87
-rw-r--r--src/modules/evas/engines/drm/evas_swapbuf.c521
-rw-r--r--src/modules/evas/engines/drm/evas_swapper.c380
5 files changed, 1441 insertions, 99 deletions
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);
-
-/* function tables - filled in later (func and parent func) */
+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);
+
+/* 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;
+
+ LOGFN(__FILE__, __LINE__, __FUNCTION__);
- /* try to cast to our engine info structure */
- if (!(info = (Evas_Engine_Info_Drm *)einfo)) return 0;
+ /* try to cast the engine info to our engine info */
+ if (!(info = (Evas_Engine_Info_Drm *)einfo))
+ return 0;
- /* try to get the evas public data */
- if (!(epd = eo_data_scope_get(evas, EVAS_CLASS))) return 0;
+ /* try to get evas public data from the canvas */
+ if (!(epd = eo_data_scope_get(eo_evas, EVAS_CLASS)))
+ return 0;
- /* check for valid engine output */
+ /* 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;
- /* update the info structure pointer */
- re->info = info;
+ /* 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);
- /* reassign engine output */
+ /* 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;
+ }
+
+ /* 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 */
- func = pfunc;
+ /* try to inherit base functions from the software generic engine */
+ if (!_evas_module_engine_inherit(&pfunc, "software_generic"))
+ return 0;
- /* 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_);
+ /* copy base functions from the software_generic engine */
+ func = pfunc;
- /* advertise our engine functions */
+ /* 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 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 <stdio.h>
+# 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 <xf86drm.h>
+# include <xf86drmMode.h>
+# include <drm_fourcc.h>
+
+# ifdef GL_GLES
+# include <EGL/egl.h>
+# 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 <config.h>
+#endif
+
+//#include <sys/mman.h>
+
+#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 <config.h>
+#endif
+
+#include <sys/mman.h>
+
+#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); */
+}