evas: fix rotation and flipping of image in gl engine
authorkabeer khan <kabeer.khan@samsung.com>
Wed, 22 Apr 2015 09:25:38 +0000 (11:25 +0200)
committerCedric BAIL <cedric@osg.samsung.com>
Wed, 22 Apr 2015 13:10:19 +0000 (15:10 +0200)
Summary:
fix rotation(90, 180, 270) and flipping(vertical, horizontal, transpose,
transverse) of evas image in gl engine backend.

@fix

T2338

Signed-off-by: kabeer khan <kabeer.khan@samsung.com>
Reviewers: cedric, jpeg

Subscribers: cedric

Differential Revision: https://phab.enlightenment.org/D2400

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/modules/evas/engines/gl_common/evas_gl_common.h
src/modules/evas/engines/gl_common/evas_gl_context.c
src/modules/evas/engines/gl_common/evas_gl_image.c
src/modules/evas/engines/gl_generic/evas_engine.c

index b81b913..d4ca68d 100644 (file)
@@ -644,8 +644,9 @@ struct _Evas_GL_Image
    int scale_hint, content_hint;
    int csize;
 
-   Eina_List       *filtered;
-   Eina_List       *targets;
+   Eina_List         *filtered;
+   Eina_List         *targets;
+   Evas_Image_Orient orient;
 
    unsigned char    dirty : 1;
    unsigned char    cached : 1;
index 9699bdd..b526eab 100644 (file)
@@ -1256,9 +1256,53 @@ evas_gl_common_context_target_surface_set(Evas_Engine_GL_Context *gc,
    PUSH_VERTEX(pn, x    , y + h, 0); PUSH_VERTEX(pn, x + w, y    , 0); \
    PUSH_VERTEX(pn, x + w, y + h, 0); PUSH_VERTEX(pn, x    , y + h, 0); \
    } while (0)
-#define PUSH_6_TEXUV(pn, x1, y1, x2, y2) do { \
-   PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y2); \
-   PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y2); \
+#define PUSH_6_TEXUV(pn, Tex, x1, y1, x2, y2) do {                      \
+   Evas_GL_Texture *_tex = Tex;                                         \
+   if (_tex && _tex->im)                                                \
+     {                                                                  \
+        switch (_tex->im->orient)                                       \
+          {                                                             \
+           case EVAS_IMAGE_ORIENT_NONE:                                 \
+              PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y2); \
+              PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y2); \
+              break;                                                    \
+           case EVAS_IMAGE_ORIENT_90:                                   \
+              PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y2); \
+              PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x2, y2); \
+              break;                                                    \
+           case EVAS_IMAGE_ORIENT_180:                                  \
+              PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x2, y1); \
+              PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y1); \
+              break;                                                    \
+           case EVAS_IMAGE_ORIENT_270:                                  \
+              PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y1); \
+              PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x1, y1); \
+              break;                                                    \
+           case EVAS_IMAGE_FLIP_HORIZONTAL:                             \
+              PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y2); \
+              PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x2, y2); \
+              break;                                                    \
+           case EVAS_IMAGE_FLIP_VERTICAL:                               \
+              PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y1); \
+              PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y1); \
+              break;                                                    \
+           case EVAS_IMAGE_FLIP_TRANSVERSE:                             \
+              PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y2); \
+              PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x1, y2); \
+              break;                                                    \
+           case EVAS_IMAGE_FLIP_TRANSPOSE:                              \
+              PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x2, y1); \
+              PUSH_TEXUV(pn, x1, y2); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x2, y1); \
+              break;                                                    \
+           default:                                                     \
+              ERR("Wrong orientation");                                 \
+          }                                                             \
+     }                                                                  \
+   else                                                                 \
+     {                                                                  \
+        PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x1, y2); \
+        PUSH_TEXUV(pn, x2, y1); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x1, y2); \
+     }                                                                  \
    } while (0)
 #define PUSH_6_TEXUV2(pn, x1, y1, x2, y2) do { \
    PUSH_TEXUV2(pn, x1, y1); PUSH_TEXUV2(pn, x2, y1); PUSH_TEXUV2(pn, x1, y2); \
