263 lines
7.7 KiB
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);
|
|
}
|