evas: Switch EO APIs to Eina_Slice for gfx buffers (map)

This adds a plane and eina slice argument to the map/unmap
functions, instead of void_ptr + length.
This commit is contained in:
Jean-Philippe Andre 2016-09-01 21:46:42 +09:00
parent 1773ba5d82
commit 8ee431572d
10 changed files with 296 additions and 202 deletions

View File

@ -26,8 +26,8 @@
#define IMG_WIDTH 256
#define IMG_HEIGHT 256
// TODO: remove this when map/unmap are fully supported (GL engine)
#undef USE_EO_IMAGE
// undef this to test the legacy API for images
#define USE_EO_IMAGE
typedef struct _Scene_Data
{
@ -73,7 +73,7 @@ _animate_scene(void *data)
static float angle = 0.0f;
Scene_Data *scene = (Scene_Data *)data;
unsigned int *pixels;
int i, j, stride, length;
int i, j, stride;
angle += 0.5;
@ -83,11 +83,12 @@ _animate_scene(void *data)
if (angle > 360.0) angle -= 360.0f;
#ifdef USE_EO_IMAGE
pixels = efl_gfx_buffer_map(source, &length, EFL_GFX_BUFFER_ACCESS_MODE_WRITE, 0, 0, 0, 0,
EFL_GFX_COLORSPACE_ARGB8888, &stride);
if (!pixels) return EINA_TRUE;
Eina_Rw_Slice slice;
if (!efl_gfx_buffer_map(source, &slice, EFL_GFX_BUFFER_ACCESS_MODE_WRITE, 0, 0, 0, 0,
EFL_GFX_COLORSPACE_ARGB8888, 0, &stride))
return EINA_TRUE;
pixels = slice.mem;
#else
(void) length;
pixels = evas_object_image_data_get(source, EINA_TRUE);
stride = evas_object_image_stride_get(source);
#endif
@ -103,7 +104,7 @@ _animate_scene(void *data)
}
#ifdef USE_EO_IMAGE
efl_gfx_buffer_unmap(source, pixels, length);
efl_gfx_buffer_unmap(source, &slice);
efl_gfx_buffer_update_add(source, 0, 0, IMG_WIDTH, IMG_HEIGHT);
#else
evas_object_image_data_set(source, pixels);
@ -226,7 +227,7 @@ main(void)
/* Add a background image. */
#ifdef USE_EO_IMAGE
source = efl_add(EFL_CANVAS_IMAGE_CLASS, evas);
efl_gfx_buffer_data_set(source, NULL, WIDTH, HEIGHT, 0, EFL_GFX_COLORSPACE_ARGB8888);
efl_gfx_buffer_copy_set(source, NULL, IMG_WIDTH, IMG_HEIGHT, 0, EFL_GFX_COLORSPACE_ARGB8888, 0);
efl_gfx_position_set(source, (WIDTH / 2), (HEIGHT / 2));
efl_gfx_size_set(source, (WIDTH / 2), (HEIGHT / 2));
efl_gfx_visible_set(source, EINA_TRUE);

View File