@@ -1918,6 +1962,7 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
    Evas_GL_Texture_Pool *pt;
    GLfloat tx1, tx2, ty1, ty2;
    GLfloat offsetx, offsety;
+   double pw, ph;
    Eina_Bool blend = EINA_FALSE;
    Evas_GL_Shader shader = SHADER_IMG;
    GLuint prog = gc->shared->shader[shader].prog;
@@ -1992,23 +2037,36 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
    pipe_region_expand(gc, pn, x, y, w, h);
    PIPE_GROW(gc, pn, 6);
 
+   pw = pt->w;
+   ph = pt->h;
+   if (tex->im &&
+       (tex->im->orient == EVAS_IMAGE_ORIENT_90 ||
+        tex->im->orient == EVAS_IMAGE_ORIENT_270 ||
+        tex->im->orient == EVAS_IMAGE_FLIP_TRANSPOSE ||
+        tex->im->orient == EVAS_IMAGE_FLIP_TRANSVERSE))
+     {
+        // Adjust size for taking rotation into account as im->w and h are already modified.
+        pw = pt->h;
+        ph = pt->w;
+     }
+
    if ((tex->im) && (tex->im->native.data) && (!tex->im->native.yinvert))
      {
-        tx1 = ((double)(offsetx) + sx) / (double)pt->w;
-        ty1 = 1.0 - ((double)(offsety) + sy) / (double)pt->h;
-        tx2 = ((double)(offsetx) + sx + sw) / (double)pt->w;
-        ty2 = 1.0 - ((double)(offsety) + sy + sh) / (double)pt->h;
+        tx1 = ((double)(offsetx) + sx) / pw;
+        ty1 = 1.0 - ((double)(offsety) + sy) / ph;
+        tx2 = ((double)(offsetx) + sx + sw) / pw;
+        ty2 = 1.0 - ((double)(offsety) + sy + sh) / ph;
      }
    else
      {
-        tx1 = ((double)(offsetx) + sx) / (double)pt->w;
-        ty1 = ((double)(offsety) + sy) / (double)pt->h;
-        tx2 = ((double)(offsetx) + sx + sw) / (double)pt->w;
-        ty2 = ((double)(offsety) + sy + sh) / (double)pt->h;
+        tx1 = ((double)(offsetx) + sx) / pw;
+        ty1 = ((double)(offsety) + sy) / ph;
+        tx2 = ((double)(offsetx) + sx + sw) / pw;
+        ty2 = ((double)(offsety) + sy + sh) / ph;
      }
 
    PUSH_6_VERTICES(pn, x, y, w, h);
-   PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
+   PUSH_6_TEXUV(pn, tex, tx1, ty1, tx2, ty2);
 
    if (sam)
      {
@@ -2098,7 +2156,7 @@ evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
      }
 
    PUSH_6_VERTICES(pn, x, y, w, h);
-   PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
+   PUSH_6_TEXUV(pn, NULL, tx1, ty1, tx2, ty2);
    PUSH_MASK(pn, mtex, mx, my, mw, mh);
    PUSH_6_COLORS(pn, r, g, b, a);
 }
