efl/legacy/evas/src/modules/engines/xrender_x11/evas_engine_xlib_ximage.c

263 lines
7.7 KiB
C

#include "evas_common.h"
#include "evas_private.h"
#include "evas_engine.h"
#include "Evas_Engine_XRender_X11.h"
static Eina_List *_image_info_list = NULL;
static int _x_err = 0;
static void
_tmp_x_err(Display *d __UNUSED__, XErrorEvent *ev __UNUSED__)
{
_x_err = 1;
return;
}
Ximage_Info *
_xr_xlib_image_info_get(Display *display, Drawable draw, Visual *visual)
{
Ximage_Info *xinf;
Ximage_Info *xinf2;
Eina_List *l;
int di;
unsigned int dui;
Window root;
xinf2 = NULL;
EINA_LIST_FOREACH(_image_info_list, l, xinf)
if (xinf->x11.connection == display)
{
xinf2 = xinf;
break;
}
xinf = calloc(1, sizeof(Ximage_Info));
if (!xinf) return NULL;
xinf->references = 1;
xinf->x11.connection = display;
xinf->x11.draw = draw;
XGetGeometry(xinf->x11.connection, xinf->x11.draw,
&root,
&di, &di, &dui, &dui, &dui, &dui);
xinf->x11.root = root;
xinf->x11.visual = visual;
xinf->x11.fmt32 = XRenderFindStandardFormat(xinf->x11.connection, PictStandardARGB32);
xinf->x11.fmt24 = XRenderFindStandardFormat(xinf->x11.connection, PictStandardRGB24);
xinf->x11.fmt8 = XRenderFindStandardFormat(xinf->x11.connection, PictStandardA8);
xinf->x11.fmt4 = XRenderFindStandardFormat(xinf->x11.connection, PictStandardA4);
xinf->x11.fmt1 = XRenderFindStandardFormat(xinf->x11.connection, PictStandardA1);
/* find fmt for default visual */
xinf->x11.fmtdef = XRenderFindVisualFormat(xinf->x11.connection, xinf->x11.visual);
xinf->mul = _xr_xlib_render_surface_new(xinf, 1, 1, xinf->x11.fmt32, 1);
_xr_xlib_render_surface_repeat_set(xinf->mul, 1);
xinf->mul_r = xinf->mul_g = xinf->mul_b = xinf->mul_a = 0xff;
_xr_xlib_render_surface_solid_rectangle_set(xinf->mul, xinf->mul_r, xinf->mul_g, xinf->mul_b, xinf->mul_a, 0, 0, 1, 1);
if (xinf2)
{
xinf->can_do_shm = xinf2->can_do_shm;
xinf->depth = xinf2->depth;
}
else
{
XVisualInfo *vi, vit;
XShmSegmentInfo shm_info;
XImage *xim;
int num = 0;
vit.visualid = XVisualIDFromVisual(xinf->x11.visual);
vi = XGetVisualInfo(xinf->x11.connection, VisualIDMask, &vit, &num);
if (!vi) xinf->depth = 32;
else
{
xinf->depth = vi->depth;
XFree(vi);
}
xinf->can_do_shm = 0;
xim = XShmCreateImage(xinf->x11.connection, xinf->x11.visual, xinf->depth, ZPixmap, NULL, &shm_info, 1, 1);
if (xim)
{
shm_info.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
if (shm_info.shmid >= 0)
{
shm_info.shmaddr = xim->data = shmat(shm_info.shmid, 0, 0);
if ((shm_info.shmaddr) && (shm_info.shmaddr != (void *) -1))
{
XErrorHandler ph;
XSync(xinf->x11.connection, False);
_x_err = 0;
ph = XSetErrorHandler((XErrorHandler)_tmp_x_err);
XShmAttach(xinf->x11.connection, &shm_info);
XSync(xinf->x11.connection, False);
XSetErrorHandler((XErrorHandler)ph);
if (!_x_err) xinf->can_do_shm = 1;
shmdt(shm_info.shmaddr);
}
shmctl(shm_info.shmid, IPC_RMID, 0);
}
XDestroyImage(xim);
}
}
_image_info_list = eina_list_prepend(_image_info_list, xinf);
return xinf;
}
void
_xr_xlib_image_info_free(Ximage_Info *xinf)
{
if (xinf->pool) XSync(xinf->x11.connection, False);
_xr_xlib_image_info_pool_flush(xinf, 0, 0);
xinf->references--;
if (xinf->references != 0) return;
_xr_xlib_render_surface_free(xinf->mul);
free(xinf);
_image_info_list = eina_list_remove(_image_info_list, xinf);
}
void
_xr_xlib_image_info_pool_flush(Ximage_Info *xinf, unsigned int max_num, unsigned int max_mem)
{
if ((xinf->pool_mem <= max_mem) && (eina_list_count(xinf->pool) <= max_num)) return;
while ((xinf->pool_mem > max_mem) || (eina_list_count(xinf->pool) > max_num))
{
Ximage_Image *xim;
if (!xinf->pool) break;
xim = xinf->pool->data;
_xr_xlib_image_free(xim);
}
}
Ximage_Image *
_xr_xlib_image_new(Ximage_Info *xinf, int w, int h, int depth)
{
Ximage_Image *xim, *xim2;
Eina_List *l;
xim2 = NULL;
EINA_LIST_FOREACH(xinf->pool, l, xim)
{
if ((xim->width >= w) && (xim->height >= h) && (xim->depth == depth) && (xim->available))
{
if (!xim2) xim2 = xim;
else if ((xim->width * xim->height) < (xim2->width * xim2->height)) xim2 = xim;
}
}
if (xim2)
{
xim2->available = 0;
return xim2;
}
xim = calloc(1, sizeof(Ximage_Image));
if (xim)
{
xim->xinf = xinf;
xim->width = w;
xim->height = h;
xim->depth = depth;
xim->available = 0;
if (xim->xinf->can_do_shm)
{
xim->x11.xlib.shm_info = calloc(1, sizeof(XShmSegmentInfo));
if (xim->x11.xlib.shm_info)
{
xim->x11.xlib.xim = XShmCreateImage(xim->xinf->x11.connection, xim->xinf->x11.visual, xim->depth, ZPixmap, NULL, xim->x11.xlib.shm_info, xim->width, xim->height);
if (xim->x11.xlib.xim)
{
xim->x11.xlib.shm_info->shmid = shmget(IPC_PRIVATE, xim->x11.xlib.xim->bytes_per_line * xim->x11.xlib.xim->height, IPC_CREAT | 0777);
if (xim->x11.xlib.shm_info->shmid >= 0)
{
xim->x11.xlib.shm_info->shmaddr = xim->x11.xlib.xim->data = shmat(xim->x11.xlib.shm_info->shmid, 0, 0);
if ((xim->x11.xlib.shm_info->shmaddr) && (xim->x11.xlib.shm_info->shmaddr != (void *) -1))
{
XErrorHandler ph;
XSync(xim->xinf->x11.connection, False);
_x_err = 0;
ph = XSetErrorHandler((XErrorHandler)_tmp_x_err);
XShmAttach(xim->xinf->x11.connection, xim->x11.xlib.shm_info);
XSync(xim->xinf->x11.connection, False);
XSetErrorHandler((XErrorHandler)ph);
if (!_x_err) goto xim_ok;
shmdt(xim->x11.xlib.shm_info->shmaddr);
}
shmctl(xim->x11.xlib.shm_info->shmid, IPC_RMID, 0);
}
XDestroyImage(xim->x11.xlib.xim);
}
free(xim->x11.xlib.shm_info);
xim->x11.xlib.shm_info = NULL;
}
}
xim->x11.xlib.xim = XCreateImage(xim->xinf->x11.connection, xim->xinf->x11.visual, xim->depth, ZPixmap, 0, NULL, xim->width, xim->height, 32, 0);
if (!xim->x11.xlib.xim)
{
free(xim);
return NULL;
}
xim->x11.xlib.xim->data = malloc(xim->x11.xlib.xim->bytes_per_line * xim->x11.xlib.xim->height);
if (!xim->x11.xlib.xim->data)
{
XDestroyImage(xim->x11.xlib.xim);
free(xim);
return NULL;
}
}
else
{
return NULL;
}
xim_ok:
_xr_xlib_image_info_pool_flush(xinf, 32, (1600 * 1200 * 32 * 2));
xim->line_bytes = xim->x11.xlib.xim->bytes_per_line;
xim->data = (void *)(xim->x11.xlib.xim->data);
xinf->pool_mem += (xim->width * xim->height * xim->depth);
xinf->pool = eina_list_append(xinf->pool, xim);
return xim;
}
void
_xr_xlib_image_free(Ximage_Image *xim)
{
if (xim->x11.xlib.shm_info)
{
if (!xim->available) XSync(xim->xinf->x11.connection, False);
XShmDetach(xim->xinf->x11.connection, xim->x11.xlib.shm_info);
XDestroyImage(xim->x11.xlib.xim);
shmdt(xim->x11.xlib.shm_info->shmaddr);
shmctl(xim->x11.xlib.shm_info->shmid, IPC_RMID, 0);
free(xim->x11.xlib.shm_info);
}
else
{
free(xim->x11.xlib.xim->data);
xim->x11.xlib.xim->data = NULL;
XDestroyImage(xim->x11.xlib.xim);
}
xim->xinf->pool_mem -= (xim->width * xim->height * xim->depth);
xim->xinf->pool = eina_list_remove(xim->xinf->pool, xim);
free(xim);
}
void
_xr_xlib_image_put(Ximage_Image *xim, Drawable draw, int x, int y, int w, int h)
{
XGCValues gcv;
GC gc;
gc = XCreateGC(xim->xinf->x11.connection, draw, 0, &gcv);
if (xim->x11.xlib.shm_info)
{
XShmPutImage(xim->xinf->x11.connection, draw, gc, xim->x11.xlib.xim, 0, 0, x, y, w, h, False);
XSync(xim->xinf->x11.connection, False);
}
else
XPutImage(xim->xinf->x11.connection, draw, gc, xim->x11.xlib.xim, 0, 0, x, y, w, h);
xim->available = 1;
XFreeGC(xim->xinf->x11.connection, gc);
}