@ -1,4 +1,5 @@
import efl_gfx_types;
import eina_types;
/* FIXME: this is very very low level. expose to apps? */
enum Efl.Gfx.Buffer.Access_Mode {
@ -8,6 +9,8 @@ enum Efl.Gfx.Buffer.Access_Mode {
cow = 0x4, [[Forces copy-on-write if already mapped as read-only. Requires write.]]
}
/* FIXME: YUV and other planar formats are not properly handled in this API! */
interface Efl.Gfx.Buffer ()
{
[[Common APIs for all objects representing images and 2D pixel buffers.]]
@ -129,7 +132,7 @@ interface Efl.Gfx.Buffer ()
be negative.
]]
params {
@out length: int @nonull; [[Accessible buffer size in bytes, should not be $null.]]
@out slice: Eina.Rw_Slice; [[Pointer to the top-left pixel data.]]
@in mode: Efl.Gfx.Buffer.Access_Mode; [[Specifies whether to map for read-only,
write-only or read-write access (OR combinaison of flags).]]
@in x: int @optional; [[X position of the top-left pixel to map, defaults to 0.]]
@ -139,48 +142,25 @@ interface Efl.Gfx.Buffer ()
@in cspace: Efl.Gfx.Colorspace @optional; [[Requested colorspace. If differen from the internal cspace,
map should try to convert the data into a new buffer.
argb8888 by default.]]
@in plane: int @optional; [[Plane ID. 0 by default. Useful for planar formats only.]]
@out stride: int @optional; [[Returns the length in bytes of a mapped line]]
}
return: void_ptr @warn_unused; [[Pointer to the top-left pixel data. Returns $null in case of failure]]
return: bool;
}
buffer_unmap {
[[Unmap a region of this buffer, and update the internal data if needed.
EFL will update the internal image if the map had write access.
Note: The $slice struct does not need to be the one returned
by @.buffer_map, only its contents ($mem and $len) must match. But
after a call to @.buffer_unmap the original $slice structure is not
valid anymore.
]]
params {
@in data: void_ptr; [[Data pointer returned by a previous call to map]]
@in length: int; [[Must be the same as returned by map.]]
@in slice: const(Eina.Rw_Slice)*; [[Data slice returned by a previous call to map.]]
}
return: bool; [[This will return $false in case of failure (invalid
parameters or state of the object).]]
}
/* FIXME: naming: buffer_set, buffer_attach, external_data_set, ...? */
buffer_data_set {
[[Set the pixels for this buffer, or allocate a new memory region.
EFL will use $pixels directly, and update the GPU-side texture
if required. This will mark the image as dirty.
If $pixels is $null, then a new empty buffer will be allocated.
If the buffer already had pixel data, the previous image data will
be dropped. This is the same as @.buffer_copy_set.
The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace.
See also @.buffer_copy_set if you want EFL to copy the input buffer
internally.
]]
params {
@in pixels: void_ptr @nullable; [[If $null, allocates an empty buffer]]
@in width: int;
@in height: int;
@in stride: int @optional; [[If 0, automatically guessed from the $width.]]
@in cspace: Efl.Gfx.Colorspace @optional; [[argb8888 by default.]]
}
return: bool @warn_unused; [[This function returns $false in case of failure.]]
return: bool;
}
buffer_copy_set {
[[Set the pixels for this buffer by copying them, or allocate
@ -192,32 +172,61 @@ interface Efl.Gfx.Buffer ()
If $pixels is $null, then a new empty buffer will be allocated.
If the buffer already had pixel data, the previous image data will
be dropped. This is the same as @.buffer_data_set.
be dropped. This is the same as @.buffer_managed_set.
The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace.
$pixels should not be the return value of @.buffer_data_get.
$slice should not be the return value of @.buffer_managed_get.
]]
params {
@in pixels: const(void_ptr) @nullable; [[If $null, allocates an empty buffer]]
@in slice: const(Eina.Slice)* @nullable; [[If $null, allocates an empty buffer]]
@in width: int;
@in height: int;
@in stride: int @optional; [[If 0, automatically guessed from the $width.]]
@in cspace: Efl.Gfx.Colorspace @optional; [[argb8888 by default.]]
@in plane: int @optional; [[Plane ID. 0 by default. Useful for planar formats only.]]
}
return: bool @warn_unused; [[This function returns $false in case of failure.]]
return: bool;
}
buffer_data_get {
buffer_managed_set {
[[Set the pixels for this buffer, managed externally by the client.
EFL will use the pixel data directly, and update the GPU-side
texture if required. This will mark the image as dirty. If $slice
is $null, this will detach the pixel data.
If the buffer already had pixel data, the previous image data will
be dropped. This is the same as @.buffer_copy_set.
The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace.
See also @.buffer_copy_set if you want EFL to copy the input buffer
internally.
]]
params {
@in slice: const(Eina.Slice)* @nullable; [[If $null, detaches the previous buffer.]]
@in width: int;
@in height: int;
@in stride: int @optional; [[If 0, automatically guessed from the $width.]]
@in cspace: Efl.Gfx.Colorspace @optional; [[argb8888 by default.]]
@in plane: int @optional; [[Plane ID. 0 by default. Useful for planar formats only.]]
}
return: bool;
}
buffer_managed_get {
[[Get a direct pointer to the internal pixel data, if available.
This will return $null unless @.buffer_data_set was used to pass in an
external data pointer.
Note: This is different from the legacy API data, which is now
replaced by map/unmap.
This will return $null unless @.buffer_managed_set was used to pass
in an external data pointer. The returned @Eina.Slice struct must be
freed by the caller.
]]
return: void_ptr @warn_unused;
params {
@out slice: Eina.Slice;
@in plane: int @optional; [[Plane ID. 0 by default. Useful for planar formats only.]]
}
return: bool;
}
/* Note: border, span and buffer flags not imported from ector buffer */
}

View File