@@ -2174,7 +2232,7 @@ evas_gl_common_context_yuv_push(Evas_Engine_GL_Context *gc,
    t2y2 = ((sy + sh) / 2) / (double)tex->ptu->h;
 
    PUSH_6_VERTICES(pn, x, y, w, h);
-   PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
+   PUSH_6_TEXUV(pn, NULL, tx1, ty1, tx2, ty2);
    PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
    PUSH_6_TEXUV3(pn, t2x1, t2y1, t2x2, t2y2);
    PUSH_MASK(pn, mtex, mx, my, mw, mh);
@@ -2252,7 +2310,7 @@ evas_gl_common_context_yuy2_push(Evas_Engine_GL_Context *gc,
    t2y2 = (sy + sh) / (double)tex->ptuv->h;
 
    PUSH_6_VERTICES(pn, x, y, w, h);
-   PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
+   PUSH_6_TEXUV(pn, NULL, tx1, ty1, tx2, ty2);
    PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
    PUSH_MASK(pn, mtex, mx, my, mw, mh);
    if (!nomul)
@@ -2332,7 +2390,7 @@ evas_gl_common_context_nv12_push(Evas_Engine_GL_Context *gc,
    t2y2 = (sy + sh) / (double)tex->ptuv->h;
 
    PUSH_6_VERTICES(pn, x, y, w, h);
-   PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
+   PUSH_6_TEXUV(pn, NULL, tx1, ty1, tx2, ty2);
    PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
    PUSH_MASK(pn, mtex, mx, my, mw, mh);
    if (!nomul)
@@ -2416,7 +2474,7 @@ evas_gl_common_context_rgb_a_pair_push(Evas_Engine_GL_Context *gc,
    t2y2 = (tex->y + sy + sh) / (double)tex->pta->h;
 
    PUSH_6_VERTICES(pn, x, y, w, h);
-   PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
+   PUSH_6_TEXUV(pn, NULL, tx1, ty1, tx2, ty2);
    PUSH_6_TEXA(pn, t2x1, t2y1, t2x2, t2y2);
    PUSH_MASK(pn, mtex, mx, my, mw, mh);
    if (!nomul)
index 6f62844..331c48e 100644 (file)
@@ -228,6 +228,7 @@ found_cspace:
    im->gc = gc;
    im->cached = 1;
    im->cs.space = cspace;
+   im->orient = EVAS_IMAGE_ORIENT_NONE;
    im->alpha = im->im->cache_entry.flags.alpha;
    im->w = im->im->cache_entry.w;
    im->h = im->im->cache_entry.h;
index 93521bd..31eaabc 100644 (file)
@@ -43,7 +43,18 @@ static int _evas_engine_GL_log_dom = -1;
 #define WRN(...) EINA_LOG_DOM_WARN(_evas_engine_GL_log_dom, __VA_ARGS__)
 #define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_GL_log_dom, __VA_ARGS__)
 
+#ifdef GL_GLES
+# ifndef GL_FRAMEBUFFER
+#  define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
+# endif
+#else
+# ifndef GL_FRAMEBUFFER
+#  define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
+# endif
+#endif
+
 static int eng_gl_image_direct_get(void *data EINA_UNUSED, void *image);
+static int eng_gl_surface_destroy(void *data, void *surface);
 
 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)
@@ -473,14 +484,27 @@ eng_image_free(void *data, void *image)
 static void
 eng_image_size_get(void *data EINA_UNUSED, void *image, int *w, int *h)
 {
+   Evas_GL_Image *im;
    if (!image)
      {
         *w = 0;
         *h = 0;
         return;
      }
-   if (w) *w = ((Evas_GL_Image *)image)->w;
-   if (h) *h = ((Evas_GL_Image *)image)->h;
+   im = image;
+   if (im->orient == EVAS_IMAGE_ORIENT_90 ||
+       im->orient == EVAS_IMAGE_ORIENT_270 ||
+       im->orient == EVAS_IMAGE_FLIP_TRANSPOSE ||
+       im->orient == EVAS_IMAGE_FLIP_TRANSVERSE)
+     {
+        if (w) *w = ((Evas_GL_Image *)image)->h;
+        if (h) *h = ((Evas_GL_Image *)image)->w;
+     }
+   else
+     {
+        if (w) *w = ((Evas_GL_Image *)image)->w;
+        if (h) *h = ((Evas_GL_Image *)image)->h;
+     }
 }
 
 static void *
@@ -548,6 +572,91 @@ eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h)
    return image;
 }
 
+static Evas_GL_Image *
+_rotate_image_data(void *data, void *img)
+{
+   int alpha;
+   Evas_GL_Image *im1, *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);
+
+   if (im1->orient == EVAS_IMAGE_ORIENT_90 ||
+       im1->orient == EVAS_IMAGE_ORIENT_270 ||
+       im1->orient == EVAS_IMAGE_FLIP_TRANSPOSE ||
+       im1->orient == EVAS_IMAGE_FLIP_TRANSVERSE)
+     {
+        w = im1->h;
+        h = im1->w;
+     }
+
+   im2 = evas_gl_common_image_surface_new(gl_context, w, h, alpha);
+
+   evas_gl_common_context_target_surface_set(gl_context, im2);
+
+   // Create a new and temporary context
+   dc = evas_common_draw_context_new();
+   evas_common_draw_context_set_clip(dc, 0, 0, im2->w, im2->h);
+   gl_context->dc = dc;
+
+   // Image draw handle the rotation magically for us
+   evas_gl_common_image_draw(gl_context, im1,
+                             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);
+   GLERRV("glsym_glBindFramebuffer");
+
+   // 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);
+   GLERRV("glsym_glBindFramebuffer");
+
+   return im2;
+}
+
 static void *
 eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, int *err)
 {
@@ -555,20 +664,34 @@ eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data, i
    Evas_GL_Image *im;
    int error;
 
+   *image_data = NULL;
+
    if (!image)
      {
-        *image_data = NULL;
         if (err) *err = EVAS_LOAD_ERROR_GENERIC;
         return NULL;
      }
    im = image;
    if (im->native.data)
      {
-        *image_data = NULL;
         if (err) *err = EVAS_LOAD_ERROR_NONE;
         return im;
      }
 
+   if (im->orient != EVAS_IMAGE_ORIENT_NONE)
+     {
+        Evas_GL_Image *im_new = _rotate_image_data(data, image);
+        if (!im_new)
+          {
+             if (err) *err = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+             return im;
+          }
+        evas_gl_common_image_free(im);
+
+        *image_data = im_new->im->image.data;
+        return im_new;
+     }
+
 #ifdef GL_GLES
    re->window_use(re->software.ob);
 
@@ -771,6 +894,32 @@ eng_image_data_put(void *data, void *image, DATA32 *image_data)
    return im;
 }
 
