From 8ee431572da636f0199f25b525c39094b7760cdf Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Thu, 1 Sep 2016 21:46:42 +0900 Subject: [PATCH] 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. --- src/examples/evas/evas-3d-proxy.c | 19 +-- src/lib/efl/interfaces/efl_gfx_buffer.eo | 97 ++++++++------- src/lib/evas/canvas/efl_canvas_image.c | 117 +++++++++++++----- src/lib/evas/canvas/efl_canvas_image.eo | 4 +- src/lib/evas/canvas/efl_canvas_proxy.c | 48 ++++--- src/lib/evas/canvas/efl_canvas_scene3d.c | 44 ++++--- src/lib/evas/include/evas_private.h | 2 +- .../evas/engines/gl_generic/evas_engine.c | 23 ++-- .../engines/software_generic/evas_engine.c | 50 +++++--- src/tests/evas/evas_test_image.c | 94 +++++++------- 10 files changed, 296 insertions(+), 202 deletions(-) diff --git a/src/examples/evas/evas-3d-proxy.c b/src/examples/evas/evas-3d-proxy.c index 9edbfb2337..c7babf57ea 100644 --- a/src/examples/evas/evas-3d-proxy.c +++ b/src/examples/evas/evas-3d-proxy.c @@ -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); diff --git a/src/lib/efl/interfaces/efl_gfx_buffer.eo b/src/lib/efl/interfaces/efl_gfx_buffer.eo index 7716424901..daa829b42d 100644 --- a/src/lib/efl/interfaces/efl_gfx_buffer.eo +++ b/src/lib/efl/interfaces/efl_gfx_buffer.eo @@ -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 */ } diff --git a/src/lib/evas/canvas/efl_canvas_image.c b/src/lib/evas/canvas/efl_canvas_image.c index 73bffcec61..daa2bcf29e 100644 --- a/src/lib/evas/canvas/efl_canvas_image.c +++ b/src/lib/evas/canvas/efl_canvas_image.c @@ -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; diff --git a/src/lib/evas/canvas/efl_canvas_image.eo b/src/lib/evas/canvas/efl_canvas_image.eo index cb34c03032..2a7b807043 100644 --- a/src/lib/evas/canvas/efl_canvas_image.eo +++ b/src/lib/evas/canvas/efl_canvas_image.eo @@ -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; diff --git a/src/lib/evas/canvas/efl_canvas_proxy.c b/src/lib/evas/canvas/efl_canvas_proxy.c index f0562e2d26..aa5cfe538e 100644 --- a/src/lib/evas/canvas/efl_canvas_proxy.c +++ b/src/lib/evas/canvas/efl_canvas_proxy.c @@ -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; diff --git a/src/lib/evas/canvas/efl_canvas_scene3d.c b/src/lib/evas/canvas/efl_canvas_scene3d.c index ef4e491c7f..8c9ebae729 100644 --- a/src/lib/evas/canvas/efl_canvas_scene3d.c +++ b/src/lib/evas/canvas/efl_canvas_scene3d.c @@ -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; } diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 7e4c2e4acd..ac1a901cd8 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -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); diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index e48dd259c7..de987572d3 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -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) diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 17f9968e5b..1544c5b4e0 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -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) diff --git a/src/tests/evas/evas_test_image.c b/src/tests/evas/evas_test_image.c index 3d2f240680..8743e05b85 100644 --- a/src/tests/evas/evas_test_image.c +++ b/src/tests/evas/evas_test_image.c @@ -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);