Evas: Add SW engine map/unmap functions

Also, fix some of the code using them.
This commit is contained in:
Jean-Philippe Andre 2016-03-23 13:33:08 +09:00
parent 078117d367
commit d5b0b1e683
8 changed files with 405 additions and 15 deletions

View File

@ -4,9 +4,9 @@ enum Efl.Gfx.Colorspace {
ycbcr422p709_pl, [[YCbCr 4:2:2 Planar, ITU.BT-709 specifications. The data pointed to is just an array of row pointer, pointing to the Y rows, then the Cb, then Cr rows.]]
rgb565_a5p, [[16bit rgb565 + Alpha plane at end - 5 bits of the 8 being used per alpha byte.]]
gry8 = 4, [[8-bit gray image, or alpha only.]]
ycbcr422601_pl, [[ YCbCr 4:2:2, ITU.BT-601 specifications. The data pointed to is just an array of row pointer, pointing to line of Y,Cb,Y,Cr bytes.]]
ycbcr420nv12601_pl, [[YCbCr 4:2:0, ITU.BT-601 specification. The data pointed to is just an array of row pointer, pointing to the Y rows, then the Cb,Cr rows..]]
ycbcr420tm12601_pl, [[YCbCr 4:2:0, ITU.BT-601 specification. The data pointed to is just an array of tiled row pointer, pointing to the Y rows, then the Cb,Cr rows..]]
ycbcr422601_pl, [[YCbCr 4:2:2, ITU.BT-601 specifications. The data pointed to is just an array of row pointer, pointing to line of Y,Cb,Y,Cr bytes.]]
ycbcr420nv12601_pl, [[YCbCr 4:2:0, ITU.BT-601 specifications. The data pointed to is just an array of row pointer, pointing to the Y rows, then the Cb,Cr rows..]]
ycbcr420tm12601_pl, [[YCbCr 4:2:0, ITU.BT-601 specifications. The data pointed to is just an array of tiled row pointer, pointing to the Y rows, then the Cb,Cr rows..]]
agry88 = 8, [[AY 8bits Alpha and 8bits Grey, accessed 1 16bits at a time.]]
etc1 = 9, [[OpenGL ETC1 encoding of RGB texture (4 bit per pixel) @since 1.10.]]
rgb8_etc2 = 10, [[OpenGL GL_COMPRESSED_RGB8_ETC2 texture compression format (4 bit per pixel) @since 1.10.]]

View File

@ -38,6 +38,21 @@ _efl_canvas_image_class_destructor(Eo_Class *eo_class EINA_UNUSED)
_map_data_cow = NULL;
}
EOLIAN static Eo_Base *
_efl_canvas_image_eo_base_constructor(Eo *obj, Efl_Canvas_Image_Data *pd)
{
obj = eo_constructor(eo_super(obj, MY_CLASS));
pd->map_data = eina_cow_alloc(_map_data_cow);
return obj;
}
EOLIAN static void
_efl_canvas_image_eo_base_destructor(Eo *obj, Efl_Canvas_Image_Data *pd)
{
eina_cow_free(_map_data_cow, (const Eina_Cow_Data **) &pd->map_data);
eo_destructor(eo_super(obj, MY_CLASS));
}
Eina_Bool
_evas_image_mmap_set(Eo *eo_obj, const Eina_File *f, const char *key)
{
@ -805,7 +820,11 @@ _efl_canvas_image_efl_gfx_buffer_buffer_map(Eo *eo_obj, Efl_Canvas_Image_Data *p
goto end; // not implemented
if (!o->engine_data)
goto end;
{
if (o->cur->u.file)
ERR("image is not loaded yet");
goto end;
}
if ((x < 0) || (y < 0) || ((x + (int) w) > (int) o->cur->image.w) || ((y + (int) h) > (int) o->cur->image.h))
{
@ -839,7 +858,7 @@ _efl_canvas_image_efl_gfx_buffer_buffer_unmap(Eo *eo_obj, Efl_Canvas_Image_Data
Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
Map_Data *map;
if (!ENFN->image_data_map)
if (!ENFN->image_data_unmap)
goto fail; // not implemented
if (!o->engine_data)
@ -855,6 +874,8 @@ _efl_canvas_image_efl_gfx_buffer_buffer_unmap(Eo *eo_obj, Efl_Canvas_Image_Data
free(map);
}
return;
fail:
ERR("unmap failed");
}

View File

@ -1,4 +1,4 @@
class Efl.Canvas.Image (Evas.Image, Efl.Image_Load, Efl.Image_Animated)
class Efl.Canvas.Image (Evas.Image, Efl.Gfx.Buffer, Efl.Image_Load, Efl.Image_Animated)
{
[[Low-level Image object.
@ -9,6 +9,8 @@ class Efl.Canvas.Image (Evas.Image, Efl.Image_Load, Efl.Image_Animated)
implements {
class.constructor;
class.destructor;
Eo.Base.constructor;
Eo.Base.destructor;
Efl.Gfx.Buffer.buffer_data_get;
Efl.Gfx.Buffer.buffer_data_set;
Efl.Gfx.Buffer.buffer_copy_set;

View File

@ -76,7 +76,8 @@ EAPI int evas_common_load_rgba_image_data_from_file (Image_Entry *im);
EAPI double evas_common_load_rgba_image_frame_duration_from_file(Image_Entry *im, int start_frame, int frame_num);
void _evas_common_rgba_image_post_surface(Image_Entry *ie);
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);
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);
EAPI int _evas_common_rgba_image_data_offset(int rx, int ry, int rw, int rh, int plane, const RGBA_Image *im);
EAPI Eina_Bool evas_common_extension_can_load_get(const char *file);

View File

@ -110,7 +110,7 @@ static const Evas_Cache2_Image_Func _evas_common_image_func2 =
};
#endif
int
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)
@ -179,6 +179,93 @@ _evas_common_rgba_image_surface_size(unsigned int w, unsigned int h,
#undef ALIGN_TO_PAGE
}
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)

View File

@ -428,6 +428,7 @@ typedef struct _RGBA_Font_Source RGBA_Font_Source;
typedef struct _RGBA_Font_Glyph RGBA_Font_Glyph;
typedef struct _RGBA_Font_Glyph_Out RGBA_Font_Glyph_Out;
typedef struct _RGBA_Gfx_Compositor RGBA_Gfx_Compositor;
typedef struct _RGBA_Image_Data_Map RGBA_Image_Data_Map;
typedef struct _Cutout_Rect Cutout_Rect;
typedef struct _Cutout_Rects Cutout_Rects;
@ -832,6 +833,18 @@ struct _RGBA_Pipe_Thread_Info
};
#endif
struct _RGBA_Image_Data_Map {
EINA_INLIST;
unsigned char *ptr;
unsigned int size, stride; // in bytes
int rx, ry, rw, rh; // actual map region
unsigned char *baseptr;
unsigned char plane;
Evas_Colorspace cspace;
Eina_Bool allocated; // ptr is malloc() for cow or cspace conv
Efl_Gfx_Buffer_Access_Mode mode;
};
struct _RGBA_Image
{
Image_Entry cache_entry;
@ -879,6 +892,9 @@ struct _RGBA_Image
void *data;
} func;
} native;
/* data map/unmap */
RGBA_Image_Data_Map *maps;
};
struct _RGBA_Polygon_Point

