forked from enlightenment/efl
Begin work on getting evas drm engine to actually render
Signed-off-by: Chris Michael <cp.michael@samsung.com>
This commit is contained in:
parent
a7376722f7
commit
1984303de1
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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); */
|
||||
}
|
Loading…
Reference in New Issue