summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2016-03-21 20:15:20 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2016-03-28 16:40:01 +0900
commit08c11608880038e36ebf94fa6db5a24049146de6 (patch)
treeccaf527ea034e81ae02d490052ccb9627ce5a28f
parentf78cbac9e60406a0b2e63ed488575613074d7b90 (diff)
downloadefl-08c11608880038e36ebf94fa6db5a24049146de6.tar.gz
Efl.Canvas.Image: Implement raw data_set/copy/get
No more refcount. This is only to initialize the data from an external buffer. data_get will only work if data_set was used (not even copy_set).
-rw-r--r--src/lib/efl/interfaces/efl_gfx_buffer.eo50
-rw-r--r--src/lib/evas/canvas/efl_canvas_image.c236
-rw-r--r--src/lib/evas/canvas/efl_canvas_image.eo4
-rw-r--r--src/lib/evas/canvas/evas_image_legacy.c2
-rw-r--r--src/lib/evas/canvas/evas_image_private.h1
5 files changed, 223 insertions, 70 deletions
diff --git a/src/lib/efl/interfaces/efl_gfx_buffer.eo b/src/lib/efl/interfaces/efl_gfx_buffer.eo
index 87de79b05d..75853933cb 100644
--- a/src/lib/efl/interfaces/efl_gfx_buffer.eo
+++ b/src/lib/efl/interfaces/efl_gfx_buffer.eo
@@ -157,10 +157,9 @@ interface Efl.Gfx.Buffer ()
@in length: uint; [[Must be the same as returned by map.]]
}
}
- /* note: not a property because the refcount needs to be explicit
- * between set and get */
- /* FIXME: do we need writable flag? */
- buffer_set {
+
+ /* 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
@@ -170,15 +169,8 @@ interface Efl.Gfx.Buffer ()
If the buffer already had pixel data, the previous image data will
be dropped. This is the same as @.buffer_copy_set.
- If $pixels is the return value of @.buffer_get then EFL will
- decrement its internal reference count on the buffer data. Call
- @.buffer_update_add to flush updates and indicate changes in
- the pixel data.
-
The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace.
- Alternatively $pixels must be larger than $height x $stride
- in bytes.
See also @.buffer_copy_set if you want EFL to copy the input buffer
internally.
@@ -202,18 +194,12 @@ 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_set.
+ be dropped. This is the same as @.buffer_data_set.
The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace.
- Alternatively $pixels must be larger than $height x $stride
- in bytes.
-
- $pixels should not be the return value of @.buffer_get.
- There is no copy equivalent to this function, as you can easily
- call @.buffer_get and allocate the proper buffer on your side,
- followed by a memory copy and @.buffer_set.
+ $pixels should not be the return value of @.buffer_data_get.
]]
params {
@in pixels: const(void)* @nullable; [[If $null, allocates an empty buffer]]
@@ -224,29 +210,15 @@ interface Efl.Gfx.Buffer ()
}
return: bool @warn_unused; [[This function returns $false in case of failure.]]
}
- buffer_get {
- [[Get a direct pointer to the internal pixel data.
+ buffer_data_get {
+ [[Get a direct pointer to the internal pixel data, if available.
- This will increment an internal reference counter on the internal
- buffer. If $to_write is $true, this may trigger a copy of the
- internal pixel data, and return a writable memory block.
+ This will return $null unless @.buffer_data_set was used to pass in an
+ external data pointer.
- Call @.buffer_size.get to know the value of $width and $height.
- The memory buffer length in bytes is defined as $height x $stride.
-
- Warning: @.buffer_set MUST be called as soon as possible after
- calling @.buffer_get. @.buffer_update_add should be called after
- @.buffer_set if $to_write was $true and the pixel data has been
- modified. Once @.buffer_set is called, the pointer returned by
- @.buffer_get is not valid anymore.
+ Note: This is different from the legacy API data, which is now
+ replaced by map/unmap.
]]
- params {
- @in to_write: bool; [[If $true, requests write access]]
- @out width: int @optional;
- @out height: int @optional;
- @out stride: int @optional; [[Returns the length of one row of pixels in bytes, so that length = $height x $stride.]]
- @out cspace: Efl.Gfx.Colorspace @optional; [[Pixel encoding of the returned buffer.]]
- }
return: void* @warn_unused;
}
/* 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 03ad9cf5f8..6d088feafa 100644
--- a/src/lib/evas/canvas/efl_canvas_image.c
+++ b/src/lib/evas/canvas/efl_canvas_image.c
@@ -19,6 +19,7 @@ _evas_image_mmap_set(Eo *eo_obj, const Eina_File *f, const char *key)
evas_object_async_block(obj);
_evas_image_init_set(f, NULL, key, eo_obj, obj, o, &lo);
o->engine_data = ENFN->image_mmap(ENDT, o->cur->u.f, o->cur->key, &o->load_error, &lo);
+ o->buffer_data_set = EINA_FALSE;
_evas_image_done_set(eo_obj, obj, o);
return EINA_TRUE;
@@ -67,6 +68,7 @@ _evas_image_file_set(Eo *eo_obj, const char *file, const char *key)
evas_object_async_block(obj);
_evas_image_init_set(NULL, file, key, eo_obj, obj, o, &lo);
o->engine_data = ENFN->image_load(ENDT, o->cur->u.file, o->cur->key, &o->load_error, &lo);
+ o->buffer_data_set = EINA_FALSE;
_evas_image_done_set(eo_obj, obj, o);
return EINA_TRUE;
@@ -354,7 +356,7 @@ _evas_image_load_orientation_get(const Eo *eo_obj)
{
Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
- return o->load_opts->orientation;;
+ return o->load_opts->orientation;
}
EOLIAN static Eina_Bool
@@ -400,17 +402,15 @@ _efl_canvas_image_efl_image_animated_animated_get(Eo *eo_obj, void *_pd EINA_UNU
int
_evas_image_animated_frame_count_get(const Eo *eo_obj)
{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
- Evas_Object_Protected_Data *obj;
- int frame_count = -1;
- if (!evas_object_image_animated_get(eo_obj)) return frame_count;
+ if (!ENFN->image_animated_frame_count_get ||
+ !evas_object_image_animated_get(eo_obj))
+ return -1;
obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- if (ENFN->image_animated_frame_count_get)
- frame_count = ENFN->image_animated_frame_count_get(ENDT, o->engine_data);
-
- return frame_count;
+ return ENFN->image_animated_frame_count_get(ENDT, o->engine_data);
}
EOLIAN static int
@@ -423,15 +423,13 @@ Efl_Image_Animated_Loop_Hint
_evas_image_animated_loop_type_get(const Eo *eo_obj)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
- Efl_Image_Animated_Loop_Hint hint = EFL_IMAGE_ANIMATED_LOOP_HINT_NONE;
Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
- if (!evas_object_image_animated_get(eo_obj)) return hint;
-
- if (ENFN->image_animated_loop_type_get)
- hint = (Efl_Image_Animated_Loop_Hint) ENFN->image_animated_loop_type_get(ENDT, o->engine_data);
+ if (!ENFN->image_animated_loop_type_get ||
+ !evas_object_image_animated_get(eo_obj))
+ return EFL_IMAGE_ANIMATED_LOOP_HINT_NONE;
- return hint;
+ return (Efl_Image_Animated_Loop_Hint) ENFN->image_animated_loop_type_get(ENDT, o->engine_data);
}
EOLIAN static Efl_Image_Animated_Loop_Hint
@@ -446,16 +444,11 @@ _evas_image_animated_loop_count_get(const Eo *eo_obj)
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
- int loop_count;
- loop_count = -1;
- if (!evas_object_image_animated_get(eo_obj)) return loop_count;
+ if (!ENFN->image_animated_loop_count_get ||
+ !evas_object_image_animated_get(eo_obj))
+ return -1;
- loop_count =
- ENFN->image_animated_loop_count_get ?
- ENFN->image_animated_loop_count_get(ENDT, o->engine_data) :
- -1;
-
- return loop_count;
+ return ENFN->image_animated_loop_count_get(ENDT, o->engine_data);
}
EOLIAN static int
@@ -469,18 +462,17 @@ _evas_image_animated_frame_duration_get(const Eo *eo_obj, int start_frame, int f
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
- double frame_duration = -1;
int frame_count = 0;
- if (!ENFN->image_animated_frame_count_get) return frame_duration;
+ if (!ENFN->image_animated_frame_count_get ||
+ !ENFN->image_animated_frame_duration_get)
+ return -1.0;
frame_count = ENFN->image_animated_frame_count_get(ENDT, o->engine_data);
+ if ((start_frame + frame_num) > frame_count)
+ return -1.0;
- if ((start_frame + frame_num) > frame_count) return frame_duration;
- if (ENFN->image_animated_frame_duration_get)
- frame_duration = ENFN->image_animated_frame_duration_get(ENDT, o->engine_data, start_frame, frame_num);
-
- return frame_duration;
+ return ENFN->image_animated_frame_duration_get(ENDT, o->engine_data, start_frame, frame_num);
}
EOLIAN static double
@@ -547,6 +539,190 @@ _efl_canvas_image_efl_image_animated_animated_frame_get(Eo *eo_obj, void *_pd EI
return _evas_image_animated_frame_get(eo_obj);
}
+EOLIAN static void
+_efl_canvas_image_efl_gfx_buffer_buffer_size_get(Eo *eo_obj, void *_pd EINA_UNUSED, int *w, int *h)
+{
+ Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
+
+ if (w) *w = o->cur->image.w;
+ if (h) *h = o->cur->image.h;
+}
+
+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)
+{
+ Eina_Bool resized = EINA_FALSE, ret = EINA_FALSE, easy_copy = EINA_FALSE;
+ int int_stride = 0;
+
+ // FIXME: buffer border support is not implemented
+
+ if (o->pixels_checked_out)
+ {
+ // is there anything to do?
+ ERR("Calling buffer_data_set after evas_object_image_data_get is not "
+ "valid. Discarding previous data pointer.");
+ o->pixels_checked_out = 0;
+ }
+
+ if (o->engine_data)
+ {
+ ENFN->image_free(ENDT, o->engine_data);
+ o->engine_data = NULL;
+ }
+
+ switch (cspace)
+ {
+ case EVAS_COLORSPACE_ARGB8888:
+ case EVAS_COLORSPACE_AGRY88:
+ case EVAS_COLORSPACE_GRY8:
+ easy_copy = EINA_TRUE;
+ break;
+ default:
+ break;
+ }
+
+ int_stride = _evas_common_rgba_image_surface_size(w, 1, cspace, NULL, NULL, NULL, NULL);
+ if (!stride) stride = int_stride;
+
+ if (!copy && (int_stride != stride))
+ {
+ // FIXME: Add proper support for stride inside the engines
+ ERR("Unable to create an image with stride %d, got %d", stride, int_stride);
+ return EINA_FALSE;
+ }
+
+ if ((o->cur->image.w != w) || (o->cur->image.h != h))
+ resized = EINA_TRUE;
+
+ o->buffer_data_set = EINA_FALSE;
+ if (pixels && !copy)
+ {
+ // direct use
+ o->engine_data = ENFN->image_new_from_data(ENDT, w, h, pixels, o->cur->has_alpha, cspace);
+ o->buffer_data_set = (o->engine_data != NULL);
+ }
+ else if (stride == int_stride)
+ {
+ // simple copy
+ o->engine_data = ENFN->image_new_from_copied_data(ENDT, w, h, pixels, o->cur->has_alpha, cspace);
+ }
+ else if (easy_copy)
+ {
+ // copy each line. ouch.
+ o->engine_data = ENFN->image_new_from_copied_data(ENDT, w, h, NULL, o->cur->has_alpha, cspace);
+ if (o->engine_data)
+ {
+ uint8_t *data = NULL, *pixels_iter = pixels;
+ void *engine_data;
+ int y;
+
+ engine_data = ENFN->image_data_get(ENDT, o->engine_data, 0, (DATA32 **) &data, &o->load_error, NULL);
+ if (!engine_data || !data)
+ {
+ ERR("Failed to copy image!");
+ goto end;
+ }
+ o->engine_data = engine_data;
+ for (y = 0; y < h; y++)
+ {
+ memcpy(data + (y * int_stride), pixels_iter, int_stride);
+ pixels_iter += stride;
+ }
+ o->engine_data = ENFN->image_data_put(ENDT, o->engine_data, (DATA32 *) data);
+ }
+ }
+ else
+ {
+ // quite unlikely: non-standard cspace + stride
+ ERR("Can not copy colorspace %d with stride %d", cspace, stride);
+ goto end;
+ }
+
+ if (!o->engine_data)
+ {
+ ERR("Failed to create internal image (%dx%d, cspace: %d, pixels: %p)",
+ w, h, cspace, pixels);
+ goto end;
+ }
+
+
+ if (ENFN->image_scale_hint_set)
+ ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
+
+ if (ENFN->image_content_hint_set)
+ ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
+
+ if (ENFN->image_stride_get)
+ ENFN->image_stride_get(ENDT, o->engine_data, &int_stride);
+
+ if (resized || o->cur->u.file || o->cur->key ||
+ (o->cur->image.stride != int_stride) || (cspace != o->cur->cspace))
+ {
+ EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, cur)
+ {
+ cur->u.f = NULL;
+ cur->key = NULL;
+ cur->cspace = cspace;
+ cur->image.w = w;
+ cur->image.h = h;
+ cur->image.stride = int_stride;
+ }
+ EINA_COW_IMAGE_STATE_WRITE_END(o, cur)
+ }
+
+ ret = EINA_TRUE;
+
+end:
+ o->written = EINA_TRUE;
+ if (resized)
+ evas_object_inform_call_image_resize(obj->object);
+
+ return ret;
+}
+
+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)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
+
+ return _image_pixels_set(obj, o, pixels, w, h, stride, cspace, 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)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
+
+ return _image_pixels_set(obj, o, (void *) pixels, w, h, stride, cspace, EINA_TRUE);
+}
+
+EOLIAN static void *
+_efl_canvas_image_efl_gfx_buffer_buffer_data_get(Eo *eo_obj, void *_pd EINA_UNUSED)
+{
+ Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+ Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
+ DATA32 *data = NULL;
+
+ if (!o->buffer_data_set || !o->engine_data || !ENFN->image_data_has)
+ return NULL;
+
+ if (ENFN->image_data_has(ENDT, o->engine_data, NULL))
+ {
+ // FIXME: this is horrible code - need to store ptr somewhere safe
+ o->engine_data = ENFN->image_data_get(ENDT, o->engine_data, 0, &data, &o->load_error, NULL);
+ }
+
+ return data;
+}
+
static void
_image_preload_internal(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool cancel)
{
diff --git a/src/lib/evas/canvas/efl_canvas_image.eo b/src/lib/evas/canvas/efl_canvas_image.eo
index 19ab991ac8..95c19e22d2 100644
--- a/src/lib/evas/canvas/efl_canvas_image.eo
+++ b/src/lib/evas/canvas/efl_canvas_image.eo
@@ -8,6 +8,10 @@ class Efl.Canvas.Image (Evas.Image, Efl.Image_Load, Efl.Image_Animated)
]]
data: null;
implements {
+ Efl.Gfx.Buffer.buffer_data_get;
+ Efl.Gfx.Buffer.buffer_data_set;
+ Efl.Gfx.Buffer.buffer_copy_set;
+ Efl.Gfx.Buffer.buffer_size.get;
Efl.File.file.set;
Efl.File.file.get;
Efl.File.mmap.set;
diff --git a/src/lib/evas/canvas/evas_image_legacy.c b/src/lib/evas/canvas/evas_image_legacy.c
index 80d9a0fc24..1850057712 100644
--- a/src/lib/evas/canvas/evas_image_legacy.c
+++ b/src/lib/evas/canvas/evas_image_legacy.c
@@ -157,7 +157,7 @@ EAPI int
evas_object_image_stride_get(const Evas_Object *obj)
{
EVAS_IMAGE_API(obj, 0);
- Evas_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
+ Evas_Image_Data *o = eo_data_scope_get(obj, EVAS_IMAGE_CLASS);
return o->cur->image.stride;
}
diff --git a/src/lib/evas/canvas/evas_image_private.h b/src/lib/evas/canvas/evas_image_private.h
index 6d25dfa3b4..0fee7266c5 100644
--- a/src/lib/evas/canvas/evas_image_private.h
+++ b/src/lib/evas/canvas/evas_image_private.h
@@ -128,6 +128,7 @@ struct _Evas_Image_Data
Eina_Bool written : 1;
Eina_Bool direct_render : 1;
Eina_Bool has_filter : 1;
+ Eina_Bool buffer_data_set : 1;
struct
{
Eina_Bool video_move : 1;