From ce45d443c107ef0da87d407ffc5539e9eba9eef5 Mon Sep 17 00:00:00 2001 From: kabeer khan Date: Wed, 22 Apr 2015 11:25:38 +0200 Subject: [PATCH] evas: fix rotation and flipping of image in gl engine 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 Reviewers: cedric, jpeg Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D2400 Signed-off-by: Cedric BAIL --- .../evas/engines/gl_common/evas_gl_common.h | 5 +- .../evas/engines/gl_common/evas_gl_context.c | 92 ++++++++-- .../evas/engines/gl_common/evas_gl_image.c | 1 + .../evas/engines/gl_generic/evas_engine.c | 169 ++++++++++++++++-- 4 files changed, 234 insertions(+), 33 deletions(-) diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h index b81b913167..d4ca68d0b9 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_common.h +++ b/src/modules/evas/engines/gl_common/evas_gl_common.h @@ -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; diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c index 9699bdd99a..b526eab101 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_context.c +++ b/src/modules/evas/engines/gl_common/evas_gl_context.c @@ -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) diff --git a/src/modules/evas/engines/gl_common/evas_gl_image.c b/src/modules/evas/engines/gl_common/evas_gl_image.c index 6f62844242..331c48e870 100644 --- a/src/modules/evas/engines/gl_common/evas_gl_image.c +++ b/src/modules/evas/engines/gl_common/evas_gl_image.c @@ -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; diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index 93521bd27d..31eaabcf0e 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -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);