jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=fd4e133cc1af3351b79946cfb1bc6d79feec9d30

commit fd4e133cc1af3351b79946cfb1bc6d79feec9d30
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Thu Jul 2 11:52:16 2015 +0900

    Evas: Implement image_data_get for FBO images
---
 src/lib/evas/canvas/evas_object_image.c            |  62 +++++----
 src/lib/evas/include/evas_private.h                |   2 +-
 src/modules/evas/engines/gl_generic/evas_engine.c  | 149 +++++++++++++--------
 .../evas/engines/software_generic/evas_engine.c    |  17 ++-
 4 files changed, 135 insertions(+), 95 deletions(-)

diff --git a/src/lib/evas/canvas/evas_object_image.c 
b/src/lib/evas/canvas/evas_object_image.c
index 7134783..e18c58f 100644
--- a/src/lib/evas/canvas/evas_object_image.c
+++ b/src/lib/evas/canvas/evas_object_image.c
@@ -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)
-     {
-        int stride = 0;
-
-        if (ENFN->image_stride_get)
-          ENFN->image_stride_get(ENDT, o->engine_data, &stride);
-        else
-          stride = o->cur->image.w * 4;
+   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)
-          {
-             EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
-               state_write->image.stride = stride;
-             EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
-          }
+   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);
      }
+
    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)
diff --git a/src/lib/evas/include/evas_private.h 
b/src/lib/evas/include/evas_private.h
index 24f70cd..32e899c 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -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);
diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c 
b/src/modules/evas/engines/gl_generic/evas_engine.c
index 35005ea..3d2271e 100644
--- a/src/modules/evas/engines/gl_generic/evas_engine.c
+++ b/src/modules/evas/engines/gl_generic/evas_engine.c
@@ -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;
-     }
+     return im;
 
-   if (im->orient != EVAS_IMAGE_ORIENT_NONE)
+   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;
 }
diff --git a/src/modules/evas/engines/software_generic/evas_engine.c 
b/src/modules/evas/engines/software_generic/evas_engine.c
index b272f08..8199ab3 100644
--- a/src/modules/evas/engines/software_generic/evas_engine.c
+++ b/src/modules/evas/engines/software_generic/evas_engine.c
@@ -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;
                }
           }

-- 


Reply via email to