From fac8ec4ca75d068ded0ef0f8fb4c78bb74e0c8aa Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Mon, 19 Nov 2012 13:43:48 +0000 Subject: [PATCH] this is the START of something.. disabled at runtime for now - the swapper infra is intended to have the ability to map pixels of backbuffers right in for total zero-copy updates. SVN revision: 79452 --- src/Makefile_Evas.am | 14 +- .../evas/engines/software_x11/evas_engine.c | 386 +++++++++--- .../evas/engines/software_x11/evas_engine.h | 9 + .../engines/software_x11/evas_xcb_outbuf.c | 2 + .../engines/software_x11/evas_xlib_outbuf.c | 13 +- .../engines/software_x11/evas_xlib_swapbuf.c | 549 ++++++++++++++++++ .../engines/software_x11/evas_xlib_swapbuf.h | 53 ++ .../engines/software_x11/evas_xlib_swapper.c | 281 +++++++++ .../engines/software_x11/evas_xlib_swapper.h | 15 + 9 files changed, 1224 insertions(+), 98 deletions(-) create mode 100644 src/modules/evas/engines/software_x11/evas_xlib_swapbuf.c create mode 100644 src/modules/evas/engines/software_x11/evas_xlib_swapbuf.h create mode 100644 src/modules/evas/engines/software_x11/evas_xlib_swapper.c create mode 100644 src/modules/evas/engines/software_x11/evas_xlib_swapper.h diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 05a1150112..a7f4702107 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -1007,6 +1007,7 @@ if BUILD_ENGINE_SOFTWARE_X11 dist_installed_evasmainheaders_DATA += modules/evas/engines/software_x11/Evas_Engine_Software_X11.h SOFTWARE_X11_SOURCES = \ modules/evas/engines/software_x11/evas_engine.c \ +modules/evas/engines/software_x11/evas_engine.h \ modules/evas/engines/software_x11/evas_x_egl.c \ modules/evas/engines/software_x11/evas_x_egl.h SOFTWARE_X11_CPPFLAGS = \ @@ -1025,10 +1026,17 @@ SOFTWARE_X11_CPPFLAGS = \ SOFTWARE_X11_LIBADD = if BUILD_ENGINE_SOFTWARE_XLIB SOFTWARE_X11_SOURCES += \ +modules/evas/engines/software_x11/evas_xlib_swapbuf.c \ modules/evas/engines/software_x11/evas_xlib_outbuf.c \ modules/evas/engines/software_x11/evas_xlib_buffer.c \ modules/evas/engines/software_x11/evas_xlib_color.c \ -modules/evas/engines/software_x11/evas_xlib_main.c +modules/evas/engines/software_x11/evas_xlib_main.c \ +modules/evas/engines/software_x11/evas_xlib_swapper.c \ +modules/evas/engines/software_x11/evas_xlib_outbuf.h \ +modules/evas/engines/software_x11/evas_xlib_swapbuf.h \ +modules/evas/engines/software_x11/evas_xlib_buffer.h \ +modules/evas/engines/software_x11/evas_xlib_color.h \ +modules/evas/engines/software_x11/evas_xlib_swapper.h SOFTWARE_X11_CPPFLAGS += @evas_engine_software_xlib_cflags@ SOFTWARE_X11_LIBADD += @evas_engine_software_xlib_libs@ endif @@ -1039,10 +1047,6 @@ modules/evas/engines/software_x11/evas_xcb_outbuf.c \ modules/evas/engines/software_x11/evas_xcb_buffer.c \ modules/evas/engines/software_x11/evas_xcb_color.c \ modules/evas/engines/software_x11/evas_xcb_main.c \ -modules/evas/engines/software_x11/evas_engine.h \ -modules/evas/engines/software_x11/evas_xlib_outbuf.h \ -modules/evas/engines/software_x11/evas_xlib_buffer.h \ -modules/evas/engines/software_x11/evas_xlib_color.h \ modules/evas/engines/software_x11/evas_xcb_outbuf.h \ modules/evas/engines/software_x11/evas_xcb_buffer.h \ modules/evas/engines/software_x11/evas_xcb_color.h \ diff --git a/src/modules/evas/engines/software_x11/evas_engine.c b/src/modules/evas/engines/software_x11/evas_engine.c index 0ac8bb14ed..accbc25aee 100644 --- a/src/modules/evas/engines/software_x11/evas_engine.c +++ b/src/modules/evas/engines/software_x11/evas_engine.c @@ -6,6 +6,7 @@ #ifdef BUILD_ENGINE_SOFTWARE_XLIB # include "evas_xlib_outbuf.h" +# include "evas_xlib_swapbuf.h" # include "evas_xlib_color.h" #endif @@ -30,8 +31,11 @@ struct _Render_Engine Tilebuf *tb; Outbuf *ob; Tilebuf_Rect *rects; + Tilebuf_Rect *rects_prev[3]; Eina_Inlist *cur_rect; + short mode; unsigned char end : 1; + unsigned char lost_back : 1; void (*outbuf_free)(Outbuf *ob); void (*outbuf_reconfigure)(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth); int (*outbuf_get_rot)(Outbuf *ob); @@ -40,6 +44,7 @@ struct _Render_Engine void (*outbuf_free_region_for_update)(Outbuf *ob, RGBA_Image *update); void (*outbuf_flush)(Outbuf *ob); void (*outbuf_idle_flush)(Outbuf *ob); + int (*outbuf_swap_mode_get)(Outbuf *ob); Eina_Bool (*outbuf_alpha_get)(Outbuf *ob); struct { @@ -72,6 +77,7 @@ static void eng_output_idle_flush(void *data); #ifdef BUILD_ENGINE_SOFTWARE_XLIB +/* static void * _output_egl_setup(int w, int h, int rot, Display *disp, Drawable draw, Visual *vis, Colormap cmap, int depth, int debug, @@ -129,12 +135,12 @@ _output_egl_setup(int w, int h, int rot, Display *disp, Drawable draw, return NULL; } - /* in preliminary tests 16x16 gave highest framerates */ evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE); return re; debug = 0; } +*/ static void _output_egl_shutdown(Render_Engine *re) @@ -157,7 +163,7 @@ _output_xlib_setup(int w, int h, int rot, Display *disp, Drawable draw, evas_software_xlib_x_init(); evas_software_xlib_x_color_init(); evas_software_xlib_outbuf_init(); - + re->ob = evas_software_xlib_outbuf_setup_x(w, h, rot, OUTBUF_DEPTH_INHERIT, disp, draw, vis, cmap, depth, grayscale, @@ -192,6 +198,44 @@ _output_xlib_setup(int w, int h, int rot, Display *disp, Drawable draw, evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE); return re; } + +static void * +_output_swapbuf_setup(int w, int h, int rot, Display *disp, Drawable draw, + Visual *vis, Colormap cmap, int depth, + int debug EINA_UNUSED, + int grayscale, int max_colors, Pixmap mask, + int shape_dither, int destination_alpha) +{ + Render_Engine *re; + + if (!(re = calloc(1, sizeof(Render_Engine)))) return NULL; + + evas_software_xlib_x_init(); + evas_software_xlib_x_color_init(); + evas_software_xlib_swapbuf_init(); + + re->ob = + evas_software_xlib_swapbuf_setup_x(w, h, rot, OUTBUF_DEPTH_INHERIT, disp, + draw, vis, cmap, depth, grayscale, + max_colors, mask, shape_dither, + destination_alpha); + if (!re->ob) + { + free(re); + return NULL; + } + + re->tb = evas_common_tilebuf_new(w, h); + if (!re->tb) + { + evas_software_xlib_swapbuf_free(re->ob); + free(re); + return NULL; + } + + evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE); + return re; +} #endif #ifdef BUILD_ENGINE_SOFTWARE_XCB @@ -409,29 +453,34 @@ eng_setup(Evas *eo_e, void *in) #ifdef BUILD_ENGINE_SOFTWARE_XLIB if (info->info.backend == EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB) { - re = _output_egl_setup(e->output.w, e->output.h, - info->info.rotation, info->info.connection, - info->info.drawable, info->info.visual, - info->info.colormap, - info->info.depth, info->info.debug, - info->info.alloc_grayscale, - info->info.alloc_colors_max, - info->info.mask, info->info.shape_dither, - info->info.destination_alpha); + // this is disabled for now as we should only use/need the + // swapper infra *IF* we can get direct access to the "backbuffer" + // of a window in x11. + if (0) + re = _output_swapbuf_setup(e->output.w, e->output.h, + info->info.rotation, info->info.connection, + info->info.drawable, info->info.visual, + info->info.colormap, + info->info.depth, info->info.debug, + info->info.alloc_grayscale, + info->info.alloc_colors_max, + info->info.mask, info->info.shape_dither, + info->info.destination_alpha); if (re) { - // XXX these need to provide egl functions not xlib - re->outbuf_free = evas_software_xlib_outbuf_free; - re->outbuf_reconfigure = evas_software_xlib_outbuf_reconfigure; - re->outbuf_get_rot = evas_software_xlib_outbuf_get_rot; - re->outbuf_new_region_for_update = evas_software_xlib_outbuf_new_region_for_update; - re->outbuf_push_updated_region = evas_software_xlib_outbuf_push_updated_region; - re->outbuf_free_region_for_update = evas_software_xlib_outbuf_free_region_for_update; - re->outbuf_flush = evas_software_xlib_outbuf_flush; - re->outbuf_idle_flush = evas_software_xlib_outbuf_idle_flush; - re->outbuf_alpha_get = evas_software_xlib_outbuf_alpha_get; + re->outbuf_free = evas_software_xlib_swapbuf_free; + re->outbuf_reconfigure = evas_software_xlib_swapbuf_reconfigure; + re->outbuf_get_rot = evas_software_xlib_swapbuf_get_rot; + re->outbuf_new_region_for_update = evas_software_xlib_swapbuf_new_region_for_update; + re->outbuf_push_updated_region = evas_software_xlib_swapbuf_push_updated_region; + re->outbuf_free_region_for_update = evas_software_xlib_swapbuf_free_region_for_update; + re->outbuf_flush = evas_software_xlib_swapbuf_flush; + re->outbuf_idle_flush = evas_software_xlib_swapbuf_idle_flush; + re->outbuf_alpha_get = evas_software_xlib_swapbuf_alpha_get; + re->outbuf_swap_mode_get = evas_software_xlib_swapbuf_buffer_state_get; } - else + + if (!re) { re = _output_xlib_setup(e->output.w, e->output.h, info->info.rotation, info->info.connection, @@ -443,15 +492,16 @@ eng_setup(Evas *eo_e, void *in) info->info.mask, info->info.shape_dither, info->info.destination_alpha); - re->outbuf_free = evas_software_xlib_outbuf_free; - re->outbuf_reconfigure = evas_software_xlib_outbuf_reconfigure; - re->outbuf_get_rot = evas_software_xlib_outbuf_get_rot; - re->outbuf_new_region_for_update = evas_software_xlib_outbuf_new_region_for_update; - re->outbuf_push_updated_region = evas_software_xlib_outbuf_push_updated_region; + re->outbuf_free = evas_software_xlib_outbuf_free; + re->outbuf_reconfigure = evas_software_xlib_outbuf_reconfigure; + re->outbuf_get_rot = evas_software_xlib_outbuf_get_rot; + re->outbuf_new_region_for_update = evas_software_xlib_outbuf_new_region_for_update; + re->outbuf_push_updated_region = evas_software_xlib_outbuf_push_updated_region; re->outbuf_free_region_for_update = evas_software_xlib_outbuf_free_region_for_update; - re->outbuf_flush = evas_software_xlib_outbuf_flush; - re->outbuf_idle_flush = evas_software_xlib_outbuf_idle_flush; - re->outbuf_alpha_get = evas_software_xlib_outbuf_alpha_get; + re->outbuf_flush = evas_software_xlib_outbuf_flush; + re->outbuf_idle_flush = evas_software_xlib_outbuf_idle_flush; + re->outbuf_alpha_get = evas_software_xlib_outbuf_alpha_get; + re->outbuf_swap_mode_get = NULL; } } #endif @@ -469,18 +519,16 @@ eng_setup(Evas *eo_e, void *in) info->info.mask, info->info.shape_dither, info->info.destination_alpha); - re->outbuf_free = evas_software_xcb_outbuf_free; - re->outbuf_reconfigure = evas_software_xcb_outbuf_reconfigure; - re->outbuf_get_rot = evas_software_xcb_outbuf_rotation_get; - re->outbuf_new_region_for_update = - evas_software_xcb_outbuf_new_region_for_update; - re->outbuf_push_updated_region = - evas_software_xcb_outbuf_push_updated_region; - re->outbuf_free_region_for_update = - evas_software_xcb_outbuf_free_region_for_update; - re->outbuf_flush = evas_software_xcb_outbuf_flush; - re->outbuf_idle_flush = evas_software_xcb_outbuf_idle_flush; - re->outbuf_alpha_get = evas_software_xcb_outbuf_alpha_get; + re->outbuf_free = evas_software_xcb_outbuf_free; + re->outbuf_reconfigure = evas_software_xcb_outbuf_reconfigure; + re->outbuf_get_rot = evas_software_xcb_outbuf_rotation_get; + re->outbuf_new_region_for_update = evas_software_xcb_outbuf_new_region_for_update; + re->outbuf_push_updated_region = evas_software_xcb_outbuf_push_updated_region; + re->outbuf_free_region_for_update = evas_software_xcb_outbuf_free_region_for_update; + re->outbuf_flush = evas_software_xcb_outbuf_flush; + re->outbuf_idle_flush = evas_software_xcb_outbuf_idle_flush; + re->outbuf_alpha_get = evas_software_xcb_outbuf_alpha_get; + re->outbuf_swap_mode_get = NULL; } #endif @@ -491,29 +539,49 @@ eng_setup(Evas *eo_e, void *in) int ponebuf = 0; re = e->engine.data.output; - ponebuf = re->ob->onebuf; + if ((re) && (re->ob)) ponebuf = re->ob->onebuf; #ifdef BUILD_ENGINE_SOFTWARE_XLIB if (info->info.backend == EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB) { - // XXXX do egl stuff as above - evas_software_xlib_outbuf_free(re->ob); - re->ob = - evas_software_xlib_outbuf_setup_x(e->output.w, e->output.h, - info->info.rotation, - OUTBUF_DEPTH_INHERIT, - info->info.connection, - info->info.drawable, - info->info.visual, - info->info.colormap, - info->info.depth, - info->info.alloc_grayscale, - info->info.alloc_colors_max, - info->info.mask, - info->info.shape_dither, - info->info.destination_alpha); + // XXX + re->outbuf_free(re->ob); - evas_software_xlib_outbuf_debug_set(re->ob, info->info.debug); + if (re->outbuf_free == evas_software_xlib_swapbuf_free) + { + re->ob = + evas_software_xlib_swapbuf_setup_x(e->output.w, e->output.h, + info->info.rotation, + OUTBUF_DEPTH_INHERIT, + info->info.connection, + info->info.drawable, + info->info.visual, + info->info.colormap, + info->info.depth, + info->info.alloc_grayscale, + info->info.alloc_colors_max, + info->info.mask, + info->info.shape_dither, + info->info.destination_alpha); + } + else + { + re->ob = + evas_software_xlib_outbuf_setup_x(e->output.w, e->output.h, + info->info.rotation, + OUTBUF_DEPTH_INHERIT, + info->info.connection, + info->info.drawable, + info->info.visual, + info->info.colormap, + info->info.depth, + info->info.alloc_grayscale, + info->info.alloc_colors_max, + info->info.mask, + info->info.shape_dither, + info->info.destination_alpha); + evas_software_xlib_outbuf_debug_set(re->ob, info->info.debug); + } } #endif @@ -536,11 +604,10 @@ eng_setup(Evas *eo_e, void *in) info->info.mask, info->info.shape_dither, info->info.destination_alpha); - evas_software_xcb_outbuf_debug_set(re->ob, info->info.debug); } #endif - re->ob->onebuf = ponebuf; + if ((re) && (re->ob)) re->ob->onebuf = ponebuf; } if (!e->engine.data.output) return 0; if (!e->engine.data.context) @@ -564,6 +631,9 @@ eng_output_free(void *data) re->outbuf_free(re->ob); evas_common_tilebuf_free(re->tb); if (re->rects) evas_common_tilebuf_free_render_rects(re->rects); + if (re->rects_prev[0]) evas_common_tilebuf_free_render_rects(re->rects_prev[0]); + if (re->rects_prev[1]) evas_common_tilebuf_free_render_rects(re->rects_prev[1]); + if (re->rects_prev[2]) evas_common_tilebuf_free_render_rects(re->rects_prev[2]); _output_egl_shutdown(re); free(re); } @@ -622,41 +692,189 @@ eng_output_redraws_clear(void *data) evas_common_tilebuf_clear(re->tb); } +static Tilebuf_Rect * +_merge_rects(Tilebuf *tb, Tilebuf_Rect *r1, Tilebuf_Rect *r2, Tilebuf_Rect *r3) +{ + Tilebuf_Rect *r, *rects; + int x1, y1, x2, y2; + + 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 (r2) + { + 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) + { + x1 = rects->x; y1 = rects->y; + x2 = rects->x + rects->w; y2 = rects->y + rects->h; + EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r) + { + if (r->x < x1) x1 = r->x; + if (r->y < y1) y1 = r->y; + if ((r->x + r->w) > x2) x2 = r->x + r->w; + if ((r->y + r->h) > y2) y2 = r->y + r->h; + } + evas_common_tilebuf_free_render_rects(rects); + rects = calloc(1, sizeof(Tilebuf_Rect)); + if (rects) + { + rects->x = x1; + rects->y = y1; + rects->w = x2 - x1; + rects->h = y2 - y1; + } + } + */ + evas_common_tilebuf_clear(tb); + return rects; +} + + 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; - int ux, uy, uw, uh; + Eina_Bool first_rect = EINA_FALSE; + int i; +#define CLEAR_PREV_RECTS(x) \ + do { \ + if (re->rects_prev[i]) \ + evas_common_tilebuf_free_render_rects(re->rects_prev[i]); \ + re->rects_prev[i] = NULL; \ + } while (0) + re = (Render_Engine *)data; if (re->end) { re->end = 0; return NULL; } + if (!re->rects) { + int mode = MODE_COPY; + + if (re->outbuf_swap_mode_get) mode = re->outbuf_swap_mode_get(re->ob); + re->mode = mode; re->rects = evas_common_tilebuf_get_render_rects(re->tb); - re->cur_rect = EINA_INLIST_GET(re->rects); + if (re->rects) + { + if (re->lost_back) + { + /* 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 */ + switch (re->mode) + { + case MODE_FULL: + case MODE_COPY: // no prev rects needed + for (i = 0; i < 3; i++) CLEAR_PREV_RECTS(i); + break; + case MODE_DOUBLE: // double mode - only 1 level of prev rect + for (i = 1; i < 3; i++) CLEAR_PREV_RECTS(i); + re->rects_prev[1] = re->rects_prev[0]; + re->rects_prev[0] = re->rects; + // merge prev[1] + prev[0] -> rects + re->rects = _merge_rects(re->tb, re->rects_prev[0], re->rects_prev[1], NULL); + break; + case MODE_TRIPLE: // keep all + for (i = 2; i < 3; i++) CLEAR_PREV_RECTS(i); + re->rects_prev[2] = re->rects_prev[1]; + re->rects_prev[1] = re->rects_prev[0]; + re->rects_prev[0] = re->rects; + re->rects = NULL; + // merge prev[2] + prev[1] + prev[0] -> rects + re->rects = _merge_rects(re->tb, re->rects_prev[0], re->rects_prev[1], re->rects_prev[2]); + break; + default: + break; + } + re->cur_rect = EINA_INLIST_GET(re->rects); + 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; - ux = rect->x; uy = rect->y; uw = rect->w; uh = rect->h; - re->cur_rect = re->cur_rect->next; - if (!re->cur_rect) + if (re->rects) { - evas_common_tilebuf_free_render_rects(re->rects); - re->rects = NULL; - re->end = 1; + 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 fir the first frame + } + surface = + re->outbuf_new_region_for_update(re->ob, + *x, *y, *w, *h, + cx, cy, cw, ch); + if (!re->cur_rect) + { + re->end = 1; + } + return surface; } - - surface = - re->outbuf_new_region_for_update(re->ob, ux, uy, uw, uh, cx, cy, cw, ch); - - *x = ux; *y = uy; *w = uw; *h = uh; - return surface; + return NULL; } static void @@ -668,7 +886,6 @@ eng_output_redraws_next_update_push(void *data, void *surface, int x, int y, int #if defined(BUILD_PIPE_RENDER) evas_common_pipe_map_begin(surface); #endif /* BUILD_PIPE_RENDER */ - re->outbuf_push_updated_region(re->ob, surface, x, y, w, h); re->outbuf_free_region_for_update(re->ob, surface); evas_common_cpu_end_opt(); @@ -681,6 +898,11 @@ eng_output_flush(void *data) re = (Render_Engine *)data; re->outbuf_flush(re->ob); + if (re->rects) + { + evas_common_tilebuf_free_render_rects(re->rects); + re->rects = NULL; + } } static void @@ -706,16 +928,6 @@ eng_canvas_alpha_get(void *data, void *context EINA_UNUSED) static int module_open(Evas_Module *em) { -#ifdef BUILD_ENGINE_SOFTWARE_XLIB - static Eina_Bool xrm_inited = EINA_FALSE; - - if (!xrm_inited) - { - xrm_inited = EINA_TRUE; - XrmInitialize(); - } -#endif - if (!em) return 0; /* get whatever engine module we inherit from */ diff --git a/src/modules/evas/engines/software_x11/evas_engine.h b/src/modules/evas/engines/software_x11/evas_engine.h index 73a62bccdf..82d2d1f57c 100644 --- a/src/modules/evas/engines/software_x11/evas_engine.h +++ b/src/modules/evas/engines/software_x11/evas_engine.h @@ -60,6 +60,13 @@ enum _Outbuf_Depth OUTBUF_DEPTH_LAST }; +enum { + MODE_FULL, + MODE_COPY, + MODE_DOUBLE, + MODE_TRIPLE +}; + typedef struct _Outbuf Outbuf; struct _Outbuf @@ -112,6 +119,8 @@ struct _Outbuf /* 1 big buffer for updates - flush on idle_flush */ RGBA_Image *onebuf; Eina_Array onebuf_regions; + + void *swapper; /* a list of pending regions to write to the target */ Eina_List *pending_writes; diff --git a/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c b/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c index 9b0079f34f..eb0dcfc2ef 100644 --- a/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c +++ b/src/modules/evas/engines/software_x11/evas_xcb_outbuf.c @@ -93,6 +93,8 @@ evas_software_xcb_outbuf_setup(int w, int h, int rot, Outbuf_Depth depth, xcb_co if (!(buf = calloc(1, sizeof(Outbuf)))) return NULL; + if (xdepth < 15) rot = 0; + setup = xcb_get_setup(conn); buf->w = w; diff --git a/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c b/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c index 47763c43a1..7cc1cf0e40 100644 --- a/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c +++ b/src/modules/evas/engines/software_x11/evas_xlib_outbuf.c @@ -14,7 +14,6 @@ #include "evas_xlib_buffer.h" #include "evas_xlib_color.h" - typedef struct _Outbuf_Region Outbuf_Region; struct _Outbuf_Region @@ -188,10 +187,10 @@ evas_software_xlib_outbuf_free(Outbuf *buf) Outbuf * evas_software_xlib_outbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth, - Display *disp, Drawable draw, Visual *vis, - Colormap cmap, int x_depth, - int grayscale, int max_colors, Pixmap mask, - int shape_dither, int destination_alpha) + Display *disp, Drawable draw, Visual *vis, + Colormap cmap, int x_depth, + int grayscale, int max_colors, Pixmap mask, + int shape_dither, int destination_alpha) { Outbuf *buf; @@ -199,6 +198,8 @@ evas_software_xlib_outbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth, if (!buf) return NULL; + if (x_depth < 15) rot = 0; + buf->w = w; buf->h = h; buf->depth = depth; @@ -214,7 +215,7 @@ evas_software_xlib_outbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth, eina_array_step_set(&buf->priv.onebuf_regions, sizeof (Eina_Array), 8); - { + { Gfx_Func_Convert conv_func; X_Output_Buffer *xob; diff --git a/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.c b/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.c new file mode 100644 index 0000000000..95c1626c5f --- /dev/null +++ b/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.c @@ -0,0 +1,549 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#ifdef EVAS_CSERVE2 +#include "evas_cs2_private.h" +#endif +#include "evas_common.h" +#include "evas_macros.h" + +#include "evas_xlib_swapbuf.h" +#include "evas_xlib_color.h" +#include "evas_xlib_swapper.h" + +typedef struct _Outbuf_Region Outbuf_Region; + +struct _Outbuf_Region +{ + RGBA_Image *im; + int x; + int y; + int w; + int h; +}; + +void +evas_software_xlib_swapbuf_init(void) +{ +} + +void +evas_software_xlib_swapbuf_free(Outbuf *buf) +{ + evas_software_xlib_swapbuf_flush(buf); + evas_software_xlib_swapbuf_idle_flush(buf); + if (buf->priv.pal) + evas_software_xlib_x_color_deallocate + (buf->priv.x11.xlib.disp, buf->priv.x11.xlib.cmap, + buf->priv.x11.xlib.vis, buf->priv.pal); + eina_array_flush(&buf->priv.onebuf_regions); + free(buf); +} + +Outbuf * +evas_software_xlib_swapbuf_setup_x(int w, int h, int rot, Outbuf_Depth depth, + Display *disp, Drawable draw, Visual *vis, + Colormap cmap, int x_depth, + int grayscale, int max_colors, Pixmap mask, + int shape_dither, int destination_alpha) +{ + Outbuf *buf; + Gfx_Func_Convert conv_func = NULL; + int d; + + buf = calloc(1, sizeof(Outbuf)); + if (!buf) return NULL; + + if (x_depth < 15) rot = 0; + + buf->onebuf = 1; + buf->w = w; + buf->h = h; + buf->depth = depth; + buf->rot = rot; + buf->priv.x11.xlib.disp = disp; + buf->priv.x11.xlib.win = draw; + buf->priv.x11.xlib.vis = vis; + buf->priv.x11.xlib.cmap = cmap; + buf->priv.x11.xlib.depth = x_depth; + buf->priv.mask_dither = shape_dither; + buf->priv.destination_alpha = destination_alpha; + + if ((buf->rot == 0) || (buf->rot == 180)) + buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp, + buf->priv.x11.xlib.win, + buf->priv.x11.xlib.vis, + buf->priv.x11.xlib.depth, + buf->w, buf->h); + else if ((buf->rot == 90) || (buf->rot == 270)) + buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp, + buf->priv.x11.xlib.win, + buf->priv.x11.xlib.vis, + buf->priv.x11.xlib.depth, + buf->h, buf->w); + if (!buf->priv.swapper) + { + free(buf); + return NULL; + } + + eina_array_step_set(&buf->priv.onebuf_regions, sizeof (Eina_Array), 8); + +#ifdef WORDS_BIGENDIAN + if (evas_xlib_swapper_byte_order_get(buf->priv.swapper) == LSBFirst) + buf->priv.x11.xlib.swap = 1; + if (evas_xlib_swapper_bit_order_get(buf->priv.swapper) == MSBFirst) + buf->priv.x11.xlib.bit_swap = 1; +#else + if (evas_xlib_swapper_byte_order_get(buf->priv.swapper) == MSBFirst) + buf->priv.x11.xlib.swap = 1; + if (evas_xlib_swapper_bit_order_get(buf->priv.swapper) == MSBFirst) + buf->priv.x11.xlib.bit_swap = 1; +#endif + if (((vis->class == TrueColor) || (vis->class == DirectColor)) && + (x_depth > 8)) + { + buf->priv.mask.r = (DATA32) vis->red_mask; + buf->priv.mask.g = (DATA32) vis->green_mask; + buf->priv.mask.b = (DATA32) vis->blue_mask; + if (buf->priv.x11.xlib.swap) + { + SWAP32(buf->priv.mask.r); + SWAP32(buf->priv.mask.g); + SWAP32(buf->priv.mask.b); + } + } + else if ((vis->class == PseudoColor) || (vis->class == StaticColor) || + (vis->class == GrayScale) || (vis->class == StaticGray) || + (x_depth <= 8)) + { + Convert_Pal_Mode pm = PAL_MODE_RGB332; + + if ((vis->class == GrayScale) || (vis->class == StaticGray)) + grayscale = 1; + if (grayscale) + { + if (max_colors >= 256) pm = PAL_MODE_GRAY256; + else if (max_colors >= 64) pm = PAL_MODE_GRAY64; + else if (max_colors >= 16) pm = PAL_MODE_GRAY16; + else if (max_colors >= 4) pm = PAL_MODE_GRAY4; + else pm = PAL_MODE_MONO; + } + else + { + if (max_colors >= 256) pm = PAL_MODE_RGB332; + else if (max_colors >= 216) pm = PAL_MODE_RGB666; + else if (max_colors >= 128) pm = PAL_MODE_RGB232; + else if (max_colors >= 64) pm = PAL_MODE_RGB222; + else if (max_colors >= 32) pm = PAL_MODE_RGB221; + else if (max_colors >= 16) pm = PAL_MODE_RGB121; + else if (max_colors >= 8) pm = PAL_MODE_RGB111; + else if (max_colors >= 4) pm = PAL_MODE_GRAY4; + else pm = PAL_MODE_MONO; + } + /* FIXME: only alloc once per display+cmap */ + buf->priv.pal = evas_software_xlib_x_color_allocate + (disp, cmap, vis, pm); + if (!buf->priv.pal) + { + evas_xlib_swapper_free(buf->priv.swapper); + free(buf); + return NULL; + } + } + d = evas_xlib_swapper_depth_get(buf->priv.swapper); + if (buf->priv.pal) + { + + if (buf->rot == 0 || buf->rot == 180) + conv_func = evas_common_convert_func_get(0, buf->w, buf->h, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + buf->priv.pal->colors, + buf->rot); + else if (buf->rot == 90 || buf->rot == 270) + conv_func = evas_common_convert_func_get(0, buf->h, buf->w, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + buf->priv.pal->colors, + buf->rot); + } + else + { + if (buf->rot == 0 || buf->rot == 180) + conv_func = evas_common_convert_func_get(0, buf->w, buf->h, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + PAL_MODE_NONE, + buf->rot); + else if (buf->rot == 90 || buf->rot == 270) + conv_func = evas_common_convert_func_get(0, buf->h, buf->w, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + PAL_MODE_NONE, + buf->rot); + } + if (!conv_func) + { + ERR("At depth: %i, RGB format mask: %08x %08x %08x, " + "Palette mode: %i. " + "Not supported by compiled in converters!", + buf->priv.x11.xlib.depth, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + buf->priv.pal ? (int)buf->priv.pal->colors : -1); + } + return buf; +} + +RGBA_Image * +evas_software_xlib_swapbuf_new_region_for_update(Outbuf *buf, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch) +{ + RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, buf->w, buf->h); + if ((w <= 0) || (h <= 0)) return NULL; + // if rotation is 0, and 32bit argb, we can use the buffer directly + if ((buf->rot == 0) && + (buf->priv.mask.r == 0xff0000) && + (buf->priv.mask.g == 0x00ff00) && + (buf->priv.mask.b == 0x0000ff)) + { + RGBA_Image *im; + void *data; + int bpl = 0; + Eina_Rectangle *rect; + + im = buf->priv.onebuf; + if (!im) + { + data = evas_xlib_swapper_buffer_map(buf->priv.swapper, &bpl); +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + im = (RGBA_Image *)evas_cache2_image_data(evas_common_image_cache2_get(), + buf->w, buf->h, data, + buf->priv.destination_alpha, + EVAS_COLORSPACE_ARGB8888); + else +#endif + im = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(), + buf->w, buf->h, data, + buf->priv.destination_alpha, + EVAS_COLORSPACE_ARGB8888); + buf->priv.onebuf = im; + if (!im) return NULL; + } + rect = eina_rectangle_new(x, y, w, h); + if (!eina_array_push(&buf->priv.onebuf_regions, rect)) + { +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&im->cache_entry); + else +#endif + evas_cache_image_drop(&im->cache_entry); + return NULL; + } + + // the clip region of the onebuf to render + *cx = x; + *cy = y; + *cw = w; + *ch = h; + return im; + } + else + { + RGBA_Image *im; + Eina_Rectangle *rect; + + rect = eina_rectangle_new(x, y, w, h); + if (!rect) return NULL; +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + im = (RGBA_Image *)evas_cache2_image_empty(evas_common_image_cache2_get()); + else +#endif + im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get()); + if (!im) + { + free(rect); + return NULL; + } + im->cache_entry.flags.alpha |= buf->priv.destination_alpha ? 1 : 0; +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_surface_alloc(&im->cache_entry, w, h); + else +#endif + evas_cache_image_surface_alloc(&im->cache_entry, w, h); + im->extended_info = rect; + buf->priv.pending_writes = eina_list_append(buf->priv.pending_writes, im); + + // the region is the update image + *cx = 0; + *cy = 0; + *cw = w; + *ch = h; + return im; + } + return NULL; +} + +void +evas_software_xlib_swapbuf_free_region_for_update(Outbuf *buf EINA_UNUSED, RGBA_Image *update EINA_UNUSED) +{ + /* no need to do anything - they are cleaned up on flush */ +} + +void +evas_software_xlib_swapbuf_flush(Outbuf *buf) +{ + if (!buf->priv.pending_writes) + { + Eina_Rectangle *rects, *rect; + Eina_Array_Iterator it; + unsigned int n, i; + RGBA_Image *im; + + n = eina_array_count_get(&buf->priv.onebuf_regions); + if (n == 0) return; + rects = alloca(n * sizeof(Eina_Rectangle)); + EINA_ARRAY_ITER_NEXT(&buf->priv.onebuf_regions, i, rect, it) + { + rects[i] = *rect; + } + evas_xlib_swapper_buffer_unmap(buf->priv.swapper); + evas_xlib_swapper_swap(buf->priv.swapper, rects, n); + eina_array_clean(&buf->priv.onebuf_regions); + im = buf->priv.onebuf; + buf->priv.onebuf = NULL; + if (im) + { +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&im->cache_entry); + else +#endif + evas_cache_image_drop(&im->cache_entry); + } + } + else + { + RGBA_Image *im; + Eina_Rectangle *rects; + unsigned int n, i = 0; + + n = eina_list_count(buf->priv.pending_writes); + if (n == 0) return; + rects = alloca(n * sizeof(Eina_Rectangle)); + EINA_LIST_FREE(buf->priv.pending_writes, im) + { + Eina_Rectangle *rect = im->extended_info; + int x, y, w, h; + + x = rect->x; y = rect->y; w = rect->w; h = rect->h; + rects[i] = *rect; + if (buf->rot == 0) + { + rects[i].x = x; + rects[i].y = y; + } + else if (buf->rot == 90) + { + rects[i].x = y; + rects[i].y = buf->w - x - w; + } + else if (buf->rot == 180) + { + rects[i].x = buf->w - x - w; + rects[i].y = buf->h - y - h; + } + else if (buf->rot == 270) + { + rects[i].x = buf->h - y - h; + rects[i].y = x; + } + if ((buf->rot == 0) || (buf->rot == 180)) + { + rects[i].w = w; + rects[i].h = h; + } + else if ((buf->rot == 90) || (buf->rot == 270)) + { + rects[i].w = h; + rects[i].h = w; + } + free(rect); +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&im->cache_entry); + else +#endif + evas_cache_image_drop(&im->cache_entry); + } + evas_xlib_swapper_buffer_unmap(buf->priv.swapper); + evas_xlib_swapper_swap(buf->priv.swapper, rects, n); +// evas_xlib_swapper_swap(buf->priv.swapper, NULL, 0); + } +} + +void +evas_software_xlib_swapbuf_idle_flush(Outbuf *buf) +{ + return; + buf = NULL; +} + +void +evas_software_xlib_swapbuf_push_updated_region(Outbuf *buf, RGBA_Image *update, int x, int y, int w, int h) +{ + Gfx_Func_Convert conv_func = NULL; + Eina_Rectangle r = { 0, 0, 0, 0 }; + int d, bpl = 0, wid, bpp; + DATA32 *src_data; + DATA8 *dst_data; + + if (!buf->priv.pending_writes) return; + d = evas_xlib_swapper_depth_get(buf->priv.swapper); + if (buf->priv.pal) + { + if ((buf->rot == 0) || (buf->rot == 180)) + conv_func = evas_common_convert_func_get(0, w, h, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + buf->priv.pal->colors, + buf->rot); + else if ((buf->rot == 90) || (buf->rot == 270)) + conv_func = evas_common_convert_func_get(0, h, w, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + buf->priv.pal->colors, + buf->rot); + } + else + { + if ((buf->rot == 0) || (buf->rot == 180)) + conv_func = evas_common_convert_func_get(0, w, h, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + PAL_MODE_NONE, + buf->rot); + else if ((buf->rot == 90) || (buf->rot == 270)) + conv_func = evas_common_convert_func_get(0, h, w, d, + buf->priv.mask.r, + buf->priv.mask.g, + buf->priv.mask.b, + PAL_MODE_NONE, + buf->rot); + } + if (!conv_func) return; + if (buf->rot == 0) + { + r.x = x; + r.y = y; + } + else if (buf->rot == 90) + { + r.x = y; + r.y = buf->w - x - w; + } + else if (buf->rot == 180) + { + r.x = buf->w - x - w; + r.y = buf->h - y - h; + } + else if (buf->rot == 270) + { + r.x = buf->h - y - h; + r.y = x; + } + if ((buf->rot == 0) || (buf->rot == 180)) + { + r.w = w; + r.h = h; + } + else if ((buf->rot == 90) || (buf->rot == 270)) + { + r.w = h; + r.h = w; + } + src_data = update->image.data; + if (!src_data) return; + dst_data = evas_xlib_swapper_buffer_map(buf->priv.swapper, &bpl); + if (!dst_data) return; + bpp = d / 8; + if (bpp <= 0) return; + wid = bpl / bpp; + dst_data += (bpl * r.y) + (r.x * bpp); + if (buf->priv.pal) + conv_func(src_data, dst_data, + update->cache_entry.w - w, + wid - r.w, + r.w, r.h, + x, y, + buf->priv.pal->lookup); + else + conv_func(src_data, dst_data, + update->cache_entry.w - w, + wid - r.w, + r.w, r.h, + x, y, + NULL); +} + +void +evas_software_xlib_swapbuf_reconfigure(Outbuf *buf, int w, int h, int rot, + Outbuf_Depth depth) +{ + if ((w == buf->w) && (h == buf->h) && (rot == buf->rot) && + (depth == buf->depth)) + return; + buf->w = w; + buf->h = h; + buf->rot = rot; + evas_xlib_swapper_free(buf->priv.swapper); + if ((buf->rot == 0) || (buf->rot == 180)) + buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp, + buf->priv.x11.xlib.win, + buf->priv.x11.xlib.vis, + buf->priv.x11.xlib.depth, + buf->w, buf->h); + else if ((buf->rot == 90) || (buf->rot == 270)) + buf->priv.swapper = evas_xlib_swapper_new(buf->priv.x11.xlib.disp, + buf->priv.x11.xlib.win, + buf->priv.x11.xlib.vis, + buf->priv.x11.xlib.depth, + buf->h, buf->w); +} + +int +evas_software_xlib_swapbuf_get_rot(Outbuf * buf) +{ + return buf->rot; +} + +Eina_Bool +evas_software_xlib_swapbuf_alpha_get(Outbuf *buf) +{ + return buf->priv.destination_alpha; +} + +int +evas_software_xlib_swapbuf_buffer_state_get(Outbuf *buf) +{ + int mode; + if (!buf->priv.swapper) return MODE_FULL; + mode = evas_xlib_swapper_buffer_state_get(buf->priv.swapper); + return mode; +} diff --git a/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.h b/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.h new file mode 100644 index 0000000000..f8276a01e0 --- /dev/null +++ b/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.h @@ -0,0 +1,53 @@ +#ifndef EVAS_XLIB_SWAPBUF_H +#define EVAS_XLIB_SWAPBUF_H + + +#include "evas_engine.h" + + +void evas_software_xlib_swapbuf_init(void); +void evas_software_xlib_swapbuf_free(Outbuf *buf); +Outbuf *evas_software_xlib_swapbuf_setup_x(int w, + int h, + int rot, + Outbuf_Depth depth, + Display *disp, + Drawable draw, + Visual *vis, + Colormap cmap, + int x_depth, + int grayscale, + int max_colors, + Pixmap mask, + int shape_dither, + int destination_alpha); +RGBA_Image *evas_software_xlib_swapbuf_new_region_for_update(Outbuf *buf, + int x, + int y, + int w, + int h, + int *cx, + int *cy, + int *cw, + int *ch); +void evas_software_xlib_swapbuf_free_region_for_update(Outbuf *buf, + RGBA_Image *update); +void evas_software_xlib_swapbuf_flush(Outbuf *buf); +void evas_software_xlib_swapbuf_idle_flush(Outbuf *buf); +void evas_software_xlib_swapbuf_push_updated_region(Outbuf *buf, + RGBA_Image *update, + int x, + int y, + int w, + int h); +void evas_software_xlib_swapbuf_reconfigure(Outbuf *buf, + int w, + int h, + int rot, + Outbuf_Depth depth); +int evas_software_xlib_swapbuf_get_rot(Outbuf *buf); +void evas_software_xlib_swapbuf_rotation_set(Outbuf *buf, + int rot); +Eina_Bool evas_software_xlib_swapbuf_alpha_get(Outbuf *buf); +int evas_software_xlib_swapbuf_buffer_state_get(Outbuf *buf); +#endif diff --git a/src/modules/evas/engines/software_x11/evas_xlib_swapper.c b/src/modules/evas/engines/software_x11/evas_xlib_swapper.c new file mode 100644 index 0000000000..f863a75ad7 --- /dev/null +++ b/src/modules/evas/engines/software_x11/evas_xlib_swapper.c @@ -0,0 +1,281 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "evas_common.h" +#include "evas_macros.h" +#include "evas_xlib_swapper.h" + +typedef struct +{ + XImage *xim; + XShmSegmentInfo shm_info; + void *data; + int w, h, bpl; + Eina_Bool shm : 1; + Eina_Bool valid : 1; +} Buffer; + +struct _X_Swapper +{ + Display *disp; + Drawable draw; + Visual *vis; + GC gc; + Buffer buf[3]; + int w, h, depth; + int buf_cur, buf_num; + Eina_Bool mapped: 1; +}; + +static Eina_Bool _x_err = EINA_FALSE; + +static void +_x_err_hand(Display *d EINA_UNUSED, XErrorEvent *ev EINA_UNUSED) +{ + _x_err = 1; + return; +} + +static Eina_Bool +_buf_new(X_Swapper *swp, Buffer *buf) +{ + buf->w = swp->w; + buf->h = swp->h; + + // try shm first + buf->xim = XShmCreateImage(swp->disp, swp->vis, swp->depth, ZPixmap, + NULL, &(buf->shm_info), buf->w, buf->h); + if (buf->xim) + { + buf->bpl = buf->xim->bytes_per_line; + + buf->shm_info.shmid = shmget(IPC_PRIVATE, buf->bpl * buf->h, + IPC_CREAT | 0777); + if (buf->shm_info.shmid >= 0) + { + buf->shm_info.readOnly = False; + buf->shm_info.shmaddr = buf->data = buf->xim->data = + shmat(buf->shm_info.shmid, 0, 0); + if (buf->shm_info.shmaddr != ((void *)-1)) + { + XErrorHandler ph; + + XSync(swp->disp, False); + _x_err = EINA_FALSE; + ph = XSetErrorHandler((XErrorHandler)_x_err_hand); + XShmAttach(swp->disp, &(buf->shm_info)); + XSync(swp->disp, False); + XSetErrorHandler((XErrorHandler)ph); + if (!_x_err) + { + buf->shm = EINA_TRUE; + } + else + { + shmdt(buf->shm_info.shmaddr); + shmctl(buf->shm_info.shmid, IPC_RMID, 0); + XDestroyImage(buf->xim); + buf->xim = NULL; + } + } + else + { + shmdt(buf->shm_info.shmaddr); + shmctl(buf->shm_info.shmid, IPC_RMID, 0); + XDestroyImage(buf->xim); + buf->xim = NULL; + } + } + else + { + XDestroyImage(buf->xim); + buf->xim = NULL; + } + } + + if (!buf->xim) // shm failed - try normal ximage + { + buf->xim = XCreateImage(swp->disp, swp->vis, swp->depth, ZPixmap, + 0, NULL, buf->w, buf->h, 32, 0); + if (!buf->xim) return EINA_FALSE; + buf->bpl = buf->xim->bytes_per_line; + buf->data = buf->xim->data = malloc(buf->bpl * buf->h); + if (!buf->data) + { + XDestroyImage(buf->xim); + buf->xim = NULL; + return EINA_FALSE; + } + } + return EINA_TRUE; +} + +static void +_buf_free(X_Swapper *swp, Buffer *buf) +{ + if (!buf->xim) return; + if (buf->shm) + { + XShmDetach(swp->disp, &(buf->shm_info)); + XDestroyImage(buf->xim); + shmdt(buf->shm_info.shmaddr); + shmctl(buf->shm_info.shmid, IPC_RMID, 0); + } + else + { + XDestroyImage(buf->xim); + } + buf->xim = NULL; + buf->shm = EINA_FALSE; +} + +static void +_buf_put(X_Swapper *swp, Buffer *buf, Eina_Rectangle *rects, int nrects) +{ + Region tmpr; + int i; + + if (!buf->xim) return; + tmpr = XCreateRegion(); + if (rects) + { + for (i = 0; i < nrects; i++) + { + XRectangle xr; + + xr.x = rects[i].x; xr.y = rects[i].y; + xr.width = rects[i].w; xr.height = rects[i].h; + XUnionRectWithRegion(&xr, tmpr, tmpr); + } + } + else + { + XRectangle xr; + + xr.x = 0; xr.y = 0; + xr.width = buf->w; xr.height = buf->h; + XUnionRectWithRegion(&xr, tmpr, tmpr); + } + XSetRegion(swp->disp, swp->gc, tmpr); + XDestroyRegion(tmpr); + if (buf->shm) + { + XShmPutImage(swp->disp, swp->draw, swp->gc, buf->xim, 0, 0, 0, 0, + buf->w, buf->h, False); + } + else + { + XPutImage(swp->disp, swp->draw, swp->gc, buf->xim, 0, 0, 0, 0, + buf->w, buf->h); + } + XSync(swp->disp, False); +} + +//////////////////////////////////// + +X_Swapper * +evas_xlib_swapper_new(Display *disp, Drawable draw, Visual *vis, + int depth, int w, int h) +{ + X_Swapper *swp; + XGCValues gcv; + int i; + + int nbuf = 3; // pretend we are triple buffered + + swp = calloc(1, sizeof(X_Swapper)); + if (!swp) return NULL; + swp->disp = disp; + swp->draw = draw; + swp->vis = vis; + swp->depth = depth; + swp->w = w; + swp->h = h; + swp->buf_num = nbuf; + swp->gc = XCreateGC(swp->disp, swp->draw, 0, &gcv); + for (i = 0; i < swp->buf_num; i++) + { + if (!_buf_new(swp, &(swp->buf[i]))) + { + evas_xlib_swapper_free(swp); + return NULL; + } + } + return swp; +} + +void +evas_xlib_swapper_free(X_Swapper *swp) +{ + int i; + + for (i = 0; i < swp->buf_num; i++) + { + _buf_free(swp, &(swp->buf[i])); + } + free(swp); +} + +void * +evas_xlib_swapper_buffer_map(X_Swapper *swp, int *bpl) +{ + swp->mapped = EINA_TRUE; + if (bpl) *bpl = swp->buf[swp->buf_cur].bpl; + return swp->buf[swp->buf_cur].data; +} + +void +evas_xlib_swapper_buffer_unmap(X_Swapper *swp) +{ + swp->mapped = EINA_FALSE; +} + +void +evas_xlib_swapper_swap(X_Swapper *swp, Eina_Rectangle *rects, int nrects) +{ + int n; + + n = swp->buf_cur; + _buf_put(swp, &(swp->buf[n]), rects, nrects); + swp->buf[n].valid = 1; + swp->buf_cur = (swp->buf_cur + 1) % swp->buf_num; +} + +int +evas_xlib_swapper_buffer_state_get(X_Swapper *swp) +{ + int i, n, count = 0; + + for (i = 0; i < swp->buf_num; i++) + { + n = (swp->buf_num + swp->buf_cur - (i)) % swp->buf_num; + if (swp->buf[n].valid) count++; + else break; + } + if (count == swp->buf_num) + { + if (count == 1) return MODE_COPY; + else if (count == 2) return MODE_DOUBLE; + else if (count == 3) return MODE_TRIPLE; + } + return MODE_FULL; +} + +int +evas_xlib_swapper_depth_get(X_Swapper *swp) +{ + return swp->buf[0].xim->bits_per_pixel; +} + +int +evas_xlib_swapper_byte_order_get(X_Swapper *swp) +{ + return swp->buf[0].xim->byte_order; +} + +int +evas_xlib_swapper_bit_order_get(X_Swapper *swp) +{ + return swp->buf[0].xim->bitmap_bit_order; +} diff --git a/src/modules/evas/engines/software_x11/evas_xlib_swapper.h b/src/modules/evas/engines/software_x11/evas_xlib_swapper.h new file mode 100644 index 0000000000..5399b80fcb --- /dev/null +++ b/src/modules/evas/engines/software_x11/evas_xlib_swapper.h @@ -0,0 +1,15 @@ +#include "evas_engine.h" + +typedef struct _X_Swapper X_Swapper; + +X_Swapper *evas_xlib_swapper_new(Display *disp, Drawable draw, Visual *vis, + int depth, int w, int h); +void evas_xlib_swapper_free(X_Swapper *swp); +void *evas_xlib_swapper_buffer_map(X_Swapper *swp, int *bpl); +void evas_xlib_swapper_buffer_unmap(X_Swapper *swp); +void evas_xlib_swapper_swap(X_Swapper *swp, Eina_Rectangle *rects, int nrects); +int evas_xlib_swapper_buffer_state_get(X_Swapper *swp); +int evas_xlib_swapper_depth_get(X_Swapper *swp); +int evas_xlib_swapper_byte_order_get(X_Swapper *swp); +int evas_xlib_swapper_bit_order_get(X_Swapper *swp); +