Evas masking: Add fast path for image-only masks in GL.

This will currently optimize most of the masks when using the
GL engine[1].

This is a very special case that adds a highly optimized path
for masking in GL. It works by creating a virtual image, containing
a pointer to the original image and a new geometry[2].

Instead of creating a new FBO-based surface (image_map_surface),
we refer to the original image and adjust the mask geometry on
the fly.

KNOWN BUGS:
- masking a map with such a scaled image is now broken.

[1] Right now all masks are simple Evas Object Image, so that means
    all cases of masking, except masks of masks, or masks of maps,
    will be optimized with this new method.

[2] This virtual image mechanism is still quite hackish and may
    be improved (for memory usage, refcounting, etc...)
This commit is contained in:
Jean-Philippe Andre 2015-02-25 19:05:12 +09:00
parent f298183d4e
commit fddaf62fcc
11 changed files with 328 additions and 144 deletions

View File

@ -3541,6 +3541,18 @@ state_write:
}
}
static inline void
_image_mask_image_set(Evas_Object_Protected_Data *obj, Eina_Bool smooth, void *image)
{
if ((obj->mask->image != image) || (obj->mask->smooth_scale != smooth))
{
EINA_COW_WRITE_BEGIN(evas_object_mask_cow, obj->mask, Evas_Object_Mask_Data, mask)
mask->image = image;
mask->smooth_scale = smooth;
EINA_COW_WRITE_END(evas_object_mask_cow, obj->mask, mask);
}
}
static void
evas_object_image_render_pre(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
@ -3561,6 +3573,15 @@ evas_object_image_render_pre(Evas_Object *eo_obj,
if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1)) return;
/* plain mask images */
if (obj->mask->is_mask && !o->cur->scene && !o->cur->source)
{
DBG("Setting image pointer in mask data.");
_image_mask_image_set(obj, o->cur->smooth_scale, o->engine_data);
}
else
_image_mask_image_set(obj, EINA_FALSE, NULL);
/* if someone is clipping this obj - go calculate the clipper */
if (obj->cur->clipper)
{

View File

@ -368,7 +368,10 @@ _evas_render_phase1_direct(Evas_Public_Data *e,
{
/* is image clipper */
if (_evas_render_object_changed_get(obj))
_evas_mask_redraw_set(e, obj);
{
obj->func->render_pre(obj->object, obj, obj->private_data);
_evas_mask_redraw_set(e, obj);
}
}
}
for (i = 0; i < render_objects->count; i++)
@ -1768,6 +1771,7 @@ evas_render_mask_subrender(Evas_Public_Data *evas,
int level)
{
int x, y, w, h, r, g, b, a;
Eina_Bool is_image, done = EINA_FALSE;
void *ctx;
if (!mask) return;
@ -1779,6 +1783,8 @@ evas_render_mask_subrender(Evas_Public_Data *evas,
RD(level, "evas_render_mask_subrender(%p, prev: %p)\n", mask, prev_mask);
is_image = eo_isa(mask->object, EVAS_IMAGE_CLASS);
x = mask->cur->geometry.x;
y = mask->cur->geometry.y;
w = mask->cur->geometry.w;
@ -1821,81 +1827,102 @@ evas_render_mask_subrender(Evas_Public_Data *evas,
EINA_COW_WRITE_BEGIN(evas_object_mask_cow, mask->mask, Evas_Object_Mask_Data, mdata)
mdata->redraw = EINA_FALSE;
/* delete render surface if changed or if already alpha
* (we don't know how to render objects to alpha) */
if (mdata->surface && ((w != mdata->w) || (h != mdata->h) || mdata->is_alpha))
if (is_image && !prev_mask && mdata->image && ENFN->image_scaled_update)
{
ENFN->image_map_surface_free(ENDT, mdata->surface);
mdata->surface = NULL;
/* Fast path (for GL) that avoids creating a map surface, render the
* scaled image in it, when the shaders can just scale on the fly. */
void *scaled = ENFN->image_scaled_update
(ENDT, mdata->surface, mdata->image, w, h,
mdata->smooth_scale, EINA_TRUE, EVAS_COLORSPACE_GRY8);
if (scaled)
{
done = EINA_TRUE;
if (mdata->surface && (mdata->surface != scaled))
ENFN->image_map_surface_free(ENDT, mdata->surface);
mdata->surface = scaled;
mdata->w = w;
mdata->h = h;
mdata->is_alpha = (ENFN->image_colorspace_get(ENDT, scaled) == EVAS_COLORSPACE_GRY8);
}
}
/* create new RGBA render surface if needed */
if (!mdata->surface)
if (!done)
{
mdata->surface = ENFN->image_map_surface_new(ENDT, w, h, EINA_TRUE);
if (!mdata->surface) goto end;
mdata->is_alpha = EINA_FALSE;
mdata->w = w;
mdata->h = h;
}
/* delete render surface if changed or if already alpha
* (we don't know how to render objects to alpha) */
if (mdata->surface && ((w != mdata->w) || (h != mdata->h) || mdata->is_alpha))
{
ENFN->image_map_surface_free(ENDT, mdata->surface);
mdata->surface = NULL;
}
/* Clear surface with transparency */
ctx = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, ctx, 0, 0, 0, 0);
ENFN->context_render_op_set(ENDT, ctx, EVAS_RENDER_COPY);
ENFN->rectangle_draw(ENDT, ctx, mdata->surface, 0, 0, w, h, EINA_FALSE);
ENFN->context_free(ENDT, ctx);
/* create new RGBA render surface if needed */
if (!mdata->surface)
{
mdata->surface = ENFN->image_map_surface_new(ENDT, w, h, EINA_TRUE);
if (!mdata->surface) goto end;
mdata->is_alpha = EINA_FALSE;
mdata->w = w;
mdata->h = h;
}
/* Render mask to RGBA surface */
ctx = ENFN->context_new(ENDT);
if (prev_mask)
{
ENFN->context_clip_image_set(ENDT, ctx,
prev_mask->mask->surface,
prev_mask->cur->geometry.x - x,
prev_mask->cur->geometry.y - y);
}
evas_render_mapped(evas, mask->object, mask, ctx, mdata->surface,
-x, -y, 1, 0, 0, evas->output.w, evas->output.h,
NULL, level, EINA_TRUE, EINA_FALSE);
ENFN->context_free(ENDT, ctx);
/* Clear surface with transparency */
ctx = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, ctx, 0, 0, 0, 0);
ENFN->context_render_op_set(ENDT, ctx, EVAS_RENDER_COPY);
ENFN->rectangle_draw(ENDT, ctx, mdata->surface, 0, 0, w, h, EINA_FALSE);
ENFN->context_free(ENDT, ctx);
/* BEGIN HACK */
/* Render mask to RGBA surface */
ctx = ENFN->context_new(ENDT);
if (prev_mask)
{
ENFN->context_clip_image_set(ENDT, ctx,
prev_mask->mask->surface,
prev_mask->cur->geometry.x - x,
prev_mask->cur->geometry.y - y);
}
evas_render_mapped(evas, mask->object, mask, ctx, mdata->surface,
-x, -y, 1, 0, 0, evas->output.w, evas->output.h,
NULL, level, EINA_TRUE, EINA_FALSE);
ENFN->context_free(ENDT, ctx);
/* Now we want to convert this RGBA surface to Alpha.
* NOTE: So, this is not going to work with the GL engine but only with
* the SW engine. Here's the detection hack:
* FIXME: If you know of a way to support rendering to GL_ALPHA in GL,
* then we should render directly to an ALPHA surface. A priori,
* GLES FBO does not support this.
*/
if (!ENFN->gl_surface_read_pixels)
{
RGBA_Image *alpha_surface;
DATA32 *rgba;
DATA8* alpha;
/* BEGIN HACK */
alpha_surface = ENFN->image_new_from_copied_data
(ENDT, w, h, NULL, EINA_TRUE, EVAS_COLORSPACE_GRY8);
if (!alpha_surface) goto end;
/* Now we want to convert this RGBA surface to Alpha.
* NOTE: So, this is not going to work with the GL engine but only with
* the SW engine. Here's the detection hack:
* FIXME: If you know of a way to support rendering to GL_ALPHA in GL,
* then we should render directly to an ALPHA surface. A priori,
* GLES FBO does not support this.
*/
if (!ENFN->gl_surface_read_pixels)
{
RGBA_Image *alpha_surface;
DATA32 *rgba;
DATA8* alpha;
/* Copy alpha channel */
rgba = ((RGBA_Image *) mdata->surface)->image.data;
alpha = alpha_surface->image.data8;
for (y = h; y; --y)
for (x = w; x; --x, alpha++, rgba++)
*alpha = (DATA8) A_VAL(rgba);
alpha_surface = ENFN->image_new_from_copied_data
(ENDT, w, h, NULL, EINA_TRUE, EVAS_COLORSPACE_GRY8);
if (!alpha_surface) goto end;
/* Now we can drop the original surface */
ENFN->image_map_surface_free(ENDT, mdata->surface);
mdata->surface = alpha_surface;
mdata->is_alpha = EINA_TRUE;
/* Copy alpha channel */
rgba = ((RGBA_Image *) mdata->surface)->image.data;
alpha = alpha_surface->image.data8;
for (y = h; y; --y)
for (x = w; x; --x, alpha++, rgba++)
*alpha = (DATA8) A_VAL(rgba);
/* Now we can drop the original surface */
ENFN->image_map_surface_free(ENDT, mdata->surface);
mdata->surface = alpha_surface;
mdata->is_alpha = EINA_TRUE;
}
/* END OF HACK */
}
mdata->surface = ENFN->image_dirty_region(ENDT, mdata->surface, 0, 0, w, h);
/* END OF HACK */
end:
EINA_COW_WRITE_END(evas_object_mask_cow, mask->mask, mdata);

View File

@ -911,10 +911,12 @@ struct _Evas_Object_3D_Data
struct _Evas_Object_Mask_Data
{
void *surface;
void *image; // original image
int w, h;
Eina_Bool is_mask : 1;
Eina_Bool redraw : 1;
Eina_Bool is_alpha : 1;
Eina_Bool smooth_scale : 1;
};
struct _Evas_Object_Protected_State
@ -1279,6 +1281,7 @@ struct _Evas_Func
void *(*image_map_surface_new) (void *data, int w, int h, int alpha);
void (*image_map_surface_free) (void *data, void *surface);
void (*image_map_clean) (void *data, RGBA_Map *m);
void *(*image_scaled_update) (void *data, void *scaled, void *image, int dst_w, int dst_h, Eina_Bool smooth, Eina_Bool alpha, Evas_Colorspace cspace);
void (*image_content_hint_set) (void *data, void *surface, int hint);
int (*image_content_hint_get) (void *data, void *surface);

View File

@ -491,6 +491,7 @@ struct _Evas_Engine_GL_Context
Eina_Bool use_texsam : 1;
Eina_Bool use_texm : 1;
Eina_Bool anti_alias : 1;
Eina_Bool mask_smooth : 1;
Evas_GL_Image *im;
GLuint buffer;
int buffer_alloc;
@ -605,6 +606,12 @@ struct _Evas_GL_Image
unsigned char loose : 1;
} native;
struct {
Evas_GL_Image *origin;
int w, h;
Eina_Bool smooth : 1;
} scaled;
int scale_hint, content_hint;
int csize;
@ -700,46 +707,46 @@ void evas_gl_common_context_line_push(Evas_Engine_GL_Context *gc,
void evas_gl_common_context_rectangle_push(Evas_Engine_GL_Context *gc,
int x, int y, int w, int h,
int r, int g, int b, int a,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh);
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth);
void evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth, Eina_Bool tex_only);
void evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a);
void evas_gl_common_context_yuv_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth);
void evas_gl_common_context_yuy2_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth);
void evas_gl_common_context_nv12_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth);
void evas_gl_common_context_rgb_a_pair_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth);
void evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc,

