Bool visual_2d_terminate_draw(GF_VisualManager *visual, GF_TraverseState *tr_state) { u32 k, i, count, num_nodes, num_changed; GF_IRect refreshRect; Bool redraw_all; Bool hyb_force_redraw=GF_FALSE; #ifndef GPAC_DISABLE_VRML M_Background2D *bck = NULL; DrawableContext *bck_ctx = NULL; #endif DrawableContext *ctx; struct _drawable_store *it, *prev; DrawableContext *first_opaque = NULL; Bool has_clear = 0; Bool has_changed = 0; Bool redraw_all_on_background_change = GF_TRUE; /*in direct mode the visual is always redrawn*/ if (tr_state->immediate_draw) { /*flush pending contexts due to overlays*/ visual_2d_flush_overlay_areas(visual, tr_state); visual_2d_release_raster(visual); visual_clean_contexts(visual); visual->num_nodes_prev_frame = visual->num_nodes_current_frame; return 1; } num_changed = 0; /*if the aspect ratio has changed redraw everything*/ redraw_all = tr_state->invalidate_all; #ifndef GPAC_DISABLE_3D if (visual->compositor->hybrid_opengl && !visual->offscreen) redraw_all_on_background_change = GF_FALSE; #endif /*check for background changes for transparent nodes*/ #ifndef GPAC_DISABLE_VRML bck = (M_Background2D*)gf_list_get(visual->back_stack, 0); if (bck) { if (!bck->isBound) { if (visual->last_had_back) { if (redraw_all_on_background_change) redraw_all = 1; else hyb_force_redraw = 1; } visual->last_had_back = 0; } else { bck_ctx = b2d_get_context(bck, visual->back_stack); if (!visual->last_had_back || (bck_ctx->flags & CTX_REDRAW_MASK) ) { if (redraw_all_on_background_change) redraw_all = 1; else hyb_force_redraw = 1; } visual->last_had_back = (bck_ctx->aspect.fill_texture && !bck_ctx->aspect.fill_texture->transparent) ? 2 : 1; } } else #endif if (visual->last_had_back) { visual->last_had_back = 0; if (redraw_all_on_background_change) redraw_all = 1; else hyb_force_redraw = 1; } num_nodes = 0; ctx = visual->context; while (ctx && ctx->drawable) { num_nodes++; drawctx_update_info(ctx, visual); if (!redraw_all) { u32 res; assert( gf_irect_inside(&visual->top_clipper, &ctx->bi->clip) ); res = register_context_rect(&visual->to_redraw, ctx, num_nodes, &first_opaque); if (res) { num_changed ++; if (res==2) hyb_force_redraw=GF_TRUE; } } ctx = ctx->next; } /*garbage collection*/ /*clear all remaining bounds since last frames (the ones that moved or that are not drawn this frame)*/ prev = NULL; it = visual->prev_nodes; while (it) { while (drawable_get_previous_bound(it->drawable, &refreshRect, visual)) { if (!redraw_all) { //assert( gf_irect_inside(&visual->top_clipper, &refreshRect) ); gf_irect_intersect(&refreshRect, &visual->top_clipper); register_dirty_rect(&visual->to_redraw, &refreshRect); has_clear=1; } } /*if node is marked as undrawn, remove from visual*/ if (!(it->drawable->flags & DRAWABLE_DRAWN_ON_VISUAL)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Node %s no longer on visual - unregistering it\n", gf_node_get_class_name(it->drawable->node))); /*remove all bounds info related to this visual and unreg node */ drawable_reset_bounds(it->drawable, visual); it->drawable->flags &= ~DRAWABLE_REGISTERED_WITH_VISUAL; if (it->drawable->flags & DRAWABLE_IS_OVERLAY) { visual->compositor->video_out->Blit(visual->compositor->video_out, NULL, NULL, NULL, 1); } if (prev) prev->next = it->next; else visual->prev_nodes = it->next; if (!it->next) visual->last_prev_entry = prev; gf_free(it); it = prev ? prev->next : visual->prev_nodes; } else { prev = it; it = it->next; } } if (redraw_all) { ra_clear(&visual->to_redraw); ra_add(&visual->to_redraw, &visual->surf_rect); #ifdef TRACK_OPAQUE_REGIONS visual->to_redraw.list[0].opaque_node_index=0; #endif } else { ra_refresh(&visual->to_redraw); if (visual->compositor->debug_defer) { visual->ClearSurface(visual, &visual->top_clipper, 0); } } /*nothing to redraw*/ if (!hyb_force_redraw && ra_is_empty(&visual->to_redraw) ) { #ifndef GPAC_DISABLE_3D //force canvas draw visual->nb_objects_on_canvas_since_last_ogl_flush = 1; #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] No changes found since last frame - skipping redraw\n")); goto exit; } has_changed = 1; tr_state->traversing_mode = TRAVERSE_DRAW_2D; if (first_opaque && (visual->to_redraw.count==1) && gf_rect_equal(first_opaque->bi->clip, visual->to_redraw.list[0].rect)) { visual->has_modif=0; goto skip_background; } /*redraw everything*/ #ifndef GPAC_DISABLE_VRML if (bck_ctx) { drawable_check_bounds(bck_ctx, visual); tr_state->ctx = bck_ctx; visual->draw_node_index = 0; /*force clearing entire zone, not just viewport, when using color. If texture, we MUST use the VP clipper in order to compute offsets when blitting bitmaps*/ if (bck_ctx->aspect.fill_texture && bck_ctx->aspect.fill_texture->stream) { bck_ctx->bi->clip = visual->top_clipper; } else { bck_ctx->bi->clip = visual->surf_rect; } bck_ctx->bi->unclip = gf_rect_ft(&bck_ctx->bi->clip); bck_ctx->next = visual->context; bck_ctx->flags |= CTX_BACKROUND_NOT_LAYER; gf_node_traverse(bck_ctx->drawable->node, tr_state); bck_ctx->flags &= ~CTX_BACKROUND_NOT_LAYER; } else #endif /*GPAC_DISABLE_VRML*/ { count = visual->to_redraw.count; for (k=0; k<count; k++) { GF_IRect rc; /*opaque area, skip*/ #ifdef TRACK_OPAQUE_REGIONS if (visual->to_redraw.list[k].opaque_node_index > 0) continue; #endif rc = visual->to_redraw.list[k].rect; visual->ClearSurface(visual, &rc, 0); } #ifndef GPAC_DISABLE_3D if (!count && hyb_force_redraw) { compositor_2d_hybgl_clear_surface_ex(tr_state->visual, NULL, 0, GF_FALSE); } #endif } if (!redraw_all && !has_clear) visual->has_modif=0; skip_background: #ifndef GPAC_DISABLE_LOG if (gf_log_tool_level_on(GF_LOG_COMPOSE, GF_LOG_INFO)) { GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Visual2D] Redraw %d / %d nodes (all: %s - %d dirty rects\n)", num_changed, num_nodes, redraw_all ? "yes" : "no", visual->to_redraw.count)); if (visual->to_redraw.count>1) GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("\n")); for (i=0; i<visual->to_redraw.count; i++) { GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("\tDirtyRect #%d: %d:%d@%dx%d\n", i+1, visual->to_redraw.list[i].rect.x, visual->to_redraw.list[i].rect.y, visual->to_redraw.list[i].rect.width, visual->to_redraw.list[i].rect.height)); assert(visual->to_redraw.list[i].rect.width); } } #endif visual->draw_node_index = 0; ctx = visual->context; while (ctx && ctx->drawable) { visual->draw_node_index ++; tr_state->ctx = ctx; /*if overlay we cannot remove the context and cannot draw directly*/ if (! visual_2d_overlaps_overlay(tr_state->visual, ctx, tr_state)) { if (ctx->drawable->flags & DRAWABLE_USE_TRAVERSE_DRAW) { gf_node_traverse(ctx->drawable->node, tr_state); } else { drawable_draw(ctx->drawable, tr_state); } } ctx = ctx->next; } /*flush pending contexts due to overlays*/ visual_2d_flush_overlay_areas(visual, tr_state); #ifndef GPAC_DISABLE_VRML if (bck_ctx) bck_ctx->next = NULL; #endif if (visual->direct_flush) { GF_DirtyRectangles dr; u32 i; dr.count = visual->to_redraw.count; dr.list = gf_malloc(sizeof(GF_IRect)*dr.count); for (i=0; i<dr.count; i++) { dr.list[i] = visual->to_redraw.list[i].rect; } visual->compositor->video_out->FlushRectangles(visual->compositor->video_out, &dr); visual->compositor->skip_flush=1; gf_free(dr.list); } exit: /*clear dirty rects*/ ra_clear(&visual->to_redraw); visual_2d_release_raster(visual); visual_clean_contexts(visual); visual->num_nodes_prev_frame = visual->num_nodes_current_frame; return has_changed; }
Bool VS2D_TerminateDraw(VisualSurface2D *surf, RenderEffect2D *eff) { u32 j, k, i, num_to_draw, num_empty, count, max_nodes_allowed; M4IRect refreshRect; Bool redraw_all, is_empty; M_Background2D *bck; DrawableContext *bck_ctx; DrawableContext *ctx; Bool use_direct_render = 0; Bool has_changed = 0; /*in direct mode the surface is always redrawn*/ if (eff->trav_flags & TF_RENDER_DIRECT) { has_changed = 1; use_direct_render = 1; } VS2D_ResetSensors(surf); num_to_draw = 0; /*if the aspect ratio has changed redraw everything*/ redraw_all = eff->invalidate_all; /*check for background changes for transparent nodes*/ bck = NULL; bck_ctx = NULL; if (! use_direct_render) { bck = NULL; if (ChainGetCount(surf->back_stack)) bck = ChainGetEntry(surf->back_stack, 0); if (bck) { if (!bck->isBound) redraw_all = 1; surf->last_had_back = 1; bck_ctx = b2D_GetContext(bck, surf->back_stack); if (bck_ctx->redraw_flags) redraw_all = 1; } else if (surf->last_had_back) { surf->last_had_back = 0; redraw_all = 1; } surf->last_had_back = 0; } max_nodes_allowed = (u32) ((surf->top_clipper.width / MIN_BBOX_SIZE) * (surf->top_clipper.height / MIN_BBOX_SIZE)); num_empty = 0; count = surf->num_contexts; for (i=0; i<count; i++) { ctx = surf->contexts[i]; m4_irect_intersect(&ctx->clip, &surf->top_clipper); is_empty = m4_rect_is_empty(ctx->clip); /*store bounds even in direct render*/ if (!is_empty) { drawable_store_bounds(ctx); register_sensor(surf, ctx); } else if (!use_direct_render) { num_empty++; continue; } //register node to draw surf->nodes_to_draw[num_to_draw] = i; num_to_draw++; if (use_direct_render) { drawable_reset_previous_bounds(ctx->node); continue; } drawctx_update_info(ctx); /*node has changed, add to redraw area*/ if (!redraw_all && ctx->redraw_flags) { ra_union_rect(&surf->to_redraw, ctx->clip); CHECK_MAX_NODE } /*otherwise try to remove any sensor hidden below*/ if (!ctx->transparent) remove_hidden_sensors(surf, num_to_draw, ctx); }