efl/src/lib/evas/common/evas_image_main.c

1136 lines
32 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h" /* so that EAPI in Eet.h is correctly defined */
#endif
#ifdef _WIN32
# include <evil_private.h> /* mmap */
#else
# include <sys/mman.h>
#endif
#ifdef BUILD_LOADER_EET
# include <Eet.h>
#endif
#include "evas_common_private.h"
#include "evas_private.h"
#include "evas_image_private.h"
#include "evas_convert_yuv.h"
//#include "evas_cs.h"
#ifdef HAVE_VALGRIND
# include <valgrind.h>
# include <memcheck.h>
#endif
//#define SURFDBG 1
static Evas_Cache_Image *eci = NULL;
static int reference = 0;
static int evas_image_no_mmap = -1;
/* static RGBA_Image *evas_rgba_line_buffer = NULL; */
#define EVAS_RGBA_LINE_BUFFER_MIN_LEN 256
#define EVAS_RGBA_LINE_BUFFER_MAX_LEN 2048
/* static RGBA_Image *evas_alpha_line_buffer = NULL; */
#define EVAS_ALPHA_LINE_BUFFER_MIN_LEN 256
#define EVAS_ALPHA_LINE_BUFFER_MAX_LEN 2048
static Image_Entry *_evas_common_rgba_image_new(void);
static void _evas_common_rgba_image_delete(Image_Entry *ie);
static int _evas_common_rgba_image_surface_alloc(Image_Entry *ie,
unsigned int w,
unsigned int h);
static void _evas_common_rgba_image_surface_delete(Image_Entry *ie);
static DATA32 *_evas_common_rgba_image_surface_pixels(Image_Entry *ie);
static void _evas_common_rgba_image_unload(Image_Entry *im);
static void _evas_common_rgba_image_dirty_region(Image_Entry *im,
unsigned int x,
unsigned int y,
unsigned int w,
unsigned int h);
static int _evas_common_rgba_image_ram_usage(Image_Entry *ie);
/* Only called when references > 0. Need to provide a fresh copie of im. */
/* The destination surface does have a surface, but no allocated pixel data. */
static int _evas_common_rgba_image_dirty(Image_Entry* dst,
const Image_Entry* src);
static const Evas_Cache_Image_Func _evas_common_image_func =
{
_evas_common_rgba_image_new,
_evas_common_rgba_image_delete,
_evas_common_rgba_image_surface_alloc,
_evas_common_rgba_image_surface_delete,
_evas_common_rgba_image_surface_pixels,
evas_common_load_rgba_image_module_from_file,
_evas_common_rgba_image_unload,
_evas_common_rgba_image_dirty_region,
_evas_common_rgba_image_dirty,
evas_common_rgba_image_size_set,
evas_common_rgba_image_from_copied_data,
evas_common_rgba_image_from_data,
evas_common_rgba_image_colorspace_set,
evas_common_load_rgba_image_data_from_file,
_evas_common_rgba_image_ram_usage,
NULL // _evas_common_rgba_image_debug
};
EAPI int
_evas_common_rgba_image_surface_size(unsigned int w, unsigned int h,
Evas_Colorspace cspace,
/*inout*/int *l, int *r, int *t, int *b)
{
#ifndef PAGE_SIZE
# define PAGE_SIZE (4 * 1024)
#endif
#define HUGE_PAGE_SIZE (2 * 1024 * 1024)
#if defined (HAVE_SYS_MMAN_H) && (!defined (_WIN32))
# define ALIGN_TO_PAGE(Siz) \
(((Siz / PAGE_SIZE) + (Siz % PAGE_SIZE ? 1 : 0)) * PAGE_SIZE)
#else
# define ALIGN_TO_PAGE(Siz) Siz
#endif
int siz, block_size = 8;
Eina_Bool reset_borders = EINA_TRUE;
#ifdef HAVE_VALGRIND
if (RUNNING_ON_VALGRIND) evas_image_no_mmap = 1;
#endif
if (EINA_UNLIKELY(evas_image_no_mmap == -1))
{
const char *s = getenv("EVAS_IMAGE_NO_MMAP");
evas_image_no_mmap = s && (atoi(s));
if (evas_image_no_mmap)
WRN("EVAS_IMAGE_NO_MMAP is set, use this only for debugging!");
}
switch (cspace)
{
case EVAS_COLORSPACE_GRY8: siz = w * h * sizeof(DATA8); break;
case EVAS_COLORSPACE_AGRY88: siz = w * h * sizeof(DATA16); break;
case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
case EVAS_COLORSPACE_ETC1_ALPHA:
block_size = 16;
// fallthrough
case EVAS_COLORSPACE_ETC1:
case EVAS_COLORSPACE_RGB8_ETC2:
case EVAS_COLORSPACE_RGB_S3TC_DXT1:
case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
reset_borders = EINA_FALSE;
if (l && r && t && b)
{
w += *l + *r;
h += *t + *b;
}
EINA_SAFETY_ON_FALSE_RETURN_VAL(!(w & 0x3) && !(h & 0x3), 0);
siz = (w >> 2) * (h >> 2) * block_size;
break;
default:
case EVAS_COLORSPACE_ARGB8888: siz = w * h * sizeof(DATA32); break;
}
if (reset_borders)
{
if (l) *l = 0;
if (r) *r = 0;
if (t) *t = 0;
if (b) *b = 0;
}
if ((siz < PAGE_SIZE) || evas_image_no_mmap) return siz;
return ALIGN_TO_PAGE(siz);
#undef ALIGN_TO_PAGE
}
EAPI Eina_Bool
_evas_common_rgba_image_plane_get(const RGBA_Image *im, int plane,
Eina_Slice *slice)
{
unsigned char **csdata = NULL;
Evas_Colorspace cs;
size_t w, h;
if (!im || !slice) return EINA_FALSE;
cs = im->cache_entry.space;
w = im->cache_entry.w;
h = im->cache_entry.h;
switch (cs)
{
case EVAS_COLORSPACE_YCBCR422P601_PL:
case EVAS_COLORSPACE_YCBCR422P709_PL:
case EVAS_COLORSPACE_YCBCR422601_PL:
case EVAS_COLORSPACE_YCBCR420NV12601_PL:
case EVAS_COLORSPACE_YCBCR420TM12601_PL:
if (!im->cs.data) return EINA_FALSE;
csdata = im->cs.data;
break;
default:
if (!im->image.data) return EINA_FALSE;
break;
}
switch (cs)
{
case EVAS_COLORSPACE_ARGB8888:
if (plane != 0) return EINA_FALSE;
slice->len = w * h * 4;
slice->mem = im->image.data;
return EINA_TRUE;
case EVAS_COLORSPACE_AGRY88:
if (plane != 0) return EINA_FALSE;
slice->len = w * h * 2;
slice->mem = im->image.data;
return EINA_TRUE;
case EVAS_COLORSPACE_GRY8:
if (plane != 0) return EINA_FALSE;
slice->len = w * h;
slice->mem = im->image.data;
return EINA_TRUE;
case EVAS_COLORSPACE_RGB565_A5P:
if (plane == 0)
{
slice->mem = im->image.data;
slice->len = w * h * 2;
return EINA_TRUE;
}
else if (plane == 1)
{
slice->mem = im->image.data8 + (w * h * 2);
slice->len = w * h;
return EINA_TRUE;
}
return EINA_FALSE;
// YUV, assume contiguous memory within a plane - padding ok
// 1 plane
case EVAS_COLORSPACE_YCBCR422601_PL:
if (plane != 0) return EINA_FALSE;
slice->mem = csdata[0];
slice->len = (h > 1) ? ((csdata[1] - csdata[0]) * h * 2) : (w * 2);
return EINA_TRUE;
// 2 planes
case EVAS_COLORSPACE_YCBCR420NV12601_PL:
case EVAS_COLORSPACE_YCBCR420TM12601_PL:
if (plane == 0)
{
slice->mem = csdata[0];
slice->len = (h > 1) ? ((csdata[1] - csdata[0]) * h) : w;
return EINA_TRUE;
}
else if (plane == 1)
{
slice->mem = csdata[h];
slice->len = (h > 1) ? ((csdata[h+1] - csdata[h]) * h / 2) : w / 2;
return EINA_TRUE;
}
return EINA_FALSE;
// 3 planes
case EVAS_COLORSPACE_YCBCR422P601_PL:
case EVAS_COLORSPACE_YCBCR422P709_PL:
if (plane == 0)
{
slice->mem = csdata[0];
slice->len = (h > 1) ? ((csdata[1] - csdata[0]) * h) : w;
return EINA_TRUE;
}
else if (plane == 1)
{
slice->mem = csdata[h];
slice->len = (h > 1) ? ((csdata[h+1] - csdata[h]) * h / 2) : w / 2;
return EINA_TRUE;
}
else if (plane == 2)
{
slice->mem = csdata[h + h / 2];
slice->len = (h > 1) ? ((csdata[h+h/2+1] - csdata[h+h/2]) * h / 2) : w / 2;
return EINA_TRUE;
}
return EINA_FALSE;
// ETC1/2 RGB, S3TC RGB
case EVAS_COLORSPACE_ETC1:
case EVAS_COLORSPACE_RGB8_ETC2:
case EVAS_COLORSPACE_RGB_S3TC_DXT1:
if (plane != 0) return EINA_FALSE;
slice->mem = im->image.data;
slice->len = (w * h * 8) / 16;
return EINA_TRUE;
// ETC2 ARGB, S3TC ARGB
case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
if (plane != 0) return EINA_FALSE;
slice->mem = im->image.data;
slice->len = (w * h * 16) / 16;
return EINA_TRUE;
// ETC1+Alpha
case EVAS_COLORSPACE_ETC1_ALPHA:
if (plane == 0)
{
slice->mem = im->image.data;
slice->len = (w * h * 8) / 16;
return EINA_TRUE;
}
else if (plane == 1)
{
slice->mem = im->image.data8 + (w * h * 8) / 16;
slice->len = (w * h * 8) / 16;
return EINA_TRUE;
}
return EINA_FALSE;
default:
return EINA_FALSE;
}
}
EAPI int
_evas_common_rgba_image_data_offset(int rx, int ry, int rw, int rh,
int plane, const RGBA_Image *im)
{
// note: no stride support
EINA_SAFETY_ON_NULL_RETURN_VAL(im, -1);
const Image_Entry *ie = &im->cache_entry;
if ((rx < 0) || (ry < 0) || (rw < 0) || (rh < 0)) return -1;
if (((rx + rw) > (int) ie->w) || ((ry + rh) > (int) ie->h)) return -1;
switch (ie->space)
{
case EVAS_COLORSPACE_ARGB8888:
return (ry * ie->w + rx) * 4;
case EVAS_COLORSPACE_AGRY88:
return (ry * ie->w + rx) * 2;
case EVAS_COLORSPACE_GRY8:
return ry * ie->w + rx;
case EVAS_COLORSPACE_RGB565_A5P:
if (plane == 0) return (ry * ie->w + rx) * 2;
else if (plane == 1) return ry * ie->w + rx + (ie->w * ie->h) * 2;
else return -1;
// YUV
case EVAS_COLORSPACE_YCBCR422P601_PL:
case EVAS_COLORSPACE_YCBCR422P709_PL:
case EVAS_COLORSPACE_YCBCR422601_PL:
if ((rx & 1) || (rw & 1)) return -1;
if (plane == 0) return ry * ie->w + rx;
else if (plane == 1) return (ry * ie->w) / 2 + rx + ie->w * ie->h;
else return -1;
case EVAS_COLORSPACE_YCBCR420NV12601_PL:
case EVAS_COLORSPACE_YCBCR420TM12601_PL:
if ((rx & 1) || (ry & 1) || (rw & 1) || (rh & 1)) return -1;
if (plane == 0) return ry * ie->w + rx;
else if (plane == 1) return (ry * ie->w + rx) / 2 + ie->w * ie->h;
else return -1;
// ETC1/2 RGB, S3TC RGB
case EVAS_COLORSPACE_ETC1:
case EVAS_COLORSPACE_RGB8_ETC2:
case EVAS_COLORSPACE_RGB_S3TC_DXT1:
if ((rx & 3) || (ry & 3) || (rw & 3) || (rh & 3)) return -1;
return (ry * ie->w + rx) * 8 / 16;
// ETC2 ARGB, S3TC ARGB
case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
if ((rx & 3) || (ry & 3) || (rw & 3) || (rh & 3)) return -1;
return (ry * ie->w + rx) * 16 / 16;
// ETC1+Alpha
case EVAS_COLORSPACE_ETC1_ALPHA:
if ((rx & 3) || (ry & 3) || (rw & 3) || (rh & 3)) return -1;
if (plane == 0) return (ry * ie->w + rx) * 8 / 16;
else if (plane == 1)
return (ry * ie->w + rx) * 8 / 16 + (ie->w * ie->h) * 8 / 16;
else return -1;
default:
CRI("unknown colorspace %d", ie->space);
return EINA_FALSE;
}
}
static void *
_evas_common_rgba_image_surface_mmap(Image_Entry *ie,
unsigned int w, unsigned int h,
/*inout*/int *pl, int *pr,
int *pt, int *pb)
{
int siz;
#if defined (HAVE_SYS_MMAN_H) && (!defined (_WIN32))
void *r = MAP_FAILED;
#endif
siz = _evas_common_rgba_image_surface_size(w, h, ie->space, pl, pr, pt, pb);
#if defined (HAVE_SYS_MMAN_H) && (!defined (_WIN32))
#ifndef MAP_HUGETLB
# define MAP_HUGETLB 0
#endif
if (siz < 0) return NULL;
if ((siz < PAGE_SIZE) || evas_image_no_mmap) return malloc(siz);
if (siz > ((HUGE_PAGE_SIZE * 75) / 100))
r = mmap(NULL, siz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_HUGETLB, -1, 0);
if (r == MAP_FAILED)
r = mmap(NULL, siz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (r == MAP_FAILED)
r = NULL;
return r;
#else
return malloc(siz);
#endif
}
void
evas_common_rgba_image_surface_munmap(void *data, unsigned int w, unsigned int h, Evas_Colorspace cspace)
{
if (!data) return;
#if defined (HAVE_SYS_MMAN_H) && (!defined (_WIN32))
size_t siz;
siz = _evas_common_rgba_image_surface_size(w, h, cspace,
NULL, NULL, NULL, NULL);
if ((siz < PAGE_SIZE) || evas_image_no_mmap) free(data);
else munmap(data, siz);
#else
(void)w;
(void)h;
(void)cspace;
free(data);
#endif
}
EAPI void
evas_common_image_init(void)
{
if (!eci) eci = evas_cache_image_init(&_evas_common_image_func);
reference++;
evas_common_scalecache_init();
}
EAPI void
evas_common_image_shutdown(void)
{
if (--reference == 0)
{
//// printf("REF--=%i\n", reference);
// DISABLE for now - something wrong with cache shutdown freeing things
// still in use - rage_thumb segv's now.
//
// actually - i think i see it. cache ref goes to 0 (and thus gets freed)
// because in eng_setup() when a buffer changes size it is FIRST freed
// THEN allocated again - thus brignhjing ref to 0 then back to 1 immediately
// where it should stay at 1. - see evas_engine.c in the buffer enigne for
// example. eng_output_free() is called BEFORE _output_setup(). although this
// is only a SIGNE of the problem. we can patch this up with either freeing
// after the setup (so we just pt a ref of 2 then back to 1), or just
// evas_common_image_init() at the start and evas_common_image_shutdown()
// after it all. really ref 0 should only be reached when no more canvases
// with no more objects exist anywhere.
// ENABLE IT AGAIN, hope it is fixed. Gustavo @ January 22nd, 2009.
evas_cache_image_shutdown(eci);
eci = NULL;
}
evas_common_scalecache_shutdown();
}
EAPI void
evas_common_image_image_all_unload(void)
{
evas_common_rgba_image_scalecache_dump();
evas_cache_image_unload_all(eci);
}
static Image_Entry *
_evas_common_rgba_image_new(void)
{
RGBA_Image *im;
im = calloc(1, sizeof(RGBA_Image));
if (!im) return NULL;
im->flags = RGBA_IMAGE_NOTHING;
evas_common_rgba_image_scalecache_init(&im->cache_entry);
return &im->cache_entry;
}
static void
_evas_common_rgba_image_delete(Image_Entry *ie)
{
RGBA_Image *im = (RGBA_Image *)ie;
evas_common_rgba_pending_unloads_remove(ie);
#ifdef BUILD_PIPE_RENDER
evas_common_pipe_free(im);
#endif
if (ie->loader_data)
{
Evas_Image_Load_Func *evas_image_load_func = NULL;
evas_image_load_func = ie->info.loader;
if (evas_image_load_func)
evas_image_load_func->file_close(ie->loader_data);
ie->loader_data = NULL;
}
evas_common_rgba_image_scalecache_shutdown(&im->cache_entry);
if (ie->info.module) evas_module_unref((Evas_Module *)ie->info.module);
if (ie->animated.frames)
{
Image_Entry_Frame *frame;
EINA_LIST_FREE(ie->animated.frames, frame)
{
if (frame->data) free(frame->data);
if (frame->info) free(frame->info);
free(frame);
}
}
if (ie->f && !ie->flags.given_mmap)
{
eina_file_close(ie->f); // close matching open (dup in _evas_image_file_header) OK
ie->f = NULL;
}
eina_freeq_ptr_add(eina_freeq_main_get(), im, free, sizeof(*im));
}
static void
evas_common_rgba_image_unload_real(Image_Entry *ie)
{
RGBA_Image *im = (RGBA_Image *) ie;
ie->flags.loaded = 0;
if ((im->cs.data) && (im->image.data))
{
if (im->cs.data != im->image.data)
{
if (!im->cs.no_free) free(im->cs.data);
}
}
else if (im->cs.data)
{
if (!im->cs.no_free) free(im->cs.data);
}
im->cs.data = NULL;
if (im->image.data && !im->image.no_free)
{
evas_common_rgba_image_surface_munmap(im->image.data,
ie->allocated.w, ie->allocated.h,
ie->space);
#ifdef SURFDBG
surfs = eina_list_remove(surfs, ie);
#endif
}
im->image.data = NULL;
ie->allocated.w = 0;
ie->allocated.h = 0;
ie->flags.loaded = 0;
ie->flags.preload_done = 0;
ie->need_unload = 0;
#ifdef SURFDBG
surf_debug();
#endif
}
static Eina_List *pending_unloads = NULL;
EAPI void
evas_common_rgba_pending_unloads_cleanup(void)
{
Image_Entry *ie;
Eina_List *l;
Eina_List *l_next;
EINA_LIST_FOREACH_SAFE(pending_unloads, l, l_next, ie)
{
if ((ie->need_unload) && (!ie->preload))
{
evas_common_rgba_image_unload_real(ie);
pending_unloads = eina_list_remove_list(pending_unloads, l);
}
}
}
EAPI void
evas_common_rgba_pending_unloads_remove(Image_Entry *ie)
{
if (!ie->need_unload) return;
ie->need_unload = 0;
pending_unloads = eina_list_remove(pending_unloads, ie);
}
EAPI void
evas_common_rgba_image_free(Image_Entry *ie)
{
if (ie->references > 0) return;
evas_common_rgba_pending_unloads_remove(ie);
_evas_common_rgba_image_surface_delete(ie);
_evas_common_rgba_image_delete(ie);
}
#ifdef SURFDBG
static Eina_List *surfs = NULL;
static void
surf_debug(void)
{
Eina_List *l;
Image_Entry *ie;
RGBA_Image *im;
int i = 0;
printf("----SURFS----\n");
EINA_LIST_FOREACH(surfs, l, ie)
{
im = ie;
printf("%i - %p - %ix%i [%s][%s]\n",
i, im->image.data, ie->allocated.w, ie->allocated.h,
ie->file, ie->key
);
i++;
}
}
#endif
EAPI void
evas_common_rgba_image_unload(Image_Entry *ie)
{
if (!ie->flags.loaded) return;
if ((!ie->info.module) && (!ie->data1)) return;
if (!ie->file && !ie->f) return;
if ((evas_cache_async_frozen_get() == 0) &&
(ie->references > 0))
{
if (!ie->need_unload)
{
pending_unloads = eina_list_append(pending_unloads, ie);
ie->need_unload = 1;
}
return;
}
if (!ie->need_unload) evas_common_rgba_image_unload_real(ie);
}
void
_evas_common_rgba_image_post_surface(Image_Entry *ie)
{
#ifdef HAVE_PIXMAN
# ifdef PIXMAN_IMAGE
RGBA_Image *im = (RGBA_Image *)ie;
int w, h;
if (!im->image.data) return;
if (im->pixman.im) pixman_image_unref(im->pixman.im);
w = ie->allocated.w;
h = ie->allocated.h;
if ((w <= 0) || (h <= 0))
{
w = im->cache_entry.w;
h = im->cache_entry.h;
}
if (im->cache_entry.flags.alpha)
{
im->pixman.im = pixman_image_create_bits
(
#ifdef WORDS_BIGENDIAN
PIXMAN_b8g8r8a8,
#else
PIXMAN_a8r8g8b8,
#endif
w, h, im->image.data, w * 4);
}
else
{
im->pixman.im = pixman_image_create_bits
(
#ifdef WORDS_BIGENDIAN
PIXMAN_b8g8r8x8,
#else
PIXMAN_x8r8g8b8,
#endif
w, h, im->image.data, w * 4);
}
# else
(void)ie;
# endif
#else
(void)ie;
#endif
}
static int
_evas_common_rgba_image_surface_alloc(Image_Entry *ie,
unsigned int w, unsigned int h)
{
RGBA_Image *im = (RGBA_Image *) ie;
int l = 0, r = 0, t = 0, b = 0;
if (im->image.no_free) return 0;
if (im->image.data)
{
evas_common_rgba_image_surface_munmap(im->image.data,
ie->allocated.w, ie->allocated.h,
ie->space);
im->image.data = NULL;
#ifdef SURFDBG
surfs = eina_list_remove(surfs, ie);
#endif
}
l = ie->borders.l;
r = ie->borders.r;
t = ie->borders.t;
b = ie->borders.b;
im->image.data = _evas_common_rgba_image_surface_mmap(ie, w, h,
&l, &r, &t, &b);
if (!im->image.data) return -1;
ie->borders.l = l;
ie->borders.r = r;
ie->borders.t = t;
ie->borders.b = b;
ie->allocated.w = w + l + r;
ie->allocated.h = h + t + b;
#ifdef SURFDBG
surfs = eina_list_append(surfs, ie);
#endif
#ifdef HAVE_VALGRIND
int siz = 0;
siz = _evas_common_rgba_image_surface_size(w, h, ie->space, &l, &r, &t, &b);
# ifdef VALGRIND_MAKE_READABLE
if (siz > 0) VALGRIND_MAKE_READABLE(im->image.data, siz);
# else
# ifdef VALGRIND_MAKE_MEM_DEFINED
if (siz > 0) VALGRIND_MAKE_MEM_DEFINED(im->image.data, siz);
# endif
# endif
#endif
_evas_common_rgba_image_post_surface(ie);
#ifdef SURFDBG
surf_debug();
#endif
return 0;
}
static void
_evas_common_rgba_image_surface_delete(Image_Entry *ie)
{
RGBA_Image *im = (RGBA_Image *) ie;
#ifdef HAVE_PIXMAN
# ifdef PIXMAN_IMAGE
if (im->pixman.im)
{
pixman_image_unref(im->pixman.im);
im->pixman.im = NULL;
}
# endif
#endif
if (ie->file) DBG("unload: [%p] %s %s", ie, ie->file, ie->key);
if ((im->cs.data) && (im->image.data))
{
if (im->cs.data != im->image.data)
{
if (!im->cs.no_free) free(im->cs.data);
}
}
else if (im->cs.data)
{
if (!im->cs.no_free) free(im->cs.data);
}
im->cs.data = NULL;
if (im->image.data && !im->image.no_free)
{
evas_common_rgba_image_surface_munmap(im->image.data,
ie->allocated.w, ie->allocated.h,
ie->space);
#ifdef SURFDBG
surfs = eina_list_remove(surfs, ie);
#endif
}
im->image.data = NULL;
ie->allocated.w = 0;
ie->allocated.h = 0;
ie->flags.preload_done = 0;
ie->flags.loaded = 0;
evas_common_rgba_image_scalecache_dirty(&im->cache_entry);
#ifdef SURFDBG
surf_debug();
#endif
}
static void
_evas_common_rgba_image_unload(Image_Entry *im)
{
evas_common_rgba_image_scalecache_dirty(im);
evas_common_rgba_image_unload(im);
}
static void
_evas_common_rgba_image_dirty_region(Image_Entry* ie,
unsigned int x EINA_UNUSED,
unsigned int y EINA_UNUSED,
unsigned int w EINA_UNUSED,
unsigned int h EINA_UNUSED)
{
RGBA_Image *im = (RGBA_Image *) ie;
im->flags |= RGBA_IMAGE_IS_DIRTY;
evas_common_rgba_image_scalecache_dirty(&im->cache_entry);
}
/* Only called when references > 0. Need to provide a fresh copie of im. */
static int
_evas_common_rgba_image_dirty(Image_Entry *ie_dst, const Image_Entry *ie_src)
{
RGBA_Image *dst = (RGBA_Image *) ie_dst;
RGBA_Image *src = (RGBA_Image *) ie_src;
evas_common_rgba_image_scalecache_dirty((Image_Entry *)ie_src);
evas_common_rgba_image_scalecache_dirty(ie_dst);
evas_cache_image_load_data(&src->cache_entry);
if (!evas_cache_image_pixels(ie_dst))
{
if (_evas_common_rgba_image_surface_alloc(&dst->cache_entry,
src->cache_entry.w,
src->cache_entry.h))
{
return 1;
}
}
evas_common_image_colorspace_normalize(src);
evas_common_image_colorspace_normalize(dst);
return 0;
}
static int
_evas_common_rgba_image_ram_usage(Image_Entry *ie)
{
RGBA_Image *im = (RGBA_Image *)ie;
int size = sizeof(struct _RGBA_Image);
if (ie->cache_key) size += strlen(ie->cache_key);
if (ie->file) size += strlen(ie->file);
if (ie->key) size += strlen(ie->key);
if (ie->f && eina_file_virtual(ie->f)) size += eina_file_size_get(ie->f);
if (im->image.data)
{
if ((!im->image.no_free))
size += im->cache_entry.w * im->cache_entry.h * sizeof(DATA32);
}
size += evas_common_rgba_image_scalecache_usage_get(&im->cache_entry);
return size;
}
static DATA32 *
_evas_common_rgba_image_surface_pixels(Image_Entry *ie)
{
RGBA_Image *im = (RGBA_Image *)ie;
return im->image.data;
}
static RGBA_Image *
evas_common_image_create(unsigned int w, unsigned int h)
{
RGBA_Image *im;
im = (RGBA_Image *) _evas_common_rgba_image_new();
if (!im) return NULL;
im->cache_entry.w = w;
im->cache_entry.h = h;
if (_evas_common_rgba_image_surface_alloc(&im->cache_entry, w, h))
{
_evas_common_rgba_image_delete(&im->cache_entry);
return NULL;
}
im->cache_entry.flags.cached = 0;
return im;
}
EAPI RGBA_Image *
evas_common_image_alpha_create(unsigned int w, unsigned int h)
{
RGBA_Image *im;
im = (RGBA_Image *) _evas_common_rgba_image_new();
if (!im) return NULL;
im->cache_entry.w = w;
im->cache_entry.h = h;
im->cache_entry.flags.alpha = 1;
if (_evas_common_rgba_image_surface_alloc(&im->cache_entry, w, h))
{
_evas_common_rgba_image_delete(&im->cache_entry);
return NULL;
}
im->cache_entry.flags.cached = 0;
return im;
}
EAPI RGBA_Image *
evas_common_image_new(unsigned int w, unsigned int h, unsigned int alpha)
{
if (alpha) return evas_common_image_alpha_create(w, h);
return evas_common_image_create(w, h);
}
void
evas_common_image_colorspace_normalize(RGBA_Image *im)
{
if ((!im->cs.data) ||
((!im->cs.dirty) && (!(im->flags & RGBA_IMAGE_IS_DIRTY)))) return;
switch (im->cache_entry.space)
{
case EVAS_COLORSPACE_ARGB8888:
case EVAS_COLORSPACE_GRY8:
case EVAS_COLORSPACE_AGRY88:
if (im->image.data != im->cs.data)
{
if (!im->image.no_free)
{
evas_common_rgba_image_surface_munmap
(im->image.data,
im->cache_entry.allocated.w,
im->cache_entry.allocated.h,
im->cache_entry.space);
#ifdef SURFDBG
surfs = eina_list_remove(surfs, im);
#endif
((Image_Entry *)im)->allocated.w = 0;
((Image_Entry *)im)->allocated.h = 0;
}
im->image.data = im->cs.data;
im->cs.no_free = im->image.no_free;
}
break;
case EVAS_COLORSPACE_YCBCR422P601_PL:
if ((im->image.data) && (*((unsigned char **)im->cs.data)))
evas_common_convert_yuv_422p_601_rgba(im->cs.data,
(DATA8 *)im->image.data,
im->cache_entry.w,
im->cache_entry.h);
break;
case EVAS_COLORSPACE_YCBCR422601_PL:
if ((im->image.data) && (*((unsigned char **)im->cs.data)))
evas_common_convert_yuv_422_601_rgba(im->cs.data,
(DATA8 *)im->image.data,
im->cache_entry.w,
im->cache_entry.h);
break;
case EVAS_COLORSPACE_YCBCR420NV12601_PL:
if ((im->image.data) && (*((unsigned char **)im->cs.data)))
evas_common_convert_yuv_420_601_rgba(im->cs.data,
(DATA8 *)im->image.data,
im->cache_entry.w,
im->cache_entry.h);
break;
case EVAS_COLORSPACE_YCBCR420TM12601_PL:
if ((im->image.data) && (*((unsigned char **)im->cs.data)))
evas_common_convert_yuv_420T_601_rgba(im->cs.data,
(DATA8 *)im->image.data,
im->cache_entry.w,
im->cache_entry.h);
break;
case EMILE_COLORSPACE_YCBCR422P709_PL:
if ((im->image.data) && (*((unsigned char **)im->cs.data)))
evas_common_convert_yuv_422p_709_rgba(im->cs.data,
(DATA8 *)im->image.data,
im->cache_entry.w,
im->cache_entry.h);
break;
default:
break;
}
im->cs.dirty = 0;
#ifdef SURFDBG
surf_debug();
#endif
}
EAPI void
evas_common_image_colorspace_dirty(RGBA_Image *im)
{
im->cs.dirty = 1;
evas_common_rgba_image_scalecache_dirty(&im->cache_entry);
#ifdef HAVE_PIXMAN
# ifdef PIXMAN_IMAGE
if (im->pixman.im)
{
pixman_image_unref(im->pixman.im);
im->pixman.im = NULL;
}
_evas_common_rgba_image_post_surface((Image_Entry *)im);
# endif
#endif
}
EAPI void
evas_common_image_set_cache(unsigned int size)
{
if (eci)
evas_cache_image_set(eci, size);
}
EAPI int
evas_common_image_get_cache(void)
{
return evas_cache_image_get(eci);
}
EAPI RGBA_Image *
evas_common_load_image_from_file(const char *file, const char *key,
Evas_Image_Load_Opts *lo, int *error)
{
if (!file)
{
*error = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
return (RGBA_Image *) evas_cache_image_request(eci, file, key, lo, error);
}
EAPI RGBA_Image *
evas_common_load_image_from_mmap(Eina_File *f, const char *key,
Evas_Image_Load_Opts *lo, int *error)
{
if (!f)
{
*error = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
return (RGBA_Image *) evas_cache_image_mmap_request(eci, f, key, lo, error);
}
EAPI void
evas_common_image_cache_free(void)
{
evas_common_image_set_cache(0);
}
EAPI Evas_Cache_Image*
evas_common_image_cache_get(void)
{
return eci;
}
EAPI RGBA_Image *
evas_common_image_line_buffer_obtain(int len)
{
if (len < 1) return NULL;
if (len < EVAS_RGBA_LINE_BUFFER_MIN_LEN)
len = EVAS_RGBA_LINE_BUFFER_MIN_LEN;
return evas_common_image_create(len, 1);
}
EAPI void
evas_common_image_line_buffer_release(RGBA_Image *im)
{
_evas_common_rgba_image_delete(&im->cache_entry);
}
EAPI void
evas_common_image_line_buffer_free(RGBA_Image *im)
{
_evas_common_rgba_image_delete(&im->cache_entry);
}
EAPI RGBA_Image *
evas_common_image_alpha_line_buffer_obtain(int len)
{
if (len < 1) return NULL;
if (len < EVAS_ALPHA_LINE_BUFFER_MIN_LEN)
len = EVAS_ALPHA_LINE_BUFFER_MIN_LEN;
return evas_common_image_alpha_create(len, 1);
}
EAPI void
evas_common_image_alpha_line_buffer_release(RGBA_Image *im)
{
_evas_common_rgba_image_delete(&im->cache_entry);
}
EAPI void
evas_common_image_premul(Image_Entry *ie)
{
DATA32 nas = 0;
if (!ie) return;
if (!evas_cache_image_pixels(ie)) return;
if (!ie->flags.alpha) return;
switch (ie->space)
{
case EVAS_COLORSPACE_ARGB8888:
nas = evas_common_convert_argb_premul
(evas_cache_image_pixels(ie), ie->w * ie->h);
break;
case EVAS_COLORSPACE_AGRY88:
nas = evas_common_convert_ag_premul
((void *)evas_cache_image_pixels(ie), ie->w * ie->h);
default: return;
}
if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (ie->w * ie->h))
ie->flags.alpha_sparse = 1;
}
EAPI void
evas_common_image_set_alpha_sparse(Image_Entry *ie)
{
DATA32 *s, *se;
DATA32 nas = 0;
if (!ie) return;
if (!evas_cache_image_pixels(ie)) return;
if (!ie->flags.alpha) return;
s = evas_cache_image_pixels(ie);
se = s + (ie->w * ie->h);
while (s < se)
{
DATA32 p = *s & 0xff000000;
if (!p || (p == 0xff000000)) nas++;
s++;
}
if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (ie->w * ie->h))
ie->flags.alpha_sparse = 1;
}