Evas: Implement image_data_get for FBO images

This commit is contained in:
Jean-Philippe Andre 2015-07-02 11:52:16 +09:00
parent d927c1623a
commit fd4e133cc1
4 changed files with 136 additions and 96 deletions

View File

@ -1216,6 +1216,8 @@ _evas_image_data_convert(Eo *eo_obj, Evas_Image_Data *o, Evas_Colorspace to_cspa
DATA32 *data;
void* result = NULL;
// FIXME: This function is not really useful, and can't work with GL.
evas_object_async_block(obj);
if ((o->preloading) && (o->engine_data))
{
@ -1227,7 +1229,7 @@ _evas_image_data_convert(Eo *eo_obj, Evas_Image_Data *o, Evas_Colorspace to_cspa
o->pixels->video.update_pixels(o->pixels->video.data, eo_obj, &o->pixels->video);
if (o->cur->cspace == to_cspace) return NULL;
data = NULL;
o->engine_data = ENFN->image_data_get(ENDT, o->engine_data, 0, &data, &o->load_error);
o->engine_data = ENFN->image_data_get(ENDT, o->engine_data, 0, &data, &o->load_error, NULL);
result = evas_object_image_data_convert_internal(o, data, to_cspace);
if (o->engine_data)
{
@ -1324,6 +1326,8 @@ EOLIAN static void*
_evas_image_data_get(const Eo *eo_obj, Evas_Image_Data *_pd EINA_UNUSED, Eina_Bool for_writing)
{
Evas_Image_Data *o = (Evas_Image_Data *) _pd;
int stride = 0;
void *pixels;
DATA32 *data;
if (!o->engine_data) return NULL;
@ -1338,27 +1342,24 @@ _evas_image_data_get(const Eo *eo_obj, Evas_Image_Data *_pd EINA_UNUSED, Eina_Bo
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);
o->engine_data = ENFN->image_data_get(ENDT, o->engine_data, for_writing, &data, &o->load_error);
pixels = ENFN->image_data_get(ENDT, o->engine_data, for_writing, &data, &o->load_error, NULL);
/* if we fail to get engine_data, we have to return NULL */
if (!o->engine_data) return NULL;
if (!pixels) return NULL;
if (o->engine_data)
o->engine_data = pixels;
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENDT, o->engine_data, &stride);
else
stride = o->cur->image.w * 4;
if (o->cur->image.stride != stride)
{
int stride = 0;
if (ENFN->image_stride_get)
ENFN->image_stride_get(ENDT, o->engine_data, &stride);
else
stride = o->cur->image.w * 4;
if (o->cur->image.stride != stride)
{
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->image.stride = stride;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
state_write->image.stride = stride;
EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
}
o->pixels_checked_out++;
if (for_writing)
{
@ -1628,8 +1629,8 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file
DATA32 *data = NULL;
int quality = 80, compress = 9, ok = 0;
char *encoding = NULL;
RGBA_Image *im;
Eina_Bool putback = EINA_FALSE;
Image_Entry *ie;
Eina_Bool putback = EINA_FALSE, tofree = EINA_FALSE;
int imagew, imageh;
void *pixels;
@ -1679,7 +1680,7 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file
o->proxyrendering = EINA_FALSE;
}
pixels = ENFN->image_data_get(ENDT, pixels, 0, &data, &o->load_error);
pixels = ENFN->image_data_get(ENDT, pixels, 0, &data, &o->load_error, &tofree);
if (!pixels)
{
@ -1706,11 +1707,12 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file
else break;
}
}
im = (RGBA_Image*) evas_cache_image_data(evas_common_image_cache_get(),
imagew, imageh, data, o->cur->has_alpha,
EVAS_COLORSPACE_ARGB8888);
if (im)
ie = evas_cache_image_data(evas_common_image_cache_get(),
imagew, imageh, data, o->cur->has_alpha,
EVAS_COLORSPACE_ARGB8888);
if (ie)
{
RGBA_Image *im = (RGBA_Image *) ie;
if (o->cur->cspace == EVAS_COLORSPACE_ARGB8888)
im->image.data = data;
else
@ -1722,10 +1724,12 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file
if (o->cur->cspace != EVAS_COLORSPACE_ARGB8888)
free(im->image.data);
}
evas_cache_image_drop(&im->cache_entry);
evas_cache_image_drop(ie);
}
if (putback)
if (tofree)
ENFN->image_free(ENDT, pixels);
else if (putback)
o->engine_data = ENFN->image_data_put(ENDT, pixels, data);
free(encoding);
@ -1737,6 +1741,8 @@ _evas_image_pixels_import(Eo *eo_obj, Evas_Image_Data *o, Evas_Pixel_Import_Sour
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
// FIXME: This function is not really useful, and can't work with GL.
evas_object_async_block(obj);
_evas_object_image_cleanup(eo_obj, obj, o);
if ((pixels->w != o->cur->image.w) || (pixels->h != o->cur->image.h)) return EINA_FALSE;
@ -1776,7 +1782,7 @@ _evas_image_pixels_import(Eo *eo_obj, Evas_Image_Data *o, Evas_Pixel_Import_Sour
{
DATA32 *image_pixels = NULL;
o->engine_data = ENFN->image_data_get(ENDT, o->engine_data, 1, &image_pixels,&o->load_error);
o->engine_data = ENFN->image_data_get(ENDT, o->engine_data, 1, &image_pixels,&o->load_error, NULL);
if (image_pixels)
evas_common_convert_yuv_422p_601_rgba((DATA8 **) pixels->rows, (DATA8 *) image_pixels, o->cur->image.w, o->cur->image.h);
if (o->engine_data)

View File

@ -1301,7 +1301,7 @@ struct _Evas_Func
void *(*image_size_set) (void *data, void *image, int w, int h);
void (*image_stride_get) (void *data, void *image, int *stride);
void *(*image_dirty_region) (void *data, void *image, int x, int y, int w, int h);
void *(*image_data_get) (void *data, void *image, int to_write, DATA32 **image_data, int *err);
void *(*image_data_get) (void *data, void *image, int to_write, DATA32 **image_data, int *err, Eina_Bool *tofree);
void *(*image_data_put) (void *data, void *image, DATA32 *image_data);
void (*image_data_preload_request) (void *data, void *image, const Eo *target);
void (*image_data_preload_cancel) (void *data, void *image, const Eo *target);

View File

@ -53,8 +53,11 @@ static int _evas_engine_GL_log_dom = -1;
# endif
#endif
static int eng_gl_image_direct_get(void *data EINA_UNUSED, void *image);
static int eng_gl_image_direct_get(void *data, void *image);
static int eng_gl_surface_destroy(void *data, void *surface);
static Eina_Bool eng_gl_surface_lock(void *data, void *surface);
static Eina_Bool eng_gl_surface_unlock(void *data, void *surface);
static Eina_Bool eng_gl_surface_read_pixels(void *data, void *surface, int x, int y, int w, int h, Evas_Colorspace cspace, void *pixels);
static void
eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h, Eina_Bool do_async EINA_UNUSED)
@ -573,23 +576,20 @@ eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h)
}
static Evas_GL_Image *
_rotate_image_data(void *data, void *img)
_rotate_image_data(Render_Engine_GL_Generic *re, Evas_GL_Image *im1)
{
int alpha;
Evas_GL_Image *im1, *im2;
Evas_GL_Image *im2;
Evas_Engine_GL_Context *gl_context;
Render_Engine_GL_Generic *re = data;
RGBA_Draw_Context *dc;
DATA32 *pixels;
int w, h;
re->window_use(re->software.ob);
gl_context = re->window_gl_context_get(re->software.ob);
im1 = img;
w = im1->w;
h = im1->h;
alpha = eng_image_alpha_get(data, img);
alpha = eng_image_alpha_get(re, im1);
if (im1->orient == EVAS_IMAGE_ORIENT_90 ||
im1->orient == EVAS_IMAGE_ORIENT_270 ||
@ -614,71 +614,51 @@ _rotate_image_data(void *data, void *img)
0, 0, w, h,
0, 0, im2->w, im2->h,
0);
// Do not forget to flush everything or you will have nothing in your buffer
evas_gl_common_context_flush(gl_context);
gl_context->dc = NULL;
evas_common_draw_context_free(dc);
glsym_glBindFramebuffer(GL_FRAMEBUFFER, im2->tex->pt->fb);
// flush everything
eng_gl_surface_lock(re, im2);
// Rely on Evas_GL_Image infrastructure to allocate pixels
im2->im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get());
if (!im2->im) return NULL;
im2->im->cache_entry.flags.alpha = !!alpha;
evas_gl_common_image_alloc_ensure(im2);
pixels = im2->im->image.data;
if (im2->tex->pt->format == GL_BGRA)
{
glReadPixels(0, 0, im2->w, im2->h, GL_BGRA,
GL_UNSIGNED_BYTE, pixels);
}
else
{
DATA32 *ptr = pixels;
unsigned int k;
glReadPixels(0, 0, im2->w, im2->h, GL_RGBA,
GL_UNSIGNED_BYTE, pixels);
for (k = im2->w * im2->h; k; --k)
{
const DATA32 v = *ptr;
*ptr++ = (v & 0xFF00FF00)
| ((v & 0x00FF0000) >> 16)
| ((v & 0x000000FF) << 16);
}
}
glsym_glBindFramebuffer(GL_FRAMEBUFFER, 0);
eng_gl_surface_read_pixels(re, im2, 0, 0, im2->w, im2->h,
EVAS_COLORSPACE_ARGB8888, im2->im->image.data);
eng_gl_surface_unlock(re, im2);
return im2;
}
static void *
eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, int *err)
eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, int *err, Eina_Bool *tofree)
{
Render_Engine_GL_Generic *re = data;
Evas_GL_Image *im;
Evas_GL_Image *im_new = NULL;
Evas_GL_Image *im = image;
int error;
*image_data = NULL;
if (tofree) tofree = EINA_FALSE;
if (err) *err = EVAS_LOAD_ERROR_NONE;
if (!image)
if (!im)
{
if (err) *err = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
im = image;
if (im->native.data)
{
if (err) *err = EVAS_LOAD_ERROR_NONE;
return im;
}
if (im->orient != EVAS_IMAGE_ORIENT_NONE)
if (im->native.data)
return im;
if (im->im &&
im->orient != EVAS_IMAGE_ORIENT_NONE)
{
Evas_GL_Image *im_new = _rotate_image_data(data, image);
im_new = _rotate_image_data(data, image);
if (!im_new)
{
if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
@ -694,13 +674,14 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
re->window_use(re->software.ob);
if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.img) &&
(im->cs.space == EVAS_COLORSPACE_ARGB8888))
(im->cs.space == EVAS_COLORSPACE_ARGB8888) &&
secsym_tbm_surface_map &&
secsym_eglMapImageSEC)
{
if (im->tex->pt->dyn.checked_out > 0)
{
im->tex->pt->dyn.checked_out++;
*image_data = im->tex->pt->dyn.data;
if (err) *err = EVAS_LOAD_ERROR_NONE;
return im;
}
if (im->gc->shared->info.sec_tbm_surface)
@ -734,22 +715,73 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
if ((im->tex) && (im->tex->pt) && (im->tex->pt->dyn.data))
{
*image_data = im->tex->pt->dyn.data;
if (err) *err = EVAS_LOAD_ERROR_NONE;
return im;
}
re->window_use(re->software.ob);
#endif
/* use glReadPixels for FBOs (assume fbo > 0) */
if (!im->im && im->tex && im->tex->pt && im->tex->pt->fb)
{
Eina_Bool ok;
if (to_write)
{
// This could be implemented, but can't be efficient at all.
// Apps should avoid this situation.
ERR("Can not retrieve image data from FBO to write it back.");
if (err) *err = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
if (!tofree)
{
ERR("FBO image must be freed after image_data_get.");
if (err) *err = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
ok = eng_gl_surface_lock(data, im);
if (!ok)
{
if (err) *err = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
im_new = evas_gl_common_image_new_from_copied_data
(im->gc, im->tex->w, im->tex->h, NULL,
eng_image_alpha_get(data, image), EVAS_COLORSPACE_ARGB8888);
if (!im_new)
{
if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
ok = eng_gl_surface_read_pixels
(data, im, 0, 0, im_new->w, im_new->h,
EVAS_COLORSPACE_ARGB8888, im_new->im->image.data);
eng_gl_surface_unlock(data, im);
if (!ok)
{
if (err) *err = EVAS_LOAD_ERROR_GENERIC;
return NULL;
}
*image_data = im_new->im->image.data;
if (tofree) *tofree = EINA_TRUE;
return im_new;
}
/* Engine can be fail to create texture after cache drop like eng_image_content_hint_set function,
so it is need to add code which check im->im's NULL value*/
if (!im->im)
{
*image_data = NULL;
if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
{
// FIXME: Should we create an FBO and draw the texture there, to then read it back?
ERR("GL image has no source data, failed to get pixel data");
if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
#ifdef EVAS_CSERVE2
if (evas_cserve2_use_get() && evas_cache2_image_cached(&im->im->cache_entry))
@ -767,8 +799,6 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
{
if (im->references > 1)
{
Evas_GL_Image *im_new;
im_new = evas_gl_common_image_new_from_copied_data
(im->gc, im->im->cache_entry.w, im->im->cache_entry.h,
im->im->image.data,
@ -776,7 +806,6 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
eng_image_colorspace_get(data, image));
if (!im_new)
{
*image_data = NULL;
if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
@ -801,7 +830,6 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
case EVAS_COLORSPACE_ETC1_ALPHA:
ERR("This image is encoded in ETC1 or ETC2, not returning any data");
error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
*image_data = NULL;
break;
default:
abort();
@ -1599,7 +1627,7 @@ eng_gl_surface_lock(void *data EINA_UNUSED, void *surface)
{
Evas_GL_Image *im = surface;
if (!im->tex || !im->tex->pt)
if (!im || !im->tex || !im->tex->pt)
{
ERR("Can not lock image that is not a surface!");
return EINA_FALSE;
@ -1625,7 +1653,7 @@ eng_gl_surface_read_pixels(void *data EINA_UNUSED, void *surface,
Evas_Colorspace cspace, void *pixels)
{
Evas_GL_Image *im = surface;
GLint fmt = GL_BGRA;
GLint fmt = GL_BGRA, fbo = 0;
int done = 0;
EINA_SAFETY_ON_NULL_RETURN_VAL(pixels, EINA_FALSE);
@ -1647,7 +1675,9 @@ eng_gl_surface_read_pixels(void *data EINA_UNUSED, void *surface,
* But some devices don't support GL_BGRA, so we still need to convert.
*/
glsym_glBindFramebuffer(GL_FRAMEBUFFER, im->tex->pt->fb);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
if (fbo != (GLint) im->tex->pt->fb)
glsym_glBindFramebuffer(GL_FRAMEBUFFER, im->tex->pt->fb);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
// With GLX we will try to read BGRA even if the driver reports RGBA
@ -1676,7 +1706,8 @@ eng_gl_surface_read_pixels(void *data EINA_UNUSED, void *surface,
}
}
glsym_glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (fbo != (GLint) im->tex->pt->fb)
glsym_glBindFramebuffer(GL_FRAMEBUFFER, fbo);
return EINA_TRUE;
}

View File

@ -1212,17 +1212,20 @@ eng_image_dirty_region(void *data EINA_UNUSED, void *image, int x, int y, int w,
}
static void *
eng_image_data_get(void *data EINA_UNUSED, void *image, int to_write, DATA32 **image_data, int *err)
eng_image_data_get(void *data EINA_UNUSED, void *image, int to_write, DATA32 **image_data, int *err, Eina_Bool *tofree)
{
RGBA_Image *im;
RGBA_Image *im = image;
int error = EVAS_LOAD_ERROR_NONE;
if (!image)
*image_data = NULL;
if (err) *err = EVAS_LOAD_ERROR_NONE;
if (tofree) *tofree = EINA_FALSE;
if (!im)
{
*image_data = NULL;
return NULL;
if (err) *err = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return NULL;
}
im = image;
#ifdef EVAS_CSERVE2
if (evas_cserve2_use_get() && evas_cache2_image_cached(&im->cache_entry))
@ -1235,7 +1238,7 @@ eng_image_data_get(void *data EINA_UNUSED, void *image, int to_write, DATA32 **i
im = (RGBA_Image *)evas_cache2_image_writable(&im->cache_entry);
if (!im)
{
*image_data = NULL;
if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return NULL;
}
}