From: Jean-Philippe Andre Date: Wed, 22 Mar 2017 11:51:53 +0000 (+0900) Subject: evas: Fix excessive redraws of snapshot objects X-Git-Tag: upstream/1.20.0~1520 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b6c5af5edcd268a6da5c82762faf8815d729b064;p=platform%2Fupstream%2Fefl.git evas: Fix excessive redraws of snapshot objects --- diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c index fab03ba..d2c17b2 100644 --- a/src/lib/evas/canvas/evas_filter_mixin.c +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -263,12 +263,15 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, } else if (previous && !pd->data->changed) { - Eina_Bool redraw = EINA_TRUE; + Eina_Bool redraw; - if (_evas_filter_state_set_internal(pd->data->chain, pd)) + redraw = _evas_filter_state_set_internal(pd->data->chain, pd); + if (redraw) DBG("Filter redraw by state change!"); else if (obj->changed) DBG("Filter redraw by object content change!"); + else if (obj->snapshot_needs_redraw) + DBG("Filter redraw by snapshot change!"); else if (_evas_filter_obscured_region_changed(pd)) DBG("Filter redraw by obscure regions change!"); else redraw = EINA_FALSE; diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index 61d8fd2..cd63a63 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -100,12 +100,19 @@ rend_dbg(const char *txt) #define ENDT evas->engine.data.output typedef struct _Render_Updates Render_Updates; +typedef struct _Cutout_Margin Cutout_Margin; + struct _Render_Updates { void *surface; Eina_Rectangle *area; }; +struct _Cutout_Margin +{ + int l, r, t, b; +}; + static Eina_Bool evas_render_updates_internal(Evas *eo_e, unsigned char make_updates, unsigned char do_draw, Evas_Render_Done_Cb done_func, void *done_data, Eina_Bool do_async); @@ -2615,7 +2622,7 @@ end: static void _evas_render_cutout_add(Evas_Public_Data *evas, void *context, Evas_Object_Protected_Data *obj, int off_x, int off_y, - int cutout_margin) + Cutout_Margin *cutout_margin) { Evas_Coord cox = 0, coy = 0, cow = 0, coh = 0; @@ -2630,8 +2637,7 @@ _evas_render_cutout_add(Evas_Public_Data *evas, void *context, { Evas_Object_Protected_Data *oo; - oo = obj; - while (oo->cur->clipper) + for (oo = obj; oo->cur->clipper; oo = oo->cur->clipper) { if ((oo->cur->clipper->map->cur.map_parent != oo->map->cur.map_parent) && @@ -2642,7 +2648,7 @@ _evas_render_cutout_add(Evas_Public_Data *evas, void *context, oo->cur->geometry.y, oo->cur->geometry.w, oo->cur->geometry.h); - oo = oo->cur->clipper; + if ((cow <= 0) || (coh <= 0)) return; } } } @@ -2655,12 +2661,15 @@ _evas_render_cutout_add(Evas_Public_Data *evas, void *context, obj->cur->cache.clip.w, obj->cur->cache.clip.h); } else return; - cox += cutout_margin + off_x; - coy += cutout_margin + off_y; - cow -= 2 * cutout_margin; - coh -= 2 * cutout_margin; + if (cutout_margin) + { + cox += cutout_margin->l; + coy += cutout_margin->t; + cow -= cutout_margin->l + cutout_margin->r; + coh -= cutout_margin->t + cutout_margin->b; + } if ((cow <= 0) || (coh <= 0)) return; - ENFN->context_cutout_add(ENDT, context, cox, coy, cow, coh); + ENFN->context_cutout_add(ENDT, context, cox + off_x, coy + off_y, cow, coh); } void @@ -2750,11 +2759,10 @@ _rectangle_inside(Eina_Rectangle *big, Eina_Rectangle *small) return EINA_FALSE; } -static Eina_Bool -_snapshot_needs_redraw(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap, - Eina_Rectangle *opaque) +static void +_snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap) { - Eina_Bool above = EINA_FALSE, ret = EINA_FALSE; + Eina_Bool above = EINA_FALSE, add_rect = EINA_FALSE, need_redraw = EINA_FALSE; const int x = snap->cur->geometry.x; const int y = snap->cur->geometry.y; const int w = snap->cur->geometry.w; @@ -2762,27 +2770,35 @@ _snapshot_needs_redraw(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap, Evas_Object_Protected_Data *obj; Evas_Active_Entry *ent; Eina_Rectangle snap_rect = { x, y, w, h }; + Eina_Rectangle opaque = {}; void *surface; + // FIXME: Use evas' standard rectangle logic instead of this bad algo + // TODO: Improve opaque region support, maybe have more than one + // TODO: Also list redraw regions (partial updates) + + if (!evas_object_is_visible(snap->object, snap)) return; + surface = _evas_object_image_surface_get(snap, EINA_FALSE); - if (!surface) ret = EINA_TRUE; + if (!surface) need_redraw = EINA_TRUE; + if (snap->changed) add_rect = EINA_TRUE; - memset(opaque, 0, sizeof(*opaque)); EINA_INARRAY_FOREACH(&evas->active_objects, ent) { obj = ent->obj; if (obj == snap) { + if (!need_redraw) break; above = EINA_TRUE; continue; } if (!above) { - if (ret) continue; + if (add_rect) continue; if (!obj->is_smart && obj->changed && evas_object_is_in_output_rect(obj->object, obj, x, y, w, h)) - ret = EINA_TRUE; + need_redraw = EINA_TRUE; } else { @@ -2794,22 +2810,37 @@ _snapshot_needs_redraw(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap, obj->cur->geometry.w, obj->cur->geometry.h }; + if ((opaque.w * opaque.h) < (cur.w * cur.h)) + { + opaque = cur; + continue; + } + if (!eina_rectangles_intersect(&snap_rect, &cur)) continue; - if (!opaque->w || !opaque->h) - *opaque = cur; - else if (_rectangle_inside(&cur, opaque)) - *opaque = cur; - else if (!_rectangle_inside(opaque, &cur)) - { - *opaque = (Eina_Rectangle) { 0, 0, 0, 0 }; - break; - } + if (!opaque.w || !opaque.h) + opaque = cur; + else if (_rectangle_inside(&cur, &opaque)) + opaque = cur; + //else if (!_rectangle_inside(&opaque, &cur)) } } } - return ret; + + _evas_filter_obscured_region_set(snap, opaque); + snap->snapshot_needs_redraw |= need_redraw; + + if (add_rect || need_redraw) + { + // FIXME: Only add necessary rects + // Note that with filters this is extremely tricky: a simple color + // change would mean redraw all. Also blurs, displace, etc... need + // to expand by the cutout_margin (filter padding). + ENFN->output_redraws_rect_add(ENDT, + snap->cur->geometry.x, snap->cur->geometry.y, + snap->cur->geometry.w, snap->cur->geometry.h); + } } static Eina_Bool @@ -2818,9 +2849,9 @@ evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *evas, Evas_Object_Protected_Data *top, int ux, int uy, int uw, int uh, int cx, int cy, int cw, int ch, - int fx, int fy, int cutout_margin, - Eina_Bool alpha, - Eina_Bool do_async, + int fx, int fy, + Cutout_Margin *cutout_margin, + Eina_Bool alpha, Eina_Bool do_async, unsigned int *offset, int level) { Evas_Object *eo_obj; @@ -3165,11 +3196,7 @@ evas_render_updates_internal(Evas *eo_e, for (i = 0; i < e->snapshot_objects.count; i++) { obj = eina_array_data_get(&e->snapshot_objects, i); - - if (evas_object_is_visible(obj->object, obj)) - ENFN->output_redraws_rect_add(ENDT, - obj->cur->geometry.x, obj->cur->geometry.y, - obj->cur->geometry.w, obj->cur->geometry.h); + _snapshot_redraw_update(evas, obj); } } eina_evlog("-render_phase4", eo_e, 0.0, NULL); @@ -3246,21 +3273,22 @@ evas_render_updates_internal(Evas *eo_e, eina_evlog("+render_snapshots", eo_e, 0.0, NULL); for (j = e->snapshot_objects.count - 1; j >= 0; j--) { - Eina_Rectangle output, cr, ur, opaque; + Evas_Object_Protected_Data *snap; + Eina_Rectangle output, cr, ur; - obj = eina_array_data_get(&e->snapshot_objects, j); + snap = eina_array_data_get(&e->snapshot_objects, j); EINA_RECTANGLE_SET(&output, - obj->cur->geometry.x, - obj->cur->geometry.y, - obj->cur->geometry.w, - obj->cur->geometry.h); + snap->cur->geometry.x, + snap->cur->geometry.y, + snap->cur->geometry.w, + snap->cur->geometry.h); EINA_RECTANGLE_SET(&ur, ux, uy, uw, uh); - if (eina_rectangle_intersection(&ur, &output) && - _snapshot_needs_redraw(evas, obj, &opaque)) + if (snap->snapshot_needs_redraw && + eina_rectangle_intersection(&ur, &output)) { - int cutout_margin, fpl = 0, fpr = 0, fpt = 0, fpb = 0; + Cutout_Margin cm = {}; unsigned int restore_offset = offset; void *pseudo_canvas; @@ -3268,31 +3296,22 @@ evas_render_updates_internal(Evas *eo_e, ur.x - output.x, ur.y - output.y, ur.w, ur.h); - pseudo_canvas = _evas_object_image_surface_get(obj, EINA_TRUE); + pseudo_canvas = _evas_object_image_surface_get(snap, EINA_TRUE); - // TODO: List of canvas regions that need redraw // Get required margin for filters (eg. blur radius) - _evas_filter_radius_get(obj, &fpl, &fpr, &fpt, &fpb); - cutout_margin = MAX(MAX(MAX(fpl, fpr), fpt), fpb); + _evas_filter_radius_get(snap, &cm.l, &cm.r, &cm.t, &cm.b); - // Add obscure region (make it a list?) - _evas_filter_obscured_region_set(obj, opaque); - - RD(0, " SNAPSHOT %s [sfc:%p ur:%d,%d %dx%d]\n", RDNAME(obj), pseudo_canvas, ur.x, ur.y, ur.w, ur.h); + RD(0, " SNAPSHOT %s [sfc:%p ur:%d,%d %dx%d]\n", RDNAME(snap), pseudo_canvas, ur.x, ur.y, ur.w, ur.h); ctx = ENFN->context_new(ENDT); clean_them |= evas_render_updates_internal_loop(eo_e, e, pseudo_canvas, ctx, - obj, + snap, ur.x, ur.y, ur.w, ur.h, cr.x, cr.y, cr.w, cr.h, - fx, fy, cutout_margin, alpha, - do_async, + fx, fy, &cm, + alpha, do_async, &offset, 1); ENFN->context_free(ENDT, ctx); - // Force the object has changed for filter to take it into - // account. It won't be in the pending object array. - obj->changed = EINA_TRUE; - offset = restore_offset; // FIXME: For some reason the arrays are not cleaned and @@ -3321,8 +3340,8 @@ evas_render_updates_internal(Evas *eo_e, ctx, NULL, ux, uy, uw, uh, cx, cy, cw, ch, - fx, fy, 0, alpha, - do_async, + fx, fy, NULL, + alpha, do_async, &offset, 0); ENFN->context_free(ENDT, ctx); @@ -3399,6 +3418,13 @@ evas_render_updates_internal(Evas *eo_e, else if (obj->delete_me != 0) obj->delete_me++; */ } + for (i = 0; i < e->snapshot_objects.count; i++) + { + Evas_Object_Protected_Data *snap; + + snap = eina_array_data_get(&e->snapshot_objects, i); + snap->snapshot_needs_redraw = EINA_FALSE; + } eina_evlog("-render_post", eo_e, 0.0, NULL); IFRD(e->active_objects.len, 0, " ---]\n"); diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 6a0c776..1cf58e2 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -1220,6 +1220,7 @@ struct _Evas_Object_Protected_Data Eina_Bool no_render : 1; // since 1.15 Eina_Bool legacy : 1; // used legacy constructor Eina_Bool clean_layer : 1; // destructor option + Eina_Bool snapshot_needs_redraw : 1; struct { Eina_Bool pass_events : 1;