View File

@ -11,6 +11,7 @@
#include "cairo/Ector_Cairo.h"
#include "evas_ector_buffer.eo.h"
#include "evas_ector_software_buffer.eo.h"
#include "draw.h"
#if defined HAVE_DLSYM && ! defined _WIN32
# include <dlfcn.h> /* dlopen,dlclose,etc */
@ -1436,6 +1437,267 @@ eng_image_data_put(void *data, void *image, DATA32 *image_data)
return im;
}
static void *
eng_image_data_map(void *engdata EINA_UNUSED, void **image,
unsigned int *length, unsigned int *stride,
int x, int y, int w, int h,
Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode)
{
Eina_Bool cow = EINA_FALSE, to_write = EINA_FALSE;
RGBA_Image_Data_Map *map;
RGBA_Image *im = *image;
Image_Entry *ie = &im->cache_entry;
int src_stride, src_offset;
void *data;
EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image, NULL);
// FIXME: implement planes support (YUV, RGB565, ETC1+Alpha)
// FIXME: implement YUV support (im->cs.data)
if (!im->image.data)
{
int error = evas_cache_image_load_data(ie);
if (error != EVAS_LOAD_ERROR_NONE)
return NULL;
}
if (mode & EFL_GFX_BUFFER_ACCESS_MODE_COW)
cow = EINA_TRUE;
if (mode & EFL_GFX_BUFFER_ACCESS_MODE_WRITE)
to_write = EINA_TRUE;
// verify region is valid regarding special colorspaces (ETC, S3TC, YUV)
src_offset = _evas_common_rgba_image_data_offset(x, y, w, h, 0, im);
if ((src_offset < 0) || !w || !h)
{
ERR("invalid region for colorspace %d: %dx%d + %d,%d, image: %dx%d",
cspace, w, h, x, y, ie->w, ie->h);
return NULL;
}
src_stride = _evas_common_rgba_image_data_offset(ie->w, 0, 0, 0, 0, im);
// safety check for COW flag
EINA_INLIST_FOREACH(im->maps, map)
{
if ((!(map->mode & EFL_GFX_BUFFER_ACCESS_MODE_COW)) != (!cow))
{
ERR("can't map shared image data multiple times with "
"different COW flag");
return NULL;
}
}
// ensure that we are the sole owner of this image entry.
if (cow)
{
ie = evas_cache_image_alone(ie);
if (!ie) return NULL;
im = (RGBA_Image *) ie;
*image = im;
}
else
{
if (to_write && (ie->references > 1))
{
ERR("write map requires COW flag for shared images");
return NULL;
}
}
if (cspace != ie->space)
{
// using 4x4 "blocks" to support etc1/2, s3tc...
// note: no actual stride support
Cspace_Convert_Func cs_func;
Eina_Bool can_region;
RGBA_Image fake;
int rx, ry, rw, rh;
void *src_data;
int dst_stride, dst_len, dst_offset = 0;
cs_func = efl_draw_convert_func_get(ie->space, cspace, &can_region);
if (!cs_func) return NULL;
// make sure we can convert back, if map for writing
if (to_write && !efl_draw_convert_func_get(cspace, ie->space, NULL))
return NULL;
if (can_region)
{
rx = x;
ry = y;
rw = w;
rh = h;
src_data = im->image.data8 + src_offset;
}
else
{
rx = 0;
ry = 0;
rw = ie->w;
rh = ie->h;
src_data = im->image.data8;
}
// a bit hacky, but avoids passing too many parameters to the function
fake.cache_entry.w = rw;
fake.cache_entry.h = rh;
fake.cache_entry.space = cspace;
dst_stride = _evas_common_rgba_image_data_offset(rw, 0, 0, 0, 0, &fake);
if (!can_region)
dst_offset = _evas_common_rgba_image_data_offset(rx, ry, 0, 0, 0, &fake);
dst_len = rh * dst_stride;
data = malloc(dst_len);
if (!data) return NULL;
if (!cs_func(data, src_data, rw, rh, src_stride, dst_stride, ie->flags.alpha, ie->space, cspace))
{
ERR("color conversion failed");
free(data);
return NULL;
}
map = calloc(1, sizeof(*map));
map->allocated = EINA_TRUE;
map->cspace = cspace;
map->rx = rx;
map->ry = ry;
map->rh = rh;
map->rw = rw;
map->mode = mode;
map->baseptr = data;
map->ptr = map->baseptr + dst_offset;
map->size = dst_len;
map->stride = dst_stride;
}
else
{
// same colorspace
if (!to_write || !cow)
{
// no copy
int end_offset = _evas_common_rgba_image_data_offset(x + w, y + h, 0, 0, 0, im) - src_stride;
map = calloc(1, sizeof(*map));
map->baseptr = im->image.data8;
map->ptr = im->image.data8 + src_offset;
map->size = end_offset - src_offset;
}
else
{
// copy
int size = _evas_common_rgba_image_data_offset(w, h, 0, 0, 0, im);
data = malloc(size);
if (!data) return NULL;
memcpy(data, im->image.data8 + src_offset, size);
map = calloc(1, sizeof(*map));
map->allocated = EINA_TRUE;
map->baseptr = data;
map->ptr = data;
map->size = size;
}
map->cspace = cspace;
map->rx = x;
map->ry = y;
map->rw = w;
map->rh = h;
map->stride = src_stride;
}
if (map)
{
im->maps = (RGBA_Image_Data_Map *)
eina_inlist_prepend(EINA_INLIST_GET(im->maps), EINA_INLIST_GET(map));
if (length) *length = map->size;
if (stride) *stride = map->stride;
return map->ptr;
}
return NULL;
}
static void
_image_data_commit(RGBA_Image *im, RGBA_Image_Data_Map *map)
{
Image_Entry *ie = &im->cache_entry;
int dst_offset = _evas_common_rgba_image_data_offset(map->rx, map->ry, 0, 0, map->plane, im);
int dst_stride = _evas_common_rgba_image_data_offset(ie->w, 0, 0, 0, map->plane, im);
unsigned char *dst = im->image.data8 + dst_offset;
if (map->cspace == ie->space)
{
if (dst_stride == (int) map->stride)
{
DBG("unmap commit: single memcpy");
memcpy(dst, map->ptr, dst_stride * map->rh);
}
else
{
DBG("unmap commit: multiple memcpy");
for (int k = 0; k < dst_stride; k++)
memcpy(dst + k * dst_stride, map->ptr + k * dst_stride, dst_stride);
}
}
else
{
Cspace_Convert_Func cs_func;
Eina_Bool can_region;
cs_func = efl_draw_convert_func_get(map->cspace, ie->space, &can_region);
EINA_SAFETY_ON_NULL_RETURN(cs_func);
DBG("unmap commit: convert func (%p)", cs_func);
if (can_region)
{
cs_func(dst, map->ptr, map->rw, map->rh, map->stride, dst_stride,
ie->flags.alpha, map->cspace, ie->space);
}
else
{
cs_func(dst, map->baseptr, ie->w, ie->h, map->stride, dst_stride,
ie->flags.alpha, map->cspace, ie->space);
}
}
}
static void *
eng_image_data_unmap(void *engdata EINA_UNUSED, void *image, void *memory, unsigned int length)
{
RGBA_Image_Data_Map *map;
RGBA_Image *im = image;
Eina_Bool found = EINA_FALSE;
if (!im || !memory) return im;
EINA_INLIST_FOREACH(EINA_INLIST_GET(im->maps), map)
{
if ((map->ptr == memory) && (map->size == length))
{
found = EINA_TRUE;
if (map->allocated)
{
if (map->mode & EFL_GFX_BUFFER_ACCESS_MODE_WRITE)
_image_data_commit(im, map);
free(map->baseptr);
}
im->maps = (RGBA_Image_Data_Map *)
eina_inlist_remove(EINA_INLIST_GET(im->maps), EINA_INLIST_GET(map));
free(map);
break;
}
}
if (!found)
ERR("failed to unmap region %p (%u bytes)", memory, length);
return im;
}
static void
_image_flip_horizontal(DATA32 *pixels_out, const DATA32 *pixels_in,
int iw, int ih)
@ -4131,8 +4393,8 @@ static Evas_Func func =
eng_image_colorspace_get,
eng_image_file_colorspace_get,
eng_image_can_region_get,
NULL, // image_data_map
NULL, // image_data_unmap
eng_image_data_map,
eng_image_data_unmap,
eng_image_native_init,
eng_image_native_shutdown,
eng_image_native_set,