View File

@ -1251,10 +1251,10 @@ evas_gl_common_context_target_surface_set(Evas_Engine_GL_Context *gc,
#define PUSH_MASK(pn, mtex, mx, my, mw, mh) if (mtex) do { \
GLfloat tmx1, tmx2, tmy1, tmy2; \
tmx1 = (mtex->x + mx) / (double)mtex->pt->w; \
tmy1 = (mtex->y + my) / (double)mtex->pt->h; \
tmx2 = (mtex->x + mx + mw) / (double)mtex->pt->w; \
tmy2 = (mtex->y + my + mh) / (double)mtex->pt->h; \
tmx1 = mx; \
tmy1 = my; \
tmx2 = mx + mw; \
tmy2 = my + mh; \
PUSH_TEXM(pn, tmx1, tmy1); \
PUSH_TEXM(pn, tmx2, tmy1); \
PUSH_TEXM(pn, tmx1, tmy2); \
@ -1262,6 +1262,12 @@ evas_gl_common_context_target_surface_set(Evas_Engine_GL_Context *gc,
PUSH_TEXM(pn, tmx2, tmy2); \
PUSH_TEXM(pn, tmx1, tmy2); \
} while(0)
/* was:
tmx1 = (mtex->x + mx) / (double)mtex->pt->w; \
tmy1 = (mtex->y + my) / (double)mtex->pt->h; \
tmx2 = (mtex->x + mx + mw) / (double)mtex->pt->w; \
tmy2 = (mtex->y + my + mh) / (double)mtex->pt->h; \
*/
#define PIPE_GROW(gc, pn, inc) \
int nv = gc->pipe[pn].array.num * 3; (void) nv; \
@ -1580,7 +1586,7 @@ evas_gl_common_context_rectangle_push(Evas_Engine_GL_Context *gc,
int x, int y, int w, int h,
int r, int g, int b, int a,
Evas_GL_Texture *mtex,
int mx, int my, int mw, int mh)
double mx, double my, double mw, double mh, Eina_Bool mask_smooth)
{
Eina_Bool blend = EINA_FALSE;
Evas_GL_Shader shader = SHADER_RECT;
@ -1728,7 +1734,7 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth, Eina_Bool tex_only)
{
@ -1959,6 +1965,7 @@ evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texuv3 = 0;
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.use_texsam = sam;
gc->pipe[pn].array.mask_smooth = mask_smooth;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -2007,7 +2014,7 @@ evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a)
{
GLfloat tx1, tx2, ty1, ty2;
@ -2047,6 +2054,7 @@ evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texuv3 = 0;
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.use_texsam = 0;
gc->pipe[pn].array.mask_smooth = mask_smooth;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -2077,7 +2085,7 @@ evas_gl_common_context_yuv_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth)
{
@ -2126,6 +2134,7 @@ evas_gl_common_context_yuv_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texuv3 = 1;
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.use_texsam = 0;
gc->pipe[pn].array.mask_smooth = mask_smooth;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -2153,7 +2162,7 @@ evas_gl_common_context_yuy2_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth)
{
@ -2201,6 +2210,7 @@ evas_gl_common_context_yuy2_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texuv3 = 0;
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.use_texsam = 0;
gc->pipe[pn].array.mask_smooth = mask_smooth;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -2227,7 +2237,7 @@ evas_gl_common_context_nv12_push(Evas_Engine_GL_Context *gc,
Evas_GL_Texture *tex,
double sx, double sy, double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth)
{
@ -2277,6 +2287,7 @@ evas_gl_common_context_nv12_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texuv3 = 0;
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.use_texsam = 0;
gc->pipe[pn].array.mask_smooth = mask_smooth;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -2304,7 +2315,7 @@ evas_gl_common_context_rgb_a_pair_push(Evas_Engine_GL_Context *gc,
double sx, double sy,
double sw, double sh,
int x, int y, int w, int h,
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
Evas_GL_Texture *mtex, double mx, double my, double mw, double mh, Eina_Bool mask_smooth,
int r, int g, int b, int a,
Eina_Bool smooth)
@ -2359,6 +2370,7 @@ evas_gl_common_context_rgb_a_pair_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texa = EINA_TRUE;
gc->pipe[pn].array.use_texsam = 0;
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.mask_smooth = mask_smooth;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -2589,6 +2601,7 @@ evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc,
gc->pipe[pn].array.use_texm = !!mtex;
gc->pipe[pn].array.use_texa = !!mtex;
gc->pipe[pn].array.use_texsam = gc->pipe[pn].array.use_texm;
gc->pipe[pn].array.mask_smooth = EINA_FALSE;
pipe_region_expand(gc, pn, x, y, w, h);
PIPE_GROW(gc, pn, 6);
@ -3281,7 +3294,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
if (shared->info.anisotropic > 0.0)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, shared->info.anisotropic);
#endif
if (gc->pipe[i].shader.smooth)
if (gc->pipe[i].array.mask_smooth) // (gc->pipe[i].shader.smooth)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -3359,6 +3372,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
gc->pipe[i].array.use_texa = 0;
gc->pipe[i].array.use_texsam = 0;
gc->pipe[i].array.use_texm = 0;
gc->pipe[i].array.mask_smooth = 0;
gc->pipe[i].array.vertex = NULL;
gc->pipe[i].array.color = NULL;

View File

@ -61,14 +61,16 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
{
Evas_Engine_GL_Context *gc = context;
RGBA_Draw_Context *dc = draw_context;
Evas_GL_Texture *tex, *mtex = NULL;
Evas_GL_Image *mask = gc->dc->clip.mask;
Evas_GL_Texture *tex, *mtex = mask ? mask->tex : NULL;
Cutout_Rect *rct;
int r, g, b, a;
double ssx, ssy, ssw, ssh;
int c, cx, cy, cw, ch;
int i;
int sx, sy, sw, sh;
double mmx = 0.0, mmy = 0.0, mmw = 0.0, mmh = 0.0;
double mx = 0.0, my = 0.0, mw = 0.0, mh = 0.0;
Eina_Bool mask_smooth = EINA_FALSE;
if (dc != gc->dc) return;
tex = fg->ext_dat;
@ -82,36 +84,43 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
if (gc->dc->clip.mask && (sw > 0) && (sh > 0))
{
// FIXME: This code path does not handle half the stuff the other path does...
Evas_GL_Image *mask = gc->dc->clip.mask;
int nx, ny, nw, nh, dx, dy, dw, dh;
double mx, my, mw, mh;
double nx, ny, nw, nh, dx, dy, dw, dh;
const double mask_x = gc->dc->clip.mask_x;
const double mask_y = gc->dc->clip.mask_y;
const double tmw = mtex->pt->w;
const double tmh = mtex->pt->h;
double scalex = 1.0;
double scaley = 1.0;
if (mask->tex)
// canvas coords
nx = x; ny = y; nw = tex->w; nh = tex->h;
RECTS_CLIP_TO_RECT(nx, ny, nw, nh,
gc->dc->clip.x, gc->dc->clip.y,
gc->dc->clip.w, gc->dc->clip.h);
if ((nw < 1) || (nh < 1)) return;
dx = x; dy = y; dw = sw; dh = sh;
mx = mask_x; my = mask_y;
if (mask->scaled.origin && mask->scaled.w && mask->scaled.h)
{
nx = x; ny = y; nw = tex->w; nh = tex->h;
RECTS_CLIP_TO_RECT(nx, ny, nw, nh,
gc->dc->clip.x, gc->dc->clip.y,
gc->dc->clip.w, gc->dc->clip.h);
if ((nw < 1) || (nh < 1)) return;
//ssx = (double)sx + ((double)(sw * (nx - x)) / (double)(tex->w));
//ssy = (double)sy + ((double)(sh * (ny - y)) / (double)(tex->h));
//ssw = ((double)sw * (double)(nw)) / (double)(tex->w);
//ssh = ((double)sh * (double)(nh)) / (double)(tex->h);
dx = x; dy = y; dw = sw; dh = sh;
mx = gc->dc->clip.mask_x; my = gc->dc->clip.mask_y; mw = mask->w; mh = mask->h;
//RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch);
RECTS_CLIP_TO_RECT(mx, my, mw, mh, dx, dy, dw, dh);
mmx = (double)(mx - gc->dc->clip.mask_x) + ((double)(mw * (nx - dx)) / (double)(dw));
mmy = (double)(my - gc->dc->clip.mask_y) + ((double)(mh * (ny - dy)) / (double)(dh));
mmw = ((double)mw * (double)(nw)) / (double)(dw);
mmh = ((double)mh * (double)(nh)) / (double)(dh);
mtex = mask->tex;
mw = mask->scaled.w;
mh = mask->scaled.h;
scalex = mask->w / (double)mask->scaled.w;
scaley = mask->h / (double)mask->scaled.h;
mask_smooth = mask->scaled.smooth;
}
else
{
mw = mask->w;
mh = mask->h;
}
//RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch);
RECTS_CLIP_TO_RECT(mx, my, mw, mh, dx, dy, dw, dh);
// convert to tex coords
mx = (mtex->x / tmw) + ((mx - mask_x + (mw * (nx - dx)) / dw) * scalex / tmw);
my = (mtex->y / tmh) + ((my - mask_y + (mh * (ny - dy)) / dy) * scaley / tmh);
mw = (mw * nw * scalex / dw) / tmw;
mh = (mh * nh * scaley / dh) / tmh;
}
if ((!gc->dc->cutout.rects) ||
@ -133,7 +142,7 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
0.0, 0.0, 0.0, 0.0,
// sx, sy, sw, sh,
x, y, tex->w, tex->h,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a);
return;
}
@ -144,7 +153,7 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
evas_gl_common_context_font_push(gc, tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a);
}
else
@ -153,7 +162,7 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
0.0, 0.0, 0.0, 0.0,
// sx, sy, sw, sh,
x, y, tex->w, tex->h,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a);
}
return;
@ -183,7 +192,7 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
0.0, 0.0, 0.0, 0.0,
// sx, sy, sw, sh,
x, y, tex->w, tex->h,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a);
continue;
}
@ -194,7 +203,7 @@ evas_gl_font_texture_draw(void *context, void *surface EINA_UNUSED, void *draw_c
evas_gl_common_context_font_push(gc, tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a);
}
evas_common_draw_context_cutouts_free(_evas_gl_common_cutout_rects);