@ -591,13 +591,22 @@ _efl_canvas_image_efl_gfx_buffer_buffer_size_get(Eo *eo_obj, void *_pd EINA_UNUS
static Eina_Bool
_image_pixels_set(Evas_Object_Protected_Data *obj,
Evas_Image_Data *o, void *pixels, int w, int h, int stride,
Efl_Gfx_Colorspace cspace, Eina_Bool copy)
Evas_Image_Data *o, const Eina_Slice *slice,
int w, int h, int stride, Efl_Gfx_Colorspace cspace, int plane,
Eina_Bool copy)
{
Eina_Bool resized = EINA_FALSE, ret = EINA_FALSE, easy_copy = EINA_FALSE;
int int_stride = 0;
void *pixels = NULL;
// FIXME: buffer border support is not implemented
// FIXME: implement YUV support
if (plane)
{
ERR("planar formats not supported yet");
return EINA_FALSE;
}
if (ENFN->image_data_maps_get)
{
@ -627,6 +636,12 @@ _image_pixels_set(Evas_Object_Protected_Data *obj,
o->file_obj = NULL;
}
if (!slice && !copy)
{
ret = EINA_TRUE;
goto end;
}
switch (cspace)
{
case EVAS_COLORSPACE_ARGB8888:
@ -638,6 +653,20 @@ _image_pixels_set(Evas_Object_Protected_Data *obj,
break;
}
// FIXME: Properly handle YUV and other planar formats
if (slice && easy_copy)
{
size_t len;
pixels = (void *) slice->mem;
len = _evas_common_rgba_image_surface_size(w, h, cspace, NULL, NULL, NULL, NULL);
if ((stride && (slice->len < (size_t) (stride * h))) || (slice->len < len))
{
ERR("data slice is too short! (%zub, %dx%d)", slice->len, w, h);
goto end;
}
}
int_stride = _evas_common_rgba_image_surface_size(w, 1, cspace, NULL, NULL, NULL, NULL);
if (!stride) stride = int_stride;
@ -738,50 +767,82 @@ end:
}
EOLIAN static Eina_Bool
_efl_canvas_image_efl_gfx_buffer_buffer_data_set(Eo *eo_obj, void *_pd EINA_UNUSED,
void *pixels, int w, int h, int stride,
Efl_Gfx_Colorspace cspace)
_efl_canvas_image_efl_gfx_buffer_buffer_managed_set(Eo *eo_obj, void *_pd EINA_UNUSED,
const Eina_Slice *slice,
int w, int h, int stride,
Efl_Gfx_Colorspace cspace,
int plane)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
return _image_pixels_set(obj, o, pixels, w, h, stride, cspace, EINA_FALSE);
return _image_pixels_set(obj, o, slice, w, h, stride, cspace, plane, EINA_FALSE);
}
EOLIAN static Eina_Bool
_efl_canvas_image_efl_gfx_buffer_buffer_copy_set(Eo *eo_obj, void *_pd EINA_UNUSED,
const void *pixels, int w, int h, int stride,
Efl_Gfx_Colorspace cspace)
const Eina_Slice *slice, int w, int h, int stride,
Efl_Gfx_Colorspace cspace, int plane)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
return _image_pixels_set(obj, o, (void *) pixels, w, h, stride, cspace, EINA_TRUE);
return _image_pixels_set(obj, o, slice, w, h, stride, cspace, plane, EINA_TRUE);
}
EOLIAN static void *
_efl_canvas_image_efl_gfx_buffer_buffer_data_get(Eo *eo_obj, void *_pd EINA_UNUSED EINA_UNUSED)
EOLIAN static Eina_Bool
_efl_canvas_image_efl_gfx_buffer_buffer_managed_get(Eo *eo_obj, void *_pd EINA_UNUSED EINA_UNUSED,
Eina_Slice *slice, int plane)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
Evas_Colorspace cspace = EVAS_COLORSPACE_ARGB8888;
int w = 0, h = 0;
void *pixels;
EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINA_FALSE);
slice->len = 0;
slice->mem = NULL;
if (plane)
{
ERR("planar formats not supported yet!");
return EINA_FALSE;
}
if (!o->buffer_data_set || !o->engine_data || !ENFN->image_data_direct)
return NULL;
return EINA_FALSE;
return ENFN->image_data_direct(ENDT, o->engine_data, NULL);
pixels = ENFN->image_data_direct(ENDT, o->engine_data, &cspace);
if (!pixels) return EINA_FALSE;
slice->mem = pixels;
// note: length may not be same as what was originally given
ENFN->image_size_get(ENDT, o->engine_data, &w, &h);
slice->len = _evas_common_rgba_image_surface_size(w, h, cspace, NULL, NULL, NULL, NULL);
return EINA_TRUE;
}
EOLIAN static void *
EOLIAN static Eina_Bool
_efl_canvas_image_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
int *length,
Eina_Rw_Slice *slice,
Efl_Gfx_Buffer_Access_Mode mode,
int x, int y, int w, int h,
Efl_Gfx_Colorspace cspace, int *stride)
Efl_Gfx_Colorspace cspace,
int plane, int *stride)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
int s = 0, width = 0, height = 0;
const Eina_Rw_Slice *slice = NULL;
Eina_Bool ret = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINA_FALSE);
slice->len = 0;
slice->mem = NULL;
if (!ENFN->image_data_map)
goto end; // not implemented
@ -807,34 +868,30 @@ _efl_canvas_image_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
goto end;
}
slice = ENFN->image_data_map(ENDT, &o->engine_data, &s, x, y, w, h, cspace, mode);
if (slice)
if (ENFN->image_data_map(ENDT, &o->engine_data, slice, &s, x, y, w, h, cspace, mode, plane))
{
DBG("map(%p, %d,%d %dx%d) -> %p (%zu bytes)", eo_obj, x, y, w, h,
slice->mem, slice->len);
DBG("map(%p, %d,%d %dx%d plane:%d) -> " EINA_SLICE_FMT,
eo_obj, x, y, w, h, plane, EINA_SLICE_PRINT(*slice));
ret = EINA_TRUE;
}
else DBG("map(%p, %d,%d %dx%d) -> (null)", eo_obj, x, y, w, h);
else DBG("map(%p, %d,%d %dx%d plane:%d) -> (null)", eo_obj, x, y, w, h, plane);
end:
if (length) *length = slice->len;
if (stride) *stride = s;
return slice->mem;
return ret;
}
EOLIAN static Eina_Bool
_efl_canvas_image_efl_gfx_buffer_buffer_unmap(Eo *eo_obj, void *_pd EINA_UNUSED,
void *data, int length)
const Eina_Rw_Slice *slice)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
Eina_Rw_Slice slice;
if (!ENFN->image_data_unmap || !o->engine_data)
if (!slice || !ENFN->image_data_unmap || !o->engine_data)
return EINA_FALSE;
slice.mem = data;
slice.len = length;
if (!ENFN->image_data_unmap(ENDT, o->engine_data, &slice))
if (!ENFN->image_data_unmap(ENDT, o->engine_data, slice))
return EINA_FALSE;
return EINA_TRUE;

