forked from enlightenment/efl
615 lines
14 KiB
C
615 lines
14 KiB
C
#include "evas_common.h"
|
|
#include "evas_private.h"
|
|
#include "evas_engine.h"
|
|
#include "Evas_Engine_XRender_Xcb.h"
|
|
|
|
static Evas_Hash *_xr_image_hash = NULL;
|
|
static int _xr_image_cache_size = 0;
|
|
static int _xr_image_cache_usage = 0;
|
|
static Evas_List *_xr_image_cache = NULL;
|
|
static Evas_Hash *_xr_image_dirty_hash = NULL;
|
|
|
|
static void
|
|
__xre_image_dirty_hash_add(XR_Image *im)
|
|
{
|
|
char buf[64];
|
|
|
|
if (!im->data) return;
|
|
snprintf(buf, sizeof(buf), "%p", im->data);
|
|
_xr_image_dirty_hash = evas_hash_add(_xr_image_dirty_hash, buf, im);
|
|
}
|
|
|
|
static void
|
|
__xre_image_dirty_hash_del(XR_Image *im)
|
|
{
|
|
char buf[64];
|
|
|
|
if (!im->data) return;
|
|
snprintf(buf, sizeof(buf), "%p", im->data);
|
|
_xr_image_dirty_hash = evas_hash_del(_xr_image_dirty_hash, buf, im);
|
|
}
|
|
|
|
static XR_Image *
|
|
__xre_image_dirty_hash_find(void *data)
|
|
{
|
|
char buf[64];
|
|
|
|
snprintf(buf, sizeof(buf), "%p", data);
|
|
return evas_hash_find(_xr_image_dirty_hash, buf);
|
|
}
|
|
|
|
static XR_Image *
|
|
__xre_image_find(char *fkey)
|
|
{
|
|
XR_Image *im;
|
|
|
|
im = evas_hash_find(_xr_image_hash, fkey);
|
|
if (!im)
|
|
{
|
|
Evas_List *l;
|
|
|
|
for (l = _xr_image_cache; l; l = l->next)
|
|
{
|
|
im = l->data;
|
|
if (!strcmp(im->fkey, fkey))
|
|
{
|
|
_xr_image_cache = evas_list_remove_list(_xr_image_cache, l);
|
|
_xr_image_hash = evas_hash_add(_xr_image_hash, im->fkey, im);
|
|
_xr_image_cache_usage -= (im->w * im->h * 4);
|
|
break;
|
|
}
|
|
im = NULL;
|
|
}
|
|
}
|
|
if (im) im->references++;
|
|
return im;
|
|
}
|
|
|
|
XR_Image *
|
|
_xre_image_load(Xcb_Image_Info *xcbinf, const char *file, const char *key, Evas_Image_Load_Opts *lo)
|
|
{
|
|
char buf[4096];
|
|
XR_Image *im;
|
|
|
|
if (!file) return NULL;
|
|
if (!lo)
|
|
{
|
|
if (key)
|
|
snprintf(buf, sizeof(buf), "/@%p@%x@/%s//://%s", xcbinf->conn, xcbinf->root, file, key);
|
|
else
|
|
snprintf(buf, sizeof(buf), "/@%p@%x@/%s", xcbinf->conn, xcbinf->root, file);
|
|
}
|
|
else
|
|
{
|
|
if (key)
|
|
snprintf(buf, sizeof(buf), "//@/%i/%1.5f/%ix%i//@%p@%x@/%s//://%s", lo->scale_down_by, lo->dpi, lo->w, lo->h, xcbinf->conn, xcbinf->root, file, key);
|
|
else
|
|
snprintf(buf, sizeof(buf), "//@/%i/%1.5f/%ix%i//@%p@%x@/%s", lo->scale_down_by, lo->dpi, lo->w, lo->h, xcbinf->conn, xcbinf->root, file);
|
|
}
|
|
im = __xre_image_find(buf);
|
|
if (im)
|
|
{
|
|
return im;
|
|
}
|
|
|
|
im = calloc(1, sizeof(XR_Image));
|
|
if (!im) return NULL;
|
|
im->im = evas_common_load_image_from_file(file, key, lo);
|
|
if (!im->im)
|
|
{
|
|
free(im);
|
|
return NULL;
|
|
}
|
|
im->xcbinf = xcbinf;
|
|
im->xcbinf->references++;
|
|
im->fkey = strdup(buf);
|
|
im->file = (char *)evas_stringshare_add(file);
|
|
if (key) im->key = (char *)evas_stringshare_add(key);
|
|
im->w = im->im->cache_entry.w;
|
|
im->h = im->im->cache_entry.h;
|
|
im->references = 1;
|
|
if (lo) im->load_opts = *lo;
|
|
if (im->im->info.comment) im->comment = (char *)evas_stringshare_add(im->im->info.comment);
|
|
/* if (im->im->info.format == 1) im->format = evas_stringshare_add("png"); */
|
|
if (im->im->cache_entry.flags.alpha) im->alpha = 1;
|
|
_xr_image_hash = evas_hash_direct_add(_xr_image_hash, im->fkey, im);
|
|
return im;
|
|
}
|
|
|
|
XR_Image *
|
|
_xre_image_new_from_data(Xcb_Image_Info *xcbinf, int w, int h, void *data)
|
|
{
|
|
XR_Image *im;
|
|
|
|
im = calloc(1, sizeof(XR_Image));
|
|
if (!im) return NULL;
|
|
im->xcbinf = xcbinf;
|
|
im->xcbinf->references++;
|
|
im->w = w;
|
|
im->h = h;
|
|
im->references = 1;
|
|
im->data = data;
|
|
im->alpha = 1;
|
|
im->dirty = 1;
|
|
__xre_image_dirty_hash_add(im);
|
|
return im;
|
|
}
|
|
|
|
XR_Image *
|
|
_xre_image_new_from_copied_data(Xcb_Image_Info *xcbinf, int w, int h, void *data)
|
|
{
|
|
XR_Image *im;
|
|
|
|
im = calloc(1, sizeof(XR_Image));
|
|
if (!im) return NULL;
|
|
im->data = malloc(w * h * 4);
|
|
if (!im->data)
|
|
{
|
|
free(im);
|
|
return NULL;
|
|
}
|
|
if (data)
|
|
{
|
|
Gfx_Func_Copy func;
|
|
|
|
func = evas_common_draw_func_copy_get(w * h, 0);
|
|
if (func) func(data, im->data, w * h);
|
|
evas_common_cpu_end_opt();
|
|
}
|
|
im->w = w;
|
|
im->h = h;
|
|
im->references = 1;
|
|
im->xcbinf = xcbinf;
|
|
im->xcbinf->references++;
|
|
im->free_data = 1;
|
|
im->alpha = 1;
|
|
im->dirty = 1;
|
|
__xre_image_dirty_hash_add(im);
|
|
return im;
|
|
}
|
|
|
|
XR_Image *
|
|
_xre_image_new(Xcb_Image_Info *xcbinf, int w, int h)
|
|
{
|
|
XR_Image *im;
|
|
|
|
im = calloc(1, sizeof(XR_Image));
|
|
if (!im) return NULL;
|
|
im->data = malloc(w * h * 4);
|
|
if (!im->data)
|
|
{
|
|
free(im);
|
|
return NULL;
|
|
}
|
|
im->w = w;
|
|
im->h = h;
|
|
im->references = 1;
|
|
im->xcbinf = xcbinf;
|
|
im->xcbinf->references++;
|
|
im->free_data = 1;
|
|
im->alpha = 1;
|
|
im->dirty = 1;
|
|
__xre_image_dirty_hash_add(im);
|
|
return im;
|
|
}
|
|
|
|
static void
|
|
__xre_image_real_free(XR_Image *im)
|
|
{
|
|
if (im->file) evas_stringshare_del(im->file);
|
|
if (im->key) evas_stringshare_del(im->key);
|
|
if (im->fkey) free(im->fkey);
|
|
if (im->im) evas_cache_image_drop(&im->im->cache_entry);
|
|
if ((im->data) && (im->dirty)) __xre_image_dirty_hash_del(im);
|
|
if ((im->free_data) && (im->data)) free(im->data);
|
|
if (im->surface) _xr_render_surface_free(im->surface);
|
|
if (im->format) evas_stringshare_del(im->format);
|
|
if (im->comment) evas_stringshare_del(im->comment);
|
|
if (im->updates) evas_common_tilebuf_free(im->updates);
|
|
_xr_image_info_free(im->xcbinf);
|
|
free(im);
|
|
}
|
|
|
|
void
|
|
_xre_image_free(XR_Image *im)
|
|
{
|
|
im->references--;
|
|
if (im->references != 0) return;
|
|
if (!im->dirty)
|
|
{
|
|
if (im->fkey)
|
|
_xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
|
|
_xr_image_cache = evas_list_prepend(_xr_image_cache, im);
|
|
_xr_image_cache_usage += (im->w * im->h * 4);
|
|
_xre_image_cache_set(_xr_image_cache_size);
|
|
}
|
|
else
|
|
{
|
|
__xre_image_real_free(im);
|
|
}
|
|
}
|
|
|
|
void
|
|
_xre_image_region_dirty(XR_Image *im, int x, int y, int w, int h)
|
|
{
|
|
if (!im->updates)
|
|
{
|
|
im->updates = evas_common_tilebuf_new(im->w, im->h);
|
|
if (im->updates) evas_common_tilebuf_set_tile_size(im->updates, 8, 8);
|
|
}
|
|
if (im->updates)
|
|
evas_common_tilebuf_add_redraw(im->updates, x, y, w, h);
|
|
}
|
|
|
|
void
|
|
_xre_image_dirty(XR_Image *im)
|
|
{
|
|
if (im->dirty) return;
|
|
if (im->fkey)
|
|
_xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
|
|
im->dirty = 1;
|
|
__xre_image_dirty_hash_add(im);
|
|
}
|
|
|
|
XR_Image *
|
|
_xre_image_copy(XR_Image *im)
|
|
{
|
|
XR_Image *im2;
|
|
void *data = NULL;
|
|
|
|
if (im->data) data = im->data;
|
|
else
|
|
{
|
|
if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
|
|
if (im->im)
|
|
{
|
|
evas_cache_image_load_data(&im->im->cache_entry);
|
|
data = im->im->image.data;
|
|
}
|
|
}
|
|
if (!data) return NULL;
|
|
im2 = _xre_image_new_from_copied_data(im->xcbinf, im->w, im->h, data);
|
|
if (im2) im2->alpha = im->alpha;
|
|
if ((im->im) && (!im->dirty))
|
|
{
|
|
evas_cache_image_drop(&im->im->cache_entry);
|
|
im->im = NULL;
|
|
}
|
|
return im2;
|
|
}
|
|
|
|
void
|
|
_xre_image_resize(XR_Image *im, int w, int h)
|
|
{
|
|
if ((w == im->w) && (h == im->h)) return;
|
|
if (im->surface)
|
|
{
|
|
Xcb_Render_Surface *old_surface;
|
|
int x = 0, y = 0, ww, hh;
|
|
|
|
ww = w; hh = h;
|
|
RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
|
|
old_surface = im->surface;
|
|
im->surface = _xr_render_surface_new(old_surface->xcbinf,
|
|
w + 1, h + 1, old_surface->fmt, old_surface->alpha);
|
|
if (im->surface)
|
|
_xr_render_surface_copy(old_surface, im->surface, 0, 0, 0, 0, ww, hh);
|
|
_xr_render_surface_free(old_surface);
|
|
}
|
|
if (im->data)
|
|
{
|
|
Gfx_Func_Copy func;
|
|
int x = 0, y = 0, ww, hh;
|
|
unsigned int *sp, *dp;
|
|
void *data;
|
|
|
|
data = malloc(w * h * 4);
|
|
if (!data)
|
|
{
|
|
if (im->surface)
|
|
{
|
|
_xr_render_surface_free(im->surface);
|
|
im->surface = NULL;
|
|
}
|
|
return;
|
|
}
|
|
ww = w; hh = h;
|
|
|
|
RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
|
|
func = evas_common_draw_func_copy_get(w * h, 0);
|
|
if (func)
|
|
{
|
|
for (y = 0; y < hh; y++)
|
|
{
|
|
sp = ((unsigned int *)im->data) + (y * im->w);
|
|
dp = ((unsigned int *)data) + (y * w);
|
|
func(sp, dp, ww);
|
|
}
|
|
evas_common_cpu_end_opt();
|
|
}
|
|
__xre_image_dirty_hash_del(im);
|
|
free(im->data);
|
|
im->data = data;
|
|
__xre_image_dirty_hash_add(im);
|
|
}
|
|
else if (im->im)
|
|
{
|
|
RGBA_Image *im_old;
|
|
|
|
im_old = im->im;
|
|
im->im = (RGBA_Image*) evas_cache_image_empty(evas_common_image_cache_get());
|
|
if (!im->im)
|
|
{
|
|
im->im = im_old;
|
|
if (im->surface)
|
|
{
|
|
_xr_render_surface_free(im->surface);
|
|
im->surface = NULL;
|
|
}
|
|
return;
|
|
}
|
|
evas_cache_image_load_data(&im->im->cache_entry);
|
|
if (im_old->image.data)
|
|
{
|
|
int x = 0, y = 0, ww, hh;
|
|
|
|
ww = w; hh = h;
|
|
RECTS_CLIP_TO_RECT(x, y, ww, hh, 0, 0, im->w, im->h);
|
|
evas_common_blit_rectangle(im_old, im->im, 0, 0, ww, hh, 0, 0);
|
|
evas_common_cpu_end_opt();
|
|
}
|
|
im->free_data = 1;
|
|
/* FIXME: Hum ? */
|
|
im->data = im->im->image.data;
|
|
im->im->image.data = NULL;
|
|
evas_cache_image_drop(&im->im->cache_entry);
|
|
im->im = NULL;
|
|
evas_cache_image_drop(&im_old->cache_entry);
|
|
__xre_image_dirty_hash_add(im);
|
|
}
|
|
else
|
|
{
|
|
im->data = malloc(w * h * 4);
|
|
im->free_data = 1;
|
|
__xre_image_dirty_hash_add(im);
|
|
}
|
|
im->w = w;
|
|
im->h = h;
|
|
}
|
|
|
|
void *
|
|
_xre_image_data_get(XR_Image *im)
|
|
{
|
|
void *data = NULL;
|
|
|
|
if (im->data) data = im->data;
|
|
else
|
|
{
|
|
if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
|
|
if (im->im)
|
|
{
|
|
evas_cache_image_load_data(&im->im->cache_entry);
|
|
data = im->im->image.data;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
XR_Image *
|
|
_xre_image_data_find(void *data)
|
|
{
|
|
XR_Image *im;
|
|
|
|
im = __xre_image_dirty_hash_find(data);
|
|
if (im)
|
|
{
|
|
im->references++;
|
|
}
|
|
return im;
|
|
}
|
|
|
|
void
|
|
_xre_image_data_put(XR_Image *im, void *data)
|
|
{
|
|
void *imdata = NULL;
|
|
|
|
if (!data) return;
|
|
if (im->data)
|
|
{
|
|
imdata = im->data;
|
|
if (data == imdata) return;
|
|
__xre_image_dirty_hash_del(im);
|
|
if (im->free_data) free(im->data);
|
|
}
|
|
else
|
|
{
|
|
if (im->im) imdata = im->im->image.data;
|
|
if (data == imdata) return;
|
|
if (im->im)
|
|
{
|
|
evas_cache_image_drop(&im->im->cache_entry);
|
|
im->im = NULL;
|
|
}
|
|
}
|
|
im->data = data;
|
|
__xre_image_dirty_hash_add(im);
|
|
im->free_data = 0;
|
|
if (im->surface)
|
|
{
|
|
_xr_render_surface_free(im->surface);
|
|
im->surface = NULL;
|
|
}
|
|
if (!im->dirty)
|
|
{
|
|
if (im->fkey)
|
|
_xr_image_hash = evas_hash_del(_xr_image_hash, im->fkey, im);
|
|
im->dirty = 1;
|
|
}
|
|
if (im->updates)
|
|
{
|
|
evas_common_tilebuf_free(im->updates);
|
|
im->updates = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
_xre_image_alpha_set(XR_Image *im, int alpha)
|
|
{
|
|
if (im->alpha == alpha) return;
|
|
im->alpha = alpha;
|
|
if (im->surface)
|
|
{
|
|
Xcb_Render_Surface *old_surface;
|
|
|
|
old_surface = im->surface;
|
|
im->surface = NULL;
|
|
if (im->alpha)
|
|
im->surface = _xr_render_surface_new(im->xcbinf,
|
|
im->w + 1, im->h + 1, im->xcbinf->fmt32, 1);
|
|
else
|
|
im->surface = _xr_render_surface_new(im->xcbinf,
|
|
im->w + 1, im->h + 1, im->xcbinf->fmt24, 0);
|
|
if (im->surface)
|
|
_xr_render_surface_copy(old_surface,
|
|
im->surface, 0, 0, 0, 0, im->w + 1, im->h + 1);
|
|
_xr_render_surface_free(old_surface);
|
|
}
|
|
if (im->updates)
|
|
{
|
|
evas_common_tilebuf_free(im->updates);
|
|
im->updates = NULL;
|
|
}
|
|
}
|
|
|
|
int
|
|
_xre_image_alpha_get(XR_Image *im)
|
|
{
|
|
return im->alpha;
|
|
}
|
|
|
|
void
|
|
_xre_image_border_set(XR_Image *im, int l, int r, int t, int b)
|
|
{
|
|
if (!im) return;
|
|
_xre_image_surface_gen(im);
|
|
if (l < 1) l = 0;
|
|
if (r < 1) r = 0;
|
|
if (t < 1) t = 0;
|
|
if (b < 1) b = 0;
|
|
if (im->surface)
|
|
{
|
|
if (l | r | t | b)
|
|
im->surface->bordered = 1;
|
|
else
|
|
im->surface->bordered = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
_xre_image_border_get(XR_Image *im, int *l, int *r, int *t, int *b)
|
|
{
|
|
}
|
|
|
|
void
|
|
_xre_image_surface_gen(XR_Image *im)
|
|
{
|
|
void *data = NULL;
|
|
|
|
if ((im->surface) && (!im->updates)) return;
|
|
if (im->data) data = im->data;
|
|
else
|
|
{
|
|
if (!im->im) im->im = evas_common_load_image_from_file(im->file, im->key, &(im->load_opts));
|
|
if (im->im)
|
|
{
|
|
evas_cache_image_load_data(&im->im->cache_entry);
|
|
data = im->im->image.data;
|
|
}
|
|
}
|
|
if (!data) return;
|
|
if (im->surface)
|
|
{
|
|
if (im->updates)
|
|
{
|
|
Tilebuf_Rect *rects, *r;
|
|
|
|
rects = evas_common_tilebuf_get_render_rects(im->updates);
|
|
if (rects)
|
|
{
|
|
for (r = rects; r; r = (Tilebuf_Rect *)((Evas_Object_List *)r)->next)
|
|
{
|
|
int rx, ry, rw, rh;
|
|
|
|
rx = r->x; ry = r->y; rw = r->w, rh = r->h;
|
|
RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, im->w, im->h);
|
|
if (im->alpha)
|
|
_xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh);
|
|
else
|
|
_xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, rx, ry, rw, rh);
|
|
}
|
|
evas_common_tilebuf_free_render_rects(rects);
|
|
}
|
|
evas_common_tilebuf_free(im->updates);
|
|
im->updates = NULL;
|
|
}
|
|
return;
|
|
}
|
|
if (im->alpha)
|
|
{
|
|
im->surface = _xr_render_surface_new(im->xcbinf,
|
|
im->w + 1, im->h + 1, im->xcbinf->fmt32, 1);
|
|
_xr_render_surface_argb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h);
|
|
}
|
|
else
|
|
{
|
|
im->surface = _xr_render_surface_new(im->xcbinf,
|
|
im->w + 1, im->h + 1, im->xcbinf->fmt24, 0);
|
|
_xr_render_surface_rgb_pixels_fill(im->surface, im->w, im->h, data, 0, 0, im->w, im->h);
|
|
}
|
|
/* fill right and bottom pixel so interpolation works right */
|
|
_xr_render_surface_copy(im->surface, im->surface,
|
|
im->w - 1, 0,
|
|
im->w, 0,
|
|
1, im->h);
|
|
_xr_render_surface_copy(im->surface, im->surface,
|
|
0, im->h - 1,
|
|
0, im->h,
|
|
im->w, 1);
|
|
_xr_render_surface_copy(im->surface, im->surface,
|
|
im->w - 1, im->h - 1,
|
|
im->w, im->h,
|
|
1, 1);
|
|
if ((im->im) && (!im->dirty))
|
|
{
|
|
evas_cache_image_drop(&im->im->cache_entry);
|
|
im->im = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
_xre_image_cache_set(int size)
|
|
{
|
|
_xr_image_cache_size = size;
|
|
while (_xr_image_cache_usage > _xr_image_cache_size)
|
|
{
|
|
Evas_List *l;
|
|
|
|
l = evas_list_last(_xr_image_cache);
|
|
if (l)
|
|
{
|
|
XR_Image *im;
|
|
|
|
im = l->data;
|
|
_xr_image_cache = evas_list_remove_list(_xr_image_cache, l);
|
|
_xr_image_cache_usage -= (im->w * im->h * 4);
|
|
__xre_image_real_free(im);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
_xre_image_cache_get(void)
|
|
{
|
|
return _xr_image_cache_size;
|
|
}
|