View File

@ -690,6 +690,9 @@ evas_gl_common_image_free(Evas_GL_Image *im)
im->references--;
if (im->references > 0) return;
if (im->scaled.origin)
evas_gl_common_image_free(im->scaled.origin);
if (im->native.func.free)
im->native.func.free(im->native.func.data, im);
@ -964,6 +967,9 @@ evas_gl_common_image_map_draw(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
mmw = mw;
mmh = mh;
mtex = mask->tex;
// TODO: implement support for scaled masks
//if (mask->scaled.origin)
//mask_smooth = mask->scaled.smooth;
}
evas_gl_common_context_image_map_push(gc, im->tex, npoints, p,
@ -984,9 +990,10 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
Eina_Bool yuv, Eina_Bool yuy2, Eina_Bool nv12,
Eina_Bool rgb_a_pair)
{
double mmx = 0, mmy = 0, mmw = 0, mmh = 0;
double mx = 0, my = 0, mw = 0, mh = 0;
double ssx, ssy, ssw, ssh;
Evas_GL_Texture *mtex = NULL;
Evas_GL_Texture *mtex = mask ? mask->tex : NULL;
Eina_Bool mask_smooth = EINA_FALSE;
int nx, ny, nw, nh;
nx = dx; ny = dy; nw = dw; nh = dh;
@ -995,18 +1002,36 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
if ((nw < 1) || (nh < 1)) return;
if (!im->tex) return;
if (mask && mask->tex)
if (mtex && mtex->pt && mtex->pt->w && mtex->pt->h)
{
double mx, my, mw, mh;
const double tmw = mtex->pt->w;
const double tmh = mtex->pt->h;
double scalex = 1.0;
double scaley = 1.0;
mx = mask_x; my = mask_y; mw = mask->w; mh = mask->h;
// canvas coords
mx = mask_x; my = mask_y;
if (mask->scaled.origin)
{
mw = mask->scaled.w;
mh = mask->scaled.h;
scalex = mask->w / (double)mask->scaled.w;
scaley = mask->h / (double)mask->scaled.h;
mask_smooth = mask->scaled.smooth;
}
else
{
mw = mask->w;
mh = mask->h;
}
RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch);
RECTS_CLIP_TO_RECT(mx, my, mw, mh, dx, dy, dw, dh);
mmx = mx - mask_x;
mmy = my - mask_y;
mmw = mw;
mmh = mh;
mtex = mask->tex;
// convert to tex coords
mx = (mtex->x / tmw) + ((mx - mask_x) * scalex / tmw);
my = (mtex->y / tmh) + ((my - mask_y) * scaley / tmh);
mw = mw * scalex / tmw;
mh = mh * scaley / tmh;
}
if ((nx == dx) && (ny == dy) && (nw == dw) && (nh == dh))
@ -1016,7 +1041,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
sx, sy, sw, sh,
dx, dy, dw, dh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else if (yuy2)
@ -1024,7 +1049,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
sx, sy, sw, sh,
dx, dy, dw, dh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else if (nv12)
@ -1032,7 +1057,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
sx, sy, sw, sh,
dx, dy, dw, dh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else if (rgb_a_pair)
@ -1040,7 +1065,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
sx, sy, sw, sh,
dx, dy, dw, dh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else
@ -1048,7 +1073,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
sx, sy, sw, sh,
dx, dy, dw, dh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth, im->tex_only);
return;
@ -1064,7 +1089,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else if (yuy2)
@ -1072,7 +1097,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else if (nv12)
@ -1080,7 +1105,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else if (rgb_a_pair)
@ -1088,7 +1113,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth);
else
@ -1096,7 +1121,7 @@ _evas_gl_common_image_push(Evas_Engine_GL_Context *gc, Evas_GL_Image *im,
im->tex,
ssx, ssy, ssw, ssh,
nx, ny, nw, nh,
mtex, mmx, mmy, mmw, mmh,
mtex, mx, my, mw, mh, mask_smooth,
r, g, b, a,
smooth, im->tex_only);
}

