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 <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>
This commit is contained in:
kabeer khan 2015-04-22 11:25:38 +02:00 committed by Cedric BAIL
parent 5e4b523d51
commit ce45d443c1
4 changed files with 234 additions and 33 deletions

View 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;

View 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)

View 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;

View 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);