View File

@ -10,8 +10,8 @@ class Efl.Canvas.Image (Efl.Canvas.Image.Internal, Efl.Gfx.Buffer,
]]
data: null;
implements {
Efl.Gfx.Buffer.buffer_data_get;
Efl.Gfx.Buffer.buffer_data_set;
Efl.Gfx.Buffer.buffer_managed_get;
Efl.Gfx.Buffer.buffer_managed_set;
Efl.Gfx.Buffer.buffer_copy_set;
Efl.Gfx.Buffer.buffer_size.get;
Efl.Gfx.Buffer.buffer_map;

View File

@ -259,25 +259,37 @@ _proxy_image_get(Evas_Image_Data *o)
return source->proxy->surface;
}
EOLIAN static void *
EOLIAN static Eina_Bool
_efl_canvas_proxy_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
int *length,
Eina_Rw_Slice *slice,
Efl_Gfx_Buffer_Access_Mode mode,
int x, int y, int w, int h,
Efl_Gfx_Colorspace cspace, int *stride)
Efl_Gfx_Colorspace cspace, int plane,
int *stride)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
int len = 0, s = 0, width = 0, height = 0;
const Eina_Rw_Slice *slice = NULL;
void *image, *data = NULL;
int s = 0, width = 0, height = 0;
Eina_Bool ret = EINA_FALSE;
void *image;
EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINA_FALSE);
slice->len = 0;
slice->mem = NULL;
if (!ENFN->image_data_map)
goto end; // not implemented
if (plane)
{
ERR("invalid plane id for proxy object");
goto end;
}
if (mode & EFL_GFX_BUFFER_ACCESS_MODE_WRITE)
{
ERR("invalid map mode for Proxy object");
ERR("invalid map mode for proxy object");
goto end;
}
@ -303,34 +315,30 @@ _efl_canvas_proxy_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
goto end;
}
slice = ENFN->image_data_map(ENDT, &image, &s, x, y, w, h, cspace, mode);
if (slice)
if (ENFN->image_data_map(ENDT, &o->engine_data, slice, &s, x, y, w, h, cspace, mode, plane))
{
DBG("map(%p, %d,%d %dx%d) -> %p (%zu bytes)", eo_obj, x, y, w, h,
slice->mem, slice->len);
DBG("map(%p, %d,%d %dx%d plane:%d) -> " EINA_SLICE_FMT,
eo_obj, x, y, w, h, plane, EINA_SLICE_PRINT(*slice));
ret = EINA_TRUE;
}
else DBG("map(%p, %d,%d %dx%d) -> (null)", eo_obj, x, y, w, h);
else DBG("map(%p, %d,%d %dx%d plane:%d) -> (null)", eo_obj, x, y, w, h, plane);
end:
if (length) *length = len;
if (stride) *stride = s;
return data;
return ret;
}
EOLIAN static Eina_Bool
_efl_canvas_proxy_efl_gfx_buffer_buffer_unmap(Eo *eo_obj, void *_pd EINA_UNUSED,
void *data, int length)
const Eina_Rw_Slice *slice)
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
Eina_Rw_Slice slice;
if (!ENFN->image_data_unmap || !o->engine_data)
if (!slice || !ENFN->image_data_unmap || !o->engine_data)
return EINA_FALSE;
slice.mem = data;
slice.len = length;
if (!ENFN->image_data_unmap(ENDT, o->engine_data, &slice))
if (!ENFN->image_data_unmap(ENDT, o->engine_data, slice))
return EINA_FALSE;
return EINA_TRUE;