+static void *
+eng_image_orient_set(void *data, void *image, Evas_Image_Orient orient)
+{
+   Render_Engine_GL_Generic *re = data;
+   Evas_GL_Image *im;
+
+   if (!image) return NULL;
+   im = image;
+   if (im->orient == orient) return image;
+
+   re->window_use(re->software.ob);
+
+   im->orient = orient;
+   return im;
+}
+
+static Evas_Image_Orient
+eng_image_orient_get(void *data EINA_UNUSED, void *image)
+{
+   Evas_GL_Image *im;
+
+   if (!image) return EVAS_IMAGE_ORIENT_NONE;
+   im = image;
+   return im->orient;
+}
+
 static void
 eng_image_data_preload_request(void *data, void *image, const Eo *target)
 {
@@ -1474,16 +1623,6 @@ eng_gl_surface_read_pixels(void *data, void *surface,
         return EINA_FALSE;
      }
 
-#ifdef GL_GLES
-# ifndef GL_FRAMEBUFFER
-#  define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
-# endif
-#else
-# ifndef GL_FRAMEBUFFER
-#  define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
-# endif
-#endif
-
    /* Since this is an FBO, the pixels are already in the right Y order.
     * But some devices don't support GL_BGRA, so we still need to convert.
     */
@@ -2351,6 +2490,8 @@ module_open(Evas_Module *em)
    ORD(image_data_preload_cancel);
    ORD(image_alpha_set);
    ORD(image_alpha_get);
+   ORD(image_orient_set);
+   ORD(image_orient_get);
    ORD(image_border_set);
    ORD(image_border_get);
    ORD(image_draw);