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 || + !evas_object_image_animated_get(eo_obj)) + return EFL_IMAGE_ANIMATED_LOOP_HINT_NONE; - if (ENFN->image_animated_loop_type_get) - hint = (Efl_Image_Animated_Loop_Hint) ENFN->image_animated_loop_type_get(ENDT, o->engine_data); - - 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;