View File

@ -208,12 +208,13 @@ _evas_image_3d_unset(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data
EINA_COW_WRITE_END(evas_object_3d_cow, obj->data_3d, data);
}
EOLIAN static void *
EOLIAN static Eina_Bool
_efl_canvas_scene3d_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
int *length EINA_UNUSED,
Efl_Gfx_Buffer_Access_Mode mode,
int x, int y, int w, int h,
Efl_Gfx_Colorspace cspace, int *stride EINA_UNUSED)
Eina_Rw_Slice *slice,
Efl_Gfx_Buffer_Access_Mode mode,
int x, int y, int w, int h,
Efl_Gfx_Colorspace cspace, int plane,
int *stride)
{
Evas_Image_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
Evas_Public_Data *e;
@ -221,21 +222,27 @@ _efl_canvas_scene3d_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
Evas_Canvas3D_Scene_Data *pd_scene;
int width = -1, height = -1, ntex = -1;
unsigned char *pixels = NULL;
size_t len = 0;
EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINA_FALSE);
slice->len = 0;
slice->mem = NULL;
if (!o->cur->scene)
{
ERR("invalid scene data");
return NULL;
return EINA_FALSE;
}
if (mode & EFL_GFX_BUFFER_ACCESS_MODE_WRITE)
{
ERR("invalid map access mode");
return NULL;
return EINA_FALSE;
}
if (cspace != EFL_GFX_COLORSPACE_ARGB8888)
{
ERR("invalid map colorspace. Only ARGB is supported");
return NULL;
return EINA_FALSE;
}
pd_parent = efl_data_scope_get(o->cur->scene, EVAS_CANVAS3D_OBJECT_CLASS);
@ -252,7 +259,7 @@ _efl_canvas_scene3d_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
{
ERR("Invalid map dimensions : %dx%d +%d,%d. Image is %dx%d.",
w, h, x, y, width, height);
return NULL;
return EINA_FALSE;
}
if (e->engine.func->drawable_texture_target_id_get)
@ -261,23 +268,30 @@ _efl_canvas_scene3d_efl_gfx_buffer_buffer_map(Eo *eo_obj, void *_pd EINA_UNUSED,
if (e->engine.func->drawable_texture_rendered_pixels_get)
{
pixels = malloc(w * h * sizeof(DATA32)); //four component texture
len = w * h * sizeof(DATA32); //four component texture
pixels = malloc(len + sizeof(*slice) + 8);
e->engine.func->drawable_texture_rendered_pixels_get(ntex, x, y, w, h,
pd_scene->surface, pixels);
}
else
return NULL;
return EINA_FALSE;
}
else
return NULL;
return EINA_FALSE;
return pixels;
if (stride) *stride = w * sizeof(DATA32);
slice->mem = pixels;
slice->len = len;
DBG("map(%p, %d,%d %dx%d plane:%d) -> " EINA_SLICE_FMT,
eo_obj, x, y, w, h, plane, EINA_SLICE_PRINT(*slice));
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_canvas_scene3d_efl_gfx_buffer_buffer_unmap(Eo *eo_obj EINA_UNUSED, void *_pd EINA_UNUSED,
void *data, int length EINA_UNUSED)
const Eina_Rw_Slice *slice)
{
free(data);
free(slice->mem);
return EINA_TRUE;
}

View File

@ -1369,7 +1369,7 @@ struct _Evas_Func
Eina_Bool (*image_can_region_get) (void *data, void *image);
/* image data map/unmap: direct or indirect access to pixels data */
const Eina_Rw_Slice *(*image_data_map) (void *data, void **image, int *stride, int x, int y, int w, int h, Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode);
Eina_Bool (*image_data_map) (void *data, void **image, Eina_Rw_Slice *slice, int *stride, int x, int y, int w, int h, Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode, int plane);
Eina_Bool (*image_data_unmap) (void *data, void *image, const Eina_Rw_Slice *slice);
int (*image_data_maps_get) (void *data, const void *image, const Eina_Rw_Slice **slices);

View File