View File

@ -272,7 +272,7 @@ evas_gl_common_poly_draw(Evas_Engine_GL_Context *gc, Evas_GL_Polygon *poly, int
h = 1;
evas_gl_common_context_rectangle_push(gc, x, y, w, h,
cr, cg, cb, ca,
NULL, 0, 0, 0, 0);
NULL, 0, 0, 0, 0, EINA_FALSE);
}
}
else
@ -296,7 +296,7 @@ evas_gl_common_poly_draw(Evas_Engine_GL_Context *gc, Evas_GL_Polygon *poly, int
if ((w > 0) && (h > 0))
evas_gl_common_context_rectangle_push(gc, x, y, w, h,
cr, cg, cb, ca,
NULL, 0, 0, 0, 0);
NULL, 0, 0, 0, 0, EINA_FALSE);
}
}
}

View File

@ -6,7 +6,9 @@ evas_gl_common_rect_draw(Evas_Engine_GL_Context *gc, int x, int y, int w, int h)
Cutout_Rect *r;
int c, cx, cy, cw, ch, cr, cg, cb, ca, i;
double mx = 0, my = 0, mw = 0, mh = 0;
Evas_GL_Texture *mtex = NULL;
Eina_Bool mask_smooth = EINA_FALSE;
Evas_GL_Image *mask = gc->dc->clip.mask;
Evas_GL_Texture *mtex = mask ? mask->tex : NULL;
if ((w <= 0) || (h <= 0)) return;
if (!(RECTS_INTERSECT(x, y, w, h, 0, 0, gc->w, gc->h))) return;
@ -28,21 +30,44 @@ evas_gl_common_rect_draw(Evas_Engine_GL_Context *gc, int x, int y, int w, int h)
gc->dc->clip.w, gc->dc->clip.h);
}
if (gc->dc->clip.mask)
if (mtex)
{
Evas_GL_Image *mask = gc->dc->clip.mask;
const double mask_x = gc->dc->clip.mask_x;
const double mask_y = gc->dc->clip.mask_y;
const double tmw = mtex->pt->w;
const double tmh = mtex->pt->h;
double scalex = 1.0;
double scaley = 1.0;
mx = gc->dc->clip.mask_x; mw = mask->w;
my = gc->dc->clip.mask_y; mh = mask->h;
// canvas coords
mx = mask_x; my = mask_y;
if (mask->scaled.origin && mask->scaled.w && mask->scaled.h)
{
mw = mask->scaled.w;
mh = mask->scaled.h;
scalex = mask->w / (double)mask->scaled.w;
scaley = mask->h / (double)mask->scaled.h;
mask_smooth = mask->scaled.smooth;
}
else
{
mw = mask->w;
mh = mask->h;
}
RECTS_CLIP_TO_RECT(mx, my, mw, mh, cx, cy, cw, ch);
mx -= gc->dc->clip.mask_x;
my -= gc->dc->clip.mask_y;
mtex = mask->tex;
// convert to tex coords
mx = (mtex->x / tmw) + ((mx - mask_x) * scalex / tmw);
my = (mtex->y / tmh) + ((my - mask_y) * scaley / tmh);
mw = mw * scalex / tmw;
mh = mh * scaley / tmh;
}
if (!gc->dc->cutout.rects)
{
evas_gl_common_context_rectangle_push(gc, x, y, w, h, cr, cg, cb, ca, mtex, mx, my, mw, mh);
evas_gl_common_context_rectangle_push(gc, x, y, w, h, cr, cg, cb, ca, mtex, mx, my, mw, mh, mask_smooth);
}
else
{
@ -56,7 +81,7 @@ evas_gl_common_rect_draw(Evas_Engine_GL_Context *gc, int x, int y, int w, int h)
r = _evas_gl_common_cutout_rects->rects + i;
if ((r->w > 0) && (r->h > 0))
{
evas_gl_common_context_rectangle_push(gc, r->x, r->y, r->w, r->h, cr, cg, cb, ca, mtex, mx, my, mw, mh);
evas_gl_common_context_rectangle_push(gc, r->x, r->y, r->w, r->h, cr, cg, cb, ca, mtex, mx, my, mw, mh, mask_smooth);
}
}
evas_common_draw_context_cutouts_free(_evas_gl_common_cutout_rects);

