From 8286a56279242bb0418ace7d37b225621b5e5c40 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Fri, 25 Aug 2017 10:55:15 -0700 Subject: [PATCH] evas: enable rendering of multiple output. --- src/lib/evas/canvas/evas_render.c | 382 +++++++++++++++++++------------------- 1 file changed, 196 insertions(+), 186 deletions(-) diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index 1d42b8c..16895ad 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -3088,11 +3088,17 @@ evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *evas, return clean_them; } -static Efl_Canvas_Output * -_evas_overlay_output_find(Evas_Public_Data *e, Evas_Object_Protected_Data *obj) +typedef enum _Evas_3State +{ + EVAS_3STATE_OUTSIDE, + EVAS_3STATE_INSIDE, + EVAS_3STATE_OVER +} Evas_3State; + +static Evas_3State +_evas_overlay_output_find(Efl_Canvas_Output *output, + Evas_Object_Protected_Data *obj) { - Efl_Canvas_Output *output; - Eina_List *lo; const Eina_Rectangle geometry = { obj->cur->geometry.x, obj->cur->geometry.y, @@ -3102,23 +3108,14 @@ _evas_overlay_output_find(Evas_Public_Data *e, Evas_Object_Protected_Data *obj) Eina_Rectangle copy = geometry; /* A video object can only be in one output at a time, check that first */ - EINA_LIST_FOREACH(e->outputs, lo, output) - { - if (!eina_rectangle_intersection(©, &output->geometry)) - { - copy = geometry; - continue ; - } - if (memcmp(©, &geometry, sizeof (Eina_Rectangle)) != 0) - { - /* This means that it does intersect this output and another */ - return NULL; - } + if (!eina_rectangle_intersection(©, &output->geometry)) + return EVAS_3STATE_OUTSIDE; - return output; - } + if (memcmp(©, &geometry, sizeof (Eina_Rectangle)) != 0) + /* This means that it does intersect this output and another */ + return EVAS_3STATE_OVER; - return NULL; + return EVAS_3STATE_INSIDE; } static Eina_Bool @@ -3132,7 +3129,7 @@ evas_render_updates_internal(Evas *eo_e, Evas_Object_Protected_Data *obj; Evas_Public_Data *evas, *e; Efl_Canvas_Output *out; - Eina_List *ll; + Eina_List *ll, *l; Eina_Bool clean_them = EINA_FALSE; Eina_Bool rendering = EINA_FALSE; Eina_Bool alpha; @@ -3144,6 +3141,7 @@ evas_render_updates_internal(Evas *eo_e, Evas_Render_Mode render_mode = !do_async ? EVAS_RENDER_MODE_SYNC : EVAS_RENDER_MODE_ASYNC_INIT; + Eina_Bool haveup = EINA_FALSE; MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS); return EINA_FALSE; @@ -3317,195 +3315,206 @@ evas_render_updates_internal(Evas *eo_e, } eina_evlog("-render_phase5", eo_e, 0.0, NULL); - /* phase 6. Initialize output */ - out = eina_list_data_get(e->outputs); - if (out->changed) + EINA_LIST_FOREACH(e->outputs, l, out) { - ENFN->output_resize(ENC, out->output, - out->geometry.w, out->geometry.h); - ENFN->output_redraws_rect_add(ENC, - out->geometry.x, out->geometry.y, - out->geometry.w, out->geometry.h); - out->changed = EINA_FALSE; - } + /* phase 6. Initialize output */ + if (out->changed) + { + ENFN->output_resize(ENC, out->output, + out->geometry.w, out->geometry.h); + ENFN->output_redraws_rect_add(ENC, + out->geometry.x, out->geometry.y, + out->geometry.w, out->geometry.h); + out->changed = EINA_FALSE; + } - /* Define the output for Evas_GL operation */ - if (ENFN->gl_output_set) - ENFN->gl_output_set(ENC, out->output); + /* Define the output for Evas_GL operation */ + if (ENFN->gl_output_set) + ENFN->gl_output_set(ENC, out->output); - /* phase 7. check if video surface should be inlined or stay in their hardware plane */ - eina_evlog("+render_phase7", eo_e, 0.0, NULL); - alpha = ENFN->canvas_alpha_get(out->output); + /* phase 7. check if video surface should be inlined or stay in their hardware plane */ + eina_evlog("+render_phase7", eo_e, 0.0, NULL); + alpha = ENFN->canvas_alpha_get(out->output); - EINA_LIST_FOREACH(e->video_objects, ll, eo_obj) - { - Efl_Canvas_Output *output; - Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + EINA_LIST_FOREACH(e->video_objects, ll, eo_obj) + { + Evas_Object_Protected_Data *obj; + Evas_3State state; - output = _evas_overlay_output_find(e, obj); + obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + state = _evas_overlay_output_find(out, obj); + if (state == EVAS_3STATE_OUTSIDE) continue; - /* we need the surface to be transparent to display the underlying overlay */ - if (output && alpha && _evas_render_can_use_overlay(e, eo_obj, output)) - _evas_object_image_video_overlay_show(eo_obj); - else - _evas_object_image_video_overlay_hide(eo_obj); - } + /* we need the surface to be transparent to display the underlying overlay */ + if (state == EVAS_3STATE_INSIDE && + alpha && + _evas_render_can_use_overlay(e, eo_obj, out)) + _evas_object_image_video_overlay_show(eo_obj); + else + _evas_object_image_video_overlay_hide(eo_obj); + } - /* check if individual image objects can be dropped into hardware planes */ - if (ENFN->image_plane_assign) - EINA_INARRAY_FOREACH(&evas->active_objects, ao) - { - Evas_Object_Protected_Data *obj2; - Evas_Object *eo_obj2; - Efl_Canvas_Output *output; - Eina_List *lo; + /* check if individual image objects can be dropped into hardware planes */ + if (ENFN->image_plane_assign) + EINA_INARRAY_FOREACH(&evas->active_objects, ao) + { + Evas_Object_Protected_Data *obj2; + Evas_Object *eo_obj2; + Efl_Canvas_Output *output; + Evas_3State state; + Eina_List *lo; - obj2 = ao->obj; - eo_obj2 = obj2->object; + obj2 = ao->obj; + eo_obj2 = obj2->object; - if (!efl_isa(eo_obj2, EFL_CANVAS_IMAGE_INTERNAL_CLASS)) continue; + if (!efl_isa(eo_obj2, EFL_CANVAS_IMAGE_INTERNAL_CLASS)) continue; - if (evas_object_image_video_surface_get(eo_obj2)) continue; + if (evas_object_image_video_surface_get(eo_obj2)) continue; - /* Find the output the object was in */ - EINA_LIST_FOREACH(e->outputs, lo, output) - { - if (!eina_list_data_find(output->planes, obj2)) continue ; - _evas_object_image_plane_release(eo_obj2, obj2, output); - break; - } + /* Find the output the object was in */ + EINA_LIST_FOREACH(e->outputs, lo, output) + { + if (!eina_list_data_find(output->planes, obj2)) continue ; + _evas_object_image_plane_release(eo_obj2, obj2, output); + break; + } - /* A video object can only be in one output at a time, check that first */ - output = _evas_overlay_output_find(e, obj2); - if (!output) continue ; + /* A video object can only be in one output at a time, check that first */ + state = _evas_overlay_output_find(out, obj2); + if (state == EVAS_3STATE_OUTSIDE) continue ; - if (!_evas_render_can_use_overlay(e, eo_obj2, output)) - { - /* This may free up things temporarily allocated by - * _can_use_overlay() testing in the engine */ - _evas_object_image_plane_release(eo_obj2, obj2, output); + if (!_evas_render_can_use_overlay(e, eo_obj2, out)) + { + /* This may free up things temporarily allocated by + * _can_use_overlay() testing in the engine */ + _evas_object_image_plane_release(eo_obj2, obj2, out); + } } - } - eina_evlog("-render_phase7", eo_e, 0.0, NULL); + eina_evlog("-render_phase7", eo_e, 0.0, NULL); - /* phase 8. go thru each update rect and render objects in it*/ - eina_evlog("+render_phase8", eo_e, 0.0, NULL); - if (do_draw) - { - Render_Updates *ru; - void *surface; - int ux, uy, uw, uh; - int cx, cy, cw, ch; - unsigned int offset = 0; - int fx = e->framespace.x; - int fy = e->framespace.y; - int j; - Eina_Bool haveup = EINA_FALSE; - - if (do_async) _evas_render_busy_begin(); - eina_evlog("+render_surface", eo_e, 0.0, NULL); - // FIXME: handle multiple output - while ((surface = - ENFN->output_redraws_next_update_get - (ENC, out->output, - &ux, &uy, &uw, &uh, - &cx, &cy, &cw, &ch))) + /* phase 8. go thru each update rect and render objects in it*/ + eina_evlog("+render_phase8", eo_e, 0.0, NULL); + if (do_draw) { - void *ctx; + Render_Updates *ru; + void *surface; + int ux, uy, uw, uh; + int cx, cy, cw, ch; + unsigned int offset = 0; + int fx = e->framespace.x; + int fy = e->framespace.y; + int j; + + if (do_async) _evas_render_busy_begin(); + eina_evlog("+render_surface", eo_e, 0.0, NULL); + while ((surface = + ENFN->output_redraws_next_update_get + (ENC, out->output, + &ux, &uy, &uw, &uh, + &cx, &cy, &cw, &ch))) + { + void *ctx; - haveup = EINA_TRUE; + haveup = EINA_TRUE; - /* phase 7.1 render every snapshot that needs to be updated - for this part of the screen */ - eina_evlog("+render_snapshots", eo_e, 0.0, NULL); - for (j = e->snapshot_objects.count - 1; j >= 0; j--) - { - Evas_Object_Protected_Data *snap; - Eina_Rectangle output, cr, ur; - - snap = eina_array_data_get(&e->snapshot_objects, j); - - EINA_RECTANGLE_SET(&output, - snap->cur->geometry.x, - snap->cur->geometry.y, - snap->cur->geometry.w, - snap->cur->geometry.h); - EINA_RECTANGLE_SET(&ur, ux, uy, uw, uh); - - // FIXME: We should render snapshots only once per frame, - // not once per update region! - if (snap->snapshot_needs_redraw && - eina_rectangle_intersection(&ur, &output)) + /* phase 7.1 render every snapshot that needs to be updated + for this part of the screen */ + eina_evlog("+render_snapshots", eo_e, 0.0, NULL); + for (j = e->snapshot_objects.count - 1; j >= 0; j--) { - Cutout_Margin cm = {}; - unsigned int restore_offset = offset; - Eina_Bool skip_cutouts = EINA_FALSE; - void *pseudo_canvas; - - EINA_RECTANGLE_SET(&cr, - ur.x - output.x, ur.y - output.y, - ur.w, ur.h); - - pseudo_canvas = _evas_object_image_surface_get(snap, EINA_TRUE); - - // Get required margin for filters (eg. blur radius) - _evas_filter_radius_get(snap, &cm.l, &cm.r, &cm.t, &cm.b); - - if (snap->map->cur.usemap || snap->proxy->proxies || - snap->snapshot_no_obscure || - ((cm.l + cm.r) >= output.w) || - ((cm.t + cm.b) >= output.h)) - skip_cutouts = EINA_TRUE; - - 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(ENC); - clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, pseudo_canvas, ctx, - snap, - ur.x, ur.y, ur.w, ur.h, - cr.x, cr.y, cr.w, cr.h, - fx, fy, skip_cutouts, &cm, - alpha, do_async, - &offset, 1); - ENFN->context_free(ENC, ctx); - - offset = restore_offset; + Evas_Object_Protected_Data *snap; + Eina_Rectangle output, cr, ur; + + snap = eina_array_data_get(&e->snapshot_objects, j); + + EINA_RECTANGLE_SET(&output, + snap->cur->geometry.x, + snap->cur->geometry.y, + snap->cur->geometry.w, + snap->cur->geometry.h); + EINA_RECTANGLE_SET(&ur, ux, uy, uw, uh); + + // FIXME: We should render snapshots only once per frame, + // not once per update region per output ! + if (snap->snapshot_needs_redraw && + eina_rectangle_intersection(&ur, &output)) + { + Cutout_Margin cm = {}; + unsigned int restore_offset = offset; + Eina_Bool skip_cutouts = EINA_FALSE; + void *pseudo_canvas; + + EINA_RECTANGLE_SET(&cr, + ur.x - output.x, ur.y - output.y, + ur.w, ur.h); + + pseudo_canvas = _evas_object_image_surface_get(snap, EINA_TRUE); + + // Get required margin for filters (eg. blur radius) + _evas_filter_radius_get(snap, &cm.l, &cm.r, &cm.t, &cm.b); + + if (snap->map->cur.usemap || snap->proxy->proxies || + snap->snapshot_no_obscure || + ((cm.l + cm.r) >= output.w) || + ((cm.t + cm.b) >= output.h)) + skip_cutouts = EINA_TRUE; + + 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(ENC); + clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, pseudo_canvas, ctx, + snap, + ur.x, ur.y, ur.w, ur.h, + cr.x, cr.y, cr.w, cr.h, + fx, fy, skip_cutouts, &cm, + alpha, do_async, + &offset, 1); + ENFN->context_free(ENC, ctx); + + offset = restore_offset; + } } - } - eina_evlog("-render_snapshots", eo_e, 0.0, NULL); + eina_evlog("-render_snapshots", eo_e, 0.0, NULL); - eina_evlog("+render_update", eo_e, 0.0, NULL); - /* phase 7.2 render all the object on the target surface */ - if ((do_async) || (make_updates)) - { - ru = malloc(sizeof(*ru)); - ru->surface = surface; - //XXX: need a way of reffing output surfaces - NEW_RECT(ru->area, ux, uy, uw, uh); - eina_spinlock_take(&(e->render.lock)); - out->updates = eina_list_append(out->updates, ru); - eina_spinlock_release(&(e->render.lock)); - } + eina_evlog("+render_update", eo_e, 0.0, NULL); + /* phase 7.2 render all the object on the target surface */ + if ((do_async) || (make_updates)) + { + ru = malloc(sizeof(*ru)); + ru->surface = surface; + //XXX: need a way of reffing output surfaces + NEW_RECT(ru->area, ux, uy, uw, uh); + eina_spinlock_take(&(e->render.lock)); + out->updates = eina_list_append(out->updates, ru); + eina_spinlock_release(&(e->render.lock)); + } - ctx = ENFN->context_new(ENC); - clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, surface, - ctx, NULL, - ux, uy, uw, uh, - cx, cy, cw, ch, - fx, fy, - EINA_FALSE, NULL, - alpha, do_async, - &offset, 0); - ENFN->context_free(ENC, ctx); + ctx = ENFN->context_new(ENC); + clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, surface, + ctx, NULL, + ux, uy, uw, uh, + cx, cy, cw, ch, + fx, fy, + EINA_FALSE, NULL, + alpha, do_async, + &offset, 0); + ENFN->context_free(ENC, ctx); - eina_evlog("-render_update", eo_e, 0.0, NULL); - if (!do_async) - { - eina_evlog("+render_push", eo_e, 0.0, NULL); - ENFN->output_redraws_next_update_push(ENC, out->output, surface, ux, uy, uw, uh, render_mode); - eina_evlog("-render_push", eo_e, 0.0, NULL); + eina_evlog("-render_update", eo_e, 0.0, NULL); + if (!do_async) + { + eina_evlog("+render_push", eo_e, 0.0, NULL); + ENFN->output_redraws_next_update_push(ENC, out->output, surface, ux, uy, uw, uh, render_mode); + eina_evlog("-render_push", eo_e, 0.0, NULL); + } } + + eina_evlog("-render_surface", eo_e, 0.0, NULL); } + } + /* First process all output, then flush */ + if (do_draw) + { if (haveup) { if (do_async) @@ -3526,13 +3535,13 @@ evas_render_updates_internal(Evas *eo_e, _evas_object_image_video_overlay_do(eo_obj); } _cb_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL); - ENFN->output_flush(ENC, out->output, EVAS_RENDER_MODE_SYNC); + EINA_LIST_FOREACH(e->outputs, l, out) + ENFN->output_flush(ENC, out->output, EVAS_RENDER_MODE_SYNC); _cb_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL); eina_evlog("-render_output_flush", eo_e, 0.0, NULL); } } rendering = haveup; - eina_evlog("-render_surface", eo_e, 0.0, NULL); } eina_evlog("-render_phase8", eo_e, 0.0, NULL); @@ -3540,7 +3549,8 @@ evas_render_updates_internal(Evas *eo_e, if (!do_async && rendering) { /* clear redraws */ - ENFN->output_redraws_clear(ENC, out->output); + EINA_LIST_FOREACH(e->outputs, l, out) + ENFN->output_redraws_clear(ENC, out->output); } eina_evlog("-render_clear", eo_e, 0.0, NULL); -- 2.7.4