efl/src/modules/evas/engines/software_x11/evas_xlib_swapbuf.c

550 lines
18 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/time.h>
#include <sys/utsname.h>
#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 EINA_UNUSED,
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)
{
eina_rectangle_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;
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;
}
eina_rectangle_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);
i++;
}
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 EINA_UNUSED)
{
return;
}
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;
}