View File

@ -950,6 +950,57 @@ eng_image_map_surface_free(void *data, void *surface)
evas_gl_common_image_free(surface);
}
static void *
eng_image_scaled_update(void *data EINA_UNUSED, void *scaled, void *image,
int dst_w, int dst_h,
Eina_Bool smooth, Eina_Bool alpha,
Evas_Colorspace cspace EINA_UNUSED)
{
Evas_GL_Image *dst = scaled;
Evas_GL_Image *src = image;
Evas_Engine_GL_Context *gc;
if (!src) return NULL;
gc = src->gc;
if ((dst_w > gc->shared->info.max_texture_size) ||
(dst_h > gc->shared->info.max_texture_size))
return NULL;
if (dst && (dst->scaled.origin == src) &&
(dst->scaled.w == dst_w) && (dst->scaled.h == dst_h))
return dst;
if (dst) evas_gl_common_image_free(dst);
evas_gl_common_image_update(gc, src);
if (!src->tex)
{
ERR("No source texture.");
return NULL;
}
dst = calloc(1, sizeof(Evas_GL_Image));
if (!dst) return NULL;
dst->references = 1;
dst->gc = gc;
dst->cs.space = src->cs.space;
dst->alpha = alpha;
dst->w = src->w;
dst->h = src->h;
dst->tex = src->tex;
dst->tex->references++;
dst->tex_only = 1;
src->references++;
dst->scaled.origin = src;
dst->scaled.w = dst_w;
dst->scaled.h = dst_h;
dst->scaled.smooth = smooth;
return dst;
}
static void
eng_image_content_hint_set(void *data, void *image, int hint)
{
@ -2016,6 +2067,7 @@ module_open(Evas_Module *em)
ORD(image_map_surface_new);
ORD(image_map_surface_free);
ORD(image_map_clean);
ORD(image_scaled_update);
ORD(image_content_hint_set);
ORD(image_content_hint_get);

View File

@ -3545,6 +3545,7 @@ static Evas_Func func =
eng_image_map_surface_new,
eng_image_map_surface_free,
eng_image_map_clean,
NULL, // eng_image_scaled_get - used for live scaling in GL only (fastpath)
NULL, // eng_image_content_hint_set - software doesn't use it
NULL, // eng_image_content_hint_get - software doesn't use it
eng_font_pen_coords_get,