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).
This commit is contained in:
Jean-Philippe Andre 2016-03-21 20:15:20 +09:00
parent f78cbac9e6
commit 08c1160888
5 changed files with 223 additions and 70 deletions

View File

@ -157,10 +157,9 @@ interface Efl.Gfx.Buffer ()
@in length: uint; [[Must be the same as returned by map.]] @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: naming: buffer_set, buffer_attach, external_data_set, ...? */
/* FIXME: do we need writable flag? */ buffer_data_set {
buffer_set {
[[Set the pixels for this buffer, or allocate a new memory region. [[Set the pixels for this buffer, or allocate a new memory region.
EFL will use $pixels directly, and update the GPU-side texture 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 If the buffer already had pixel data, the previous image data will
be dropped. This is the same as @.buffer_copy_set. 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 The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace. $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 See also @.buffer_copy_set if you want EFL to copy the input buffer
internally. internally.
@ -202,18 +194,12 @@ interface Efl.Gfx.Buffer ()
If $pixels is $null, then a new empty buffer will be allocated. If $pixels is $null, then a new empty buffer will be allocated.
If the buffer already had pixel data, the previous image data will 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 The memory buffer $pixels must be large enough to hold
$width x $height pixels encoded in the colorspace $cspace. $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. $pixels should not be the return value of @.buffer_data_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.
]] ]]
params { params {
@in pixels: const(void)* @nullable; [[If $null, allocates an empty buffer]] @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.]] return: bool @warn_unused; [[This function returns $false in case of failure.]]
} }
buffer_get { buffer_data_get {
[[Get a direct pointer to the internal pixel data. [[Get a direct pointer to the internal pixel data, if available.
This will increment an internal reference counter on the internal This will return $null unless @.buffer_data_set was used to pass in an
buffer. If $to_write is $true, this may trigger a copy of the external data pointer.
internal pixel data, and return a writable memory block.
Call @.buffer_size.get to know the value of $width and $height. Note: This is different from the legacy API data, which is now
The memory buffer length in bytes is defined as $height x $stride. replaced by map/unmap.
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.
]] ]]
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; return: void* @warn_unused;
} }
/* Note: border, span and buffer flags not imported from ector buffer */ /* Note: border, span and buffer flags not imported from ector buffer */

View File

@ -19,6 +19,7 @@ _evas_image_mmap_set(Eo *eo_obj, const Eina_File *f, const char *key)
evas_object_async_block(obj); evas_object_async_block(obj);
_evas_image_init_set(f, NULL, key, eo_obj, obj, o, &lo); _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->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); _evas_image_done_set(eo_obj, obj, o);
return EINA_TRUE; 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_object_async_block(obj);
_evas_image_init_set(NULL, file, key, eo_obj, obj, o, &lo); _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->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); _evas_image_done_set(eo_obj, obj, o);
return EINA_TRUE; 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); 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 EOLIAN static Eina_Bool
@ -400,17 +402,15 @@ _efl_canvas_image_efl_image_animated_animated_get(Eo *eo_obj, void *_pd EINA_UNU
int int
_evas_image_animated_frame_count_get(const Eo *eo_obj) _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_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); obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
if (ENFN->image_animated_frame_count_get) return ENFN->image_animated_frame_count_get(ENDT, o->engine_data);
frame_count = ENFN->image_animated_frame_count_get(ENDT, o->engine_data);
return frame_count;
} }
EOLIAN static int EOLIAN static int
@ -423,15 +423,13 @@ Efl_Image_Animated_Loop_Hint
_evas_image_animated_loop_type_get(const Eo *eo_obj) _evas_image_animated_loop_type_get(const Eo *eo_obj)
{ {
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS); 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); 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) return (Efl_Image_Animated_Loop_Hint) ENFN->image_animated_loop_type_get(ENDT, o->engine_data);
hint = (Efl_Image_Animated_Loop_Hint) ENFN->image_animated_loop_type_get(ENDT, o->engine_data);
return hint;
} }
EOLIAN static Efl_Image_Animated_Loop_Hint 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_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_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
int loop_count; if (!ENFN->image_animated_loop_count_get ||
loop_count = -1; !evas_object_image_animated_get(eo_obj))
if (!evas_object_image_animated_get(eo_obj)) return loop_count; return -1;
loop_count = return ENFN->image_animated_loop_count_get(ENDT, o->engine_data);
ENFN->image_animated_loop_count_get ?
ENFN->image_animated_loop_count_get(ENDT, o->engine_data) :
-1;
return loop_count;
} }
EOLIAN static int 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_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_Image_Data *o = eo_data_scope_get(eo_obj, EVAS_IMAGE_CLASS);
double frame_duration = -1;
int frame_count = 0; 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); 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; return ENFN->image_animated_frame_duration_get(ENDT, o->engine_data, start_frame, frame_num);
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;
} }
EOLIAN static double 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); 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 static void
_image_preload_internal(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool cancel) _image_preload_internal(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool cancel)
{ {

View File

@ -8,6 +8,10 @@ class Efl.Canvas.Image (Evas.Image, Efl.Image_Load, Efl.Image_Animated)
]] ]]
data: null; data: null;
implements { 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.set;
Efl.File.file.get; Efl.File.file.get;
Efl.File.mmap.set; Efl.File.mmap.set;

View File

@ -157,7 +157,7 @@ EAPI int
evas_object_image_stride_get(const Evas_Object *obj) evas_object_image_stride_get(const Evas_Object *obj)
{ {
EVAS_IMAGE_API(obj, 0); 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; return o->cur->image.stride;
} }

View File

@ -128,6 +128,7 @@ struct _Evas_Image_Data
Eina_Bool written : 1; Eina_Bool written : 1;
Eina_Bool direct_render : 1; Eina_Bool direct_render : 1;
Eina_Bool has_filter : 1; Eina_Bool has_filter : 1;
Eina_Bool buffer_data_set : 1;
struct struct
{ {
Eina_Bool video_move : 1; Eina_Bool video_move : 1;