@ -2794,17 +2794,18 @@ eng_ector_end(void *data, void *context EINA_UNUSED, Ector_Surface *ector,
}
}
static const Eina_Rw_Slice *
eng_image_data_map(void *engdata EINA_UNUSED, void **image,
static Eina_Bool
eng_image_data_map(void *engdata EINA_UNUSED, void **image, Eina_Rw_Slice *slice,
int *stride, int x, int y, int w, int h,
Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode)
Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode,
int plane)
{
Eina_Bool cow = EINA_FALSE, to_write = EINA_FALSE;
Evas_GL_Image_Data_Map *map = NULL;
const Eina_Rw_Slice *slice = NULL;
Evas_GL_Image *im;
Eina_Bool ok;
EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image && slice, EINA_FALSE);
im = *image;
if (mode & EFL_GFX_BUFFER_ACCESS_MODE_COW)
@ -2818,9 +2819,9 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
int strid = 0;
// Call sw generic implementation. Should work for simple cases.
slice = pfunc.image_data_map(NULL, (void **) &im->im, &strid,
x, y, w, h, cspace, mode);
if (slice)
ok = pfunc.image_data_map(NULL, (void **) &im->im, slice, &strid,
x, y, w, h, cspace, mode, plane);
if (ok)
{
map = calloc(1, sizeof(*map));
map->cspace = cspace;
@ -2835,12 +2836,12 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
im->maps = eina_inlist_prepend(im->maps, EINA_INLIST_GET(map));
}
if (stride) *stride = strid;
return &map->slice;
return ok;
}
// TODO: glReadPixels from FBO if possible
return NULL;
return EINA_FALSE;
}
static Eina_Bool
@ -2850,7 +2851,7 @@ eng_image_data_unmap(void *engdata EINA_UNUSED, void *image, const Eina_Rw_Slice
Evas_GL_Image *im = image;
Eina_Bool found = EINA_FALSE;
if (!im || !slice)
if (!(image && slice))
return EINA_FALSE;
EINA_INLIST_FOREACH(im->maps, map)

View File

@ -1453,10 +1453,11 @@ eng_image_data_put(void *data, void *image, DATA32 *image_data)
return im;
}
static const Eina_Rw_Slice *
eng_image_data_map(void *engdata EINA_UNUSED, void **image,
static Eina_Bool
eng_image_data_map(void *engdata EINA_UNUSED, void **image, Eina_Rw_Slice *slice,
int *stride, int x, int y, int w, int h,
Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode)
Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode,
int plane)
{
Eina_Bool cow = EINA_FALSE, to_write = EINA_FALSE;
RGBA_Image_Data_Map *map;
@ -1465,17 +1466,26 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
int src_stride, src_offset;
void *data;
EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image && slice, EINVAL);
im = *image;
ie = &im->cache_entry;
slice->len = 0;
slice->mem = NULL;
// FIXME: implement planes support (YUV, RGB565, ETC1+Alpha)
// FIXME: implement YUV support (im->cs.data)
if (plane)
{
ERR("planar formats support not implemented yet!");
return EINA_FALSE;
}
if (!im->image.data)
{
int error = evas_cache_image_load_data(ie);
if (error != EVAS_LOAD_ERROR_NONE)
return NULL;
return EINA_FALSE;
}
if (mode & EFL_GFX_BUFFER_ACCESS_MODE_COW)
@ -1490,7 +1500,7 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
{
ERR("invalid region for colorspace %d: %dx%d + %d,%d, image: %dx%d",
cspace, w, h, x, y, ie->w, ie->h);
return NULL;
return EINA_FALSE;
}
src_stride = _evas_common_rgba_image_data_offset(ie->w, 0, 0, 0, 0, im);
@ -1502,7 +1512,7 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
{
ERR("can't map shared image data multiple times with "
"different COW flag");
return NULL;
return EINA_FALSE;
}
}
@ -1510,7 +1520,7 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
if (cow)
{
ie = evas_cache_image_alone(ie);
if (!ie) return NULL;
if (!ie) return EINA_FALSE;
im = (RGBA_Image *) ie;
*image = im;
}
@ -1519,7 +1529,7 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
if (to_write && (ie->references > 1))
{
ERR("write map requires COW flag for shared images");
return NULL;
return EINA_FALSE;
}
}
@ -1535,11 +1545,11 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
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;
if (!cs_func) return EINA_FALSE;
// make sure we can convert back, if map for writing
if (to_write && !efl_draw_convert_func_get(cspace, ie->space, NULL))
return NULL;
return EINA_FALSE;
if (can_region)
{
@ -1568,20 +1578,20 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
dst_len = rh * dst_stride;
data = malloc(dst_len);
if (!data) return NULL;
if (!data) return EINA_FALSE;
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;
return EINA_FALSE;
}
map = calloc(1, sizeof(*map));
if (!map)
{
free(data);
return NULL;
return EINA_FALSE;
}
map->allocated = EINA_TRUE;
map->cspace = cspace;
@ -1603,7 +1613,7 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
// 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));
if (!map) return NULL;
if (!map) return EINA_FALSE;
map->baseptr = im->image.data8;
map->slice.mem = im->image.data8 + src_offset;
@ -1614,12 +1624,12 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
// copy
int size = _evas_common_rgba_image_data_offset(w, h, 0, 0, 0, im);
data = malloc(size);
if (!data) return NULL;
if (!data) return EINA_FALSE;
map = calloc(1, sizeof(*map));
if (!map)
{
free(data);
return NULL;
return EINA_FALSE;
}
memcpy(data, im->image.data8 + src_offset, size);
@ -1639,7 +1649,9 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
im->maps = (RGBA_Image_Data_Map *)
eina_inlist_prepend(EINA_INLIST_GET(im->maps), EINA_INLIST_GET(map));
if (stride) *stride = map->stride;
return &map->slice;
slice->mem = map->slice.mem;
slice->len = map->slice.len;
return EINA_TRUE;
}
static void
@ -1693,7 +1705,7 @@ eng_image_data_unmap(void *engdata EINA_UNUSED, void *image, const Eina_Rw_Slice
RGBA_Image_Data_Map *map;
RGBA_Image *im = image;
if (!im || !slice)
if (!(image && slice))
return EINA_FALSE;
EINA_INLIST_FOREACH(EINA_INLIST_GET(im->maps), map)

View File

@ -659,15 +659,13 @@ START_TEST(evas_object_image_map_unmap)
{
Evas *e = _setup_evas();
Evas_Object *o, *o2;
void *data;
int len, stride;
int w, h, rx, ry, rw, rh;
int stride, w, h, rx, ry, rw, rh;
Efl_Gfx_Colorspace cs;
Eina_Tmpstr *tmp;
int fd;
uint32_t *data32;
uint8_t *data8;
Eina_Bool all_white = 1, all_transparent = 1;
Eina_Rw_Slice slice;
const char *imgpath = TESTS_IMG_DIR "/Pic4.png";
@ -682,26 +680,23 @@ START_TEST(evas_object_image_map_unmap)
rh = (h / 2) & ~3;
// same cspace, full image
data = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w, h, cs, &stride);
fail_if(!data);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &slice, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w, h, cs, 0, &stride));
fail_if(!slice.len || !slice.mem);
fail_if(!stride);
efl_gfx_buffer_unmap(o, data, len);
efl_gfx_buffer_unmap(o, &slice);
// same cspace, partial image
data = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_READ, rx, ry, rw, rh, cs, &stride);
fail_if(!data);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &slice, EFL_GFX_BUFFER_ACCESS_MODE_READ, rx, ry, rw, rh, cs, 0, &stride));
fail_if(!slice.len || !slice.mem);
fail_if(!stride);
efl_gfx_buffer_unmap(o, data, len);
efl_gfx_buffer_unmap(o, &slice);
// argb cspace, full image
data = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w, h, EFL_GFX_COLORSPACE_ARGB8888, &stride);
fail_if(!data);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &slice, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w, h, EFL_GFX_COLORSPACE_ARGB8888, 0, &stride));
fail_if(!slice.len || !slice.mem);
fail_if(!stride);
data32 = data;
for (int k = 0; (k < len) && (all_white || all_transparent); k++)
data32 = slice.mem;
for (int k = 0; (k < slice.len) && (all_white || all_transparent); k++)
{
if (data32[k])
all_transparent = 0;
@ -709,49 +704,45 @@ START_TEST(evas_object_image_map_unmap)
all_white = 0;
}
fail_if(all_white || all_transparent);
efl_gfx_buffer_unmap(o, data, len);
efl_gfx_buffer_unmap(o, &slice);
// argb cspace, partial image
data = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_READ, rx, ry, rw, rh, EFL_GFX_COLORSPACE_ARGB8888, &stride);
fail_if(!data);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &slice, EFL_GFX_BUFFER_ACCESS_MODE_READ, rx, ry, rw, rh, EFL_GFX_COLORSPACE_ARGB8888, 0, &stride));
fail_if(!slice.len || !slice.mem);
fail_if(!stride);
efl_gfx_buffer_unmap(o, data, len);
efl_gfx_buffer_unmap(o, &slice);
// argb cspace, partial image, write
data = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_WRITE, rx, ry, rw, rh, EFL_GFX_COLORSPACE_ARGB8888, &stride);
fail_if(!data);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &slice, EFL_GFX_BUFFER_ACCESS_MODE_WRITE, rx, ry, rw, rh, EFL_GFX_COLORSPACE_ARGB8888, 0, &stride));
fail_if(!slice.len || !slice.mem);
fail_if(!stride);
data32 = data;
data32 = slice.mem;
for (int y = 0; y < rh; y += 2)
for (int x = 0; x < rw; x++)
{
data32[y*stride/4 + x] = 0xFF00FF00;
data32[(y+1)*stride/4 + x] = 0xFFFF0000;
}
efl_gfx_buffer_unmap(o, data, len);
efl_gfx_buffer_unmap(o, &slice);
// argb cspace, partial image, write
data = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_READ| EFL_GFX_BUFFER_ACCESS_MODE_WRITE,
rx, ry, rw, rh / 2, EFL_GFX_COLORSPACE_GRY8, &stride);
fail_if(!data);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &slice, EFL_GFX_BUFFER_ACCESS_MODE_READ| EFL_GFX_BUFFER_ACCESS_MODE_WRITE,
rx, ry, rw, rh / 2, EFL_GFX_COLORSPACE_GRY8, 0, &stride));
fail_if(!slice.len || !slice.mem);
fail_if(!stride);
data8 = data;
for (int y = 0; y < rh / 4; y++)
for (int x = 0; x < rw; x++)
data8[y*stride + x] = x & 0xFF;
efl_gfx_buffer_unmap(o, data, len);
slice.bytes[y*stride + x] = x & 0xFF;
efl_gfx_buffer_unmap(o, &slice);
// save file, verify its pixels
fd = eina_file_mkstemp("/tmp/evas-test.XXXXXX.png", &tmp);
close(fd);
if (efl_file_save(o, tmp, NULL, NULL))
{
int w2, h2, stride2, len2;
uint32_t *data2, *orig;
int x, y;
Eina_Rw_Slice sorig, sdest;
int w2, h2, stride2, x, y;
uint32_t *dest, *orig;
o2 = efl_add(EFL_CANVAS_IMAGE_CLASS, e);
efl_file_set(o2, tmp, NULL);
@ -763,20 +754,21 @@ START_TEST(evas_object_image_map_unmap)
fail_if(w2 != w);
fail_if(h2 != h);
orig = efl_gfx_buffer_map(o, &len, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w, h, EFL_GFX_COLORSPACE_ARGB8888, &stride);
fail_if(!orig);
fail_if(!len);
fail_if(!efl_gfx_buffer_map(o, &sorig, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w, h, EFL_GFX_COLORSPACE_ARGB8888, 0, &stride));
fail_if(!sorig.len || !sorig.mem);
fail_if(!stride);
data2 = efl_gfx_buffer_map(o2, &len2, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w2, h2, EFL_GFX_COLORSPACE_ARGB8888, &stride2);
fail_if(!data2);
fail_if(len2 != len);
fail_if(!efl_gfx_buffer_map(o2, &sdest, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0, 0, w2, h2, EFL_GFX_COLORSPACE_ARGB8888, 0, &stride2));
fail_if(sorig.len != sdest.len);
fail_if(stride2 != stride);
dest = sdest.mem;
orig = sorig.mem;
// first quarter: same image
for (y = 0; y < h / 4; y++)
for (x = 0; x < w; x++)
fail_if(orig[y*stride/4 + x] != data2[y*stride2/4+x], "pixels differ [1]");
fail_if(orig[y*stride/4 + x] != dest[y*stride2/4+x], "pixels differ [1]");
// middle zone top: grey gradient
for (y = ry; y < (ry + rh / 4); y++)
@ -784,28 +776,28 @@ START_TEST(evas_object_image_map_unmap)
{
uint32_t c = (x - rx) & 0xFF;
c = 0xFF000000 | (c << 16) | (c << 8) | c;
fail_if(data2[y*stride/4 + x] != c, "pixels differ [2]");
fail_if(dest[y*stride/4 + x] != c, "pixels differ [2]");
}
// middle zone: grey image
for (y = (ry + rh / 4 + 1); y < (ry + rh / 2); y++)
for (x = rx; x < rx + rw; x++)
{
uint32_t c = data2[y*stride/4 + x] & 0xFF;
uint32_t c = dest[y*stride/4 + x] & 0xFF;
c = 0xFF000000 | (c << 16) | (c << 8) | c;
fail_if(data2[y*stride/4 + x] != c, "pixels differ [2bis]");
fail_if(dest[y*stride/4 + x] != c, "pixels differ [2bis]");
}
// next lines: green & red
y = ry + rh / 2;
for (x = rx; x < rx + rw; x++)
{
fail_if(data2[y*stride/4 + x] != 0xFF00FF00, "pixels differ [3]");
fail_if(data2[(y+1)*stride/4 + x] != 0xFFFF0000, "pixels differ [4]");
fail_if(dest[y*stride/4 + x] != 0xFF00FF00, "pixels differ [3]");
fail_if(dest[(y+1)*stride/4 + x] != 0xFFFF0000, "pixels differ [4]");
}
efl_gfx_buffer_unmap(o, orig, len);
efl_gfx_buffer_unmap(o2, data2, len2);
efl_gfx_buffer_unmap(o, &sorig);
efl_gfx_buffer_unmap(o2, &sdest);
}
else unlink(tmp);
eina_tmpstr_del(tmp);