View File

@ -431,11 +431,11 @@ efl_draw_convert_func_get(Efl_Gfx_Colorspace srccs, Efl_Gfx_Colorspace dstcs,
EINA_SAFETY_ON_FALSE_RETURN_VAL(srccs != dstcs, NULL);
if (dstcs != EFL_GFX_COLORSPACE_ARGB8888)
to_argb = efl_draw_convert_func_get(srccs, EFL_GFX_COLORSPACE_ARGB8888, &reg1);
if (srccs != EFL_GFX_COLORSPACE_ARGB8888)
from_argb = efl_draw_convert_func_get(EFL_GFX_COLORSPACE_ARGB8888, dstcs, &reg2);
if ((dstcs != EFL_GFX_COLORSPACE_ARGB8888) && (srccs != EFL_GFX_COLORSPACE_ARGB8888))
{
to_argb = efl_draw_convert_func_get(srccs, EFL_GFX_COLORSPACE_ARGB8888, &reg1);
from_argb = efl_draw_convert_func_get(EFL_GFX_COLORSPACE_ARGB8888, dstcs, &reg2);
}
if (region_can) *region_can = EINA_TRUE;
@ -523,5 +523,6 @@ efl_draw_convert_func_get(Efl_Gfx_Colorspace srccs, Efl_Gfx_Colorspace dstcs,
}
ERR("unsupported colorspace conversion from %d to %d", srccs, dstcs);
if (region_can) *region_can = EINA_FALSE;
return NULL;
}