This source file includes following definitions.
- group_cache_draw
- group_cache_new
- group_cache_del
- group_cache_setup
- group_cache_traverse
- group_cache_insert_entry
- gf_cache_remove_entry
- group_2d_cache_traverse
- group_cache_compute_stats
- group_2d_cache_evaluate
- compositor_set_cache_memory
- group_2d_destroy_svg
- group_2d_destroy
#include "offscreen_cache.h"
#include "visual_manager.h"
#include "mpeg4_grouping.h"
#include "texturing.h"
#define NUM_STATS_FRAMES 2
#define MIN_OBJECTS_IN_CACHE 2
void group_cache_draw(GroupCache *cache, GF_TraverseState *tr_state)
{
GF_TextureHandler *old_txh = tr_state->ctx->aspect.fill_texture;
tr_state->ctx->aspect.fill_texture = &cache->txh;
#if !defined( GPAC_DISABLE_3D) && !defined(GPAC_DISABLE_VRML)
if (tr_state->traversing_mode == TRAVERSE_DRAW_3D) {
if (!cache->drawable->mesh) {
cache->drawable->mesh = new_mesh();
}
mesh_from_path(cache->drawable->mesh, cache->drawable->path);
visual_3d_draw_2d_with_aspect(cache->drawable, tr_state, &tr_state->ctx->aspect);
return;
}
#endif
if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx)) {
visual_2d_texture_path(tr_state->visual, cache->drawable->path, tr_state->ctx, tr_state);
}
tr_state->ctx->aspect.fill_texture = old_txh;
}
GroupCache *group_cache_new(GF_Compositor *compositor, GF_Node *node)
{
GroupCache *cache;
GF_SAFEALLOC(cache, GroupCache);
if (!cache) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate group cache\n"));
return NULL;
}
gf_sc_texture_setup(&cache->txh, compositor, node);
cache->drawable = drawable_new();
cache->drawable->flags |= DRAWABLE_USE_TRAVERSE_DRAW;
cache->drawable->node = node;
cache->opacity = FIX_ONE;
gf_sc_texture_allocate(&cache->txh);
return cache;
}
void group_cache_del(GroupCache *cache)
{
drawable_del(cache->drawable);
if (cache->txh.data) gf_free(cache->txh.data);
gf_sc_texture_release(&cache->txh);
gf_sc_texture_destroy(&cache->txh);
gf_free(cache);
}
void group_cache_setup(GroupCache *cache, GF_Rect *path_bounds, GF_IRect *pix_bounds, GF_Compositor *compositor, Bool for_gl)
{
cache->txh.compositor = compositor;
cache->txh.height = pix_bounds->height;
cache->txh.width = pix_bounds->width;
cache->txh.stride = pix_bounds->width * 4;
cache->txh.pixelformat = for_gl ? GF_PIXEL_RGBA : GF_PIXEL_ARGB;
cache->txh.transparent = 1;
if (cache->txh.data)
gf_free(cache->txh.data);
#ifdef CACHE_DEBUG_ALPHA
cache->txh.stride = pix_bounds->width * 3;
cache->txh.pixelformat = GF_PIXEL_RGB_24;
cache->txh.transparent = 0;
#endif
cache->txh.data = (char *) gf_malloc (sizeof(char) * cache->txh.stride * cache->txh.height);
memset(cache->txh.data, 0x0, sizeof(char) * cache->txh.stride * cache->txh.height);
gf_path_reset(cache->drawable->path);
gf_path_add_rect_center(cache->drawable->path,
path_bounds->x + path_bounds->width/2,
path_bounds->y - path_bounds->height/2,
path_bounds->width, path_bounds->height);
}
Bool group_cache_traverse(GF_Node *node, GroupCache *cache, GF_TraverseState *tr_state, Bool force_recompute, Bool is_mpeg4, Bool auto_fit_vp)
{
GF_Matrix2D backup;
DrawableContext *group_ctx = NULL;
GF_ChildNodeItem *l;
if (!cache) return 0;
if (cache->force_recompute) {
force_recompute = 1;
cache->force_recompute = 0;
}
else if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) {
force_recompute = 1;
}
if (force_recompute) {
GF_Matrix2D backup;
GF_IRect rc1, rc2;
u32 prev_flags;
Bool prev_hybgl, visual_attached, for_3d=GF_FALSE;
GF_Rect cache_bounds;
GF_SURFACE offscreen_surface, old_surf;
GF_Raster2D *r2d = tr_state->visual->compositor->rasterizer;
DrawableContext *child_ctx;
Fixed temp_x, temp_y, scale_x, scale_y;
#ifndef GPAC_DISABLE_3D
u32 type_3d;
GF_Matrix2D transf;
#endif
GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Recomputing cache for subtree %s\n", gf_node_get_log_name(node)));
tr_state->in_group_cache = 1;
prev_flags = tr_state->immediate_draw;
gf_mx2d_copy(backup, tr_state->transform);
gf_mx2d_init(tr_state->transform);
#ifndef GPAC_DISABLE_3D
type_3d = tr_state->visual->type_3d;
tr_state->visual->type_3d = 0;
if (type_3d || tr_state->visual->compositor->hybrid_opengl)
for_3d = GF_TRUE;
#endif
prev_hybgl = tr_state->visual->compositor->hybrid_opengl;
tr_state->visual->compositor->hybrid_opengl = GF_FALSE;
tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
cache_bounds.width = cache_bounds.height = 0;
l = ((GF_ParentNode*)node)->children;
while (l) {
tr_state->bounds.width = tr_state->bounds.height = 0;
gf_node_traverse(l->node, tr_state);
l = l->next;
gf_rect_union(&cache_bounds, &tr_state->bounds);
}
tr_state->traversing_mode = TRAVERSE_SORT;
if (!cache_bounds.width || !cache_bounds.height) {
tr_state->in_group_cache = 0;
tr_state->immediate_draw = prev_flags;
gf_mx2d_copy(tr_state->transform, backup);
#ifndef GPAC_DISABLE_3D
tr_state->visual->type_3d = type_3d;
#endif
tr_state->visual->compositor->hybrid_opengl = prev_hybgl;
return 0;
}
if (is_mpeg4) {
#ifndef GPAC_DISABLE_VRML
group_ctx = drawable_init_context_mpeg4(cache->drawable, tr_state);
#endif
} else {
#ifndef GPAC_DISABLE_SVG
group_ctx = drawable_init_context_svg(cache->drawable, tr_state);
#endif
}
if (!group_ctx) return 0;
old_surf = tr_state->visual->raster_surface;
offscreen_surface = r2d->surface_new(r2d, tr_state->visual->center_coords);
tr_state->visual->raster_surface = offscreen_surface;
#ifndef GPAC_DISABLE_3D
if (type_3d) {
gf_mx2d_from_mx(&transf, &tr_state->model_matrix);
scale_x = transf.m[0];
scale_y = transf.m[4];
} else
#endif
{
scale_x = backup.m[0];
scale_y = backup.m[4];
}
#ifdef GF_SR_USE_VIDEO_CACHE
scale_x = tr_state->visual->compositor->cache_scale * scale_x / 100;
scale_y = tr_state->visual->compositor->cache_scale * scale_y / 100;
#endif
if (scale_x<0) scale_x = -scale_x;
if (scale_y<0) scale_y = -scale_y;
cache->scale = MAX(scale_x, scale_y);
tr_state->bounds = cache_bounds;
gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);
gf_mx2d_apply_rect(&tr_state->transform, &cache_bounds);
rc1 = gf_rect_pixelize(&cache_bounds);
if (rc1.width % 2) rc1.width++;
if (rc1.height%2) rc1.height++;
while (rc1.width && rc1.width<128) rc1.width *= 2;
while (rc1.height && rc1.height<128) rc1.height *= 2;
group_cache_setup(cache, &tr_state->bounds, &rc1, tr_state->visual->compositor, for_3d);
r2d->surface_attach_to_buffer(offscreen_surface, cache->txh.data,
cache->txh.width,
cache->txh.height,
0,
cache->txh.stride,
cache->txh.pixelformat);
visual_attached = tr_state->visual->is_attached;
tr_state->visual->is_attached = 1;
scale_x = gf_divfix(INT2FIX(rc1.width), tr_state->bounds.width);
scale_y = gf_divfix(INT2FIX(rc1.height), tr_state->bounds.height);
gf_mx2d_init(tr_state->transform);
gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);
cache_bounds = tr_state->bounds;
gf_mx2d_apply_rect(&tr_state->transform, &cache_bounds);
temp_x = -cache_bounds.x;
temp_y = -cache_bounds.y;
if (tr_state->visual->center_coords) {
temp_x -= cache_bounds.width/2;
temp_y += cache_bounds.height/2;
} else {
temp_y += cache_bounds.height;
}
gf_mx2d_add_translation(&tr_state->transform, temp_x, temp_y);
rc1 = tr_state->visual->surf_rect;
rc2 = tr_state->visual->top_clipper;
tr_state->visual->surf_rect.width = cache->txh.width;
tr_state->visual->surf_rect.height = cache->txh.height;
if (tr_state->visual->center_coords) {
tr_state->visual->surf_rect.y = cache->txh.height/2;
tr_state->visual->surf_rect.x = -1 * (s32) cache->txh.width/2;
} else {
tr_state->visual->surf_rect.y = cache->txh.height;
tr_state->visual->surf_rect.x = 0;
}
tr_state->visual->top_clipper = tr_state->visual->surf_rect;
tr_state->immediate_draw = 1;
group_ctx->flags &= ~CTX_NO_ANTIALIAS;
l = ((GF_ParentNode*)node)->children;
while (l) {
gf_node_traverse(l->node, tr_state);
l = l->next;
}
child_ctx = group_ctx->next;
while (child_ctx && child_ctx->drawable) {
drawable_reset_bounds(child_ctx->drawable, tr_state->visual);
child_ctx->drawable = NULL;
child_ctx = child_ctx->next;
}
tr_state->visual->cur_context = group_ctx;
gf_mx2d_copy(tr_state->transform, backup);
tr_state->in_group_cache = 0;
tr_state->immediate_draw = prev_flags;
tr_state->visual->compositor->hybrid_opengl = prev_hybgl;
tr_state->visual->is_attached = visual_attached;
r2d->surface_delete(offscreen_surface);
tr_state->visual->raster_surface = old_surf;
tr_state->traversing_mode = TRAVERSE_SORT;
#ifndef GPAC_DISABLE_3D
tr_state->visual->type_3d = type_3d;
#endif
tr_state->visual->surf_rect = rc1;
tr_state->visual->top_clipper = rc2;
cache->txh.transparent = 1;
if (tr_state->visual->center_coords)
cache->txh.flags |= GF_SR_TEXTURE_NO_GL_FLIP;
gf_sc_texture_set_data(&cache->txh);
gf_sc_texture_push_image(&cache->txh, 0, for_3d ? 0 : 1);
cache->orig_vp = tr_state->vp_size;
}
else {
if (is_mpeg4) {
#ifndef GPAC_DISABLE_VRML
group_ctx = drawable_init_context_mpeg4(cache->drawable, tr_state);
#endif
} else {
#ifndef GPAC_DISABLE_SVG
group_ctx = drawable_init_context_svg(cache->drawable, tr_state);
#endif
}
}
if (!group_ctx) return 0;
group_ctx->flags |= CTX_NO_ANTIALIAS;
if (cache->opacity != FIX_ONE)
group_ctx->aspect.fill_color = GF_COL_ARGB_FIXED(cache->opacity, FIX_ONE, FIX_ONE, FIX_ONE);
else
group_ctx->aspect.fill_color = 0;
group_ctx->aspect.fill_texture = &cache->txh;
if (!cache->opacity) {
group_ctx->drawable = NULL;
return 0;
}
drawable_check_texture_dirty(group_ctx, group_ctx->drawable, tr_state);
if (gf_node_dirty_get(node)) group_ctx->flags |= CTX_TEXTURE_DIRTY;
#ifdef CACHE_DEBUG_CENTER
gf_mx2d_copy(backup, tr_state->transform);
gf_mx2d_init(tr_state->transform);
#else
gf_mx2d_copy(backup, tr_state->transform);
if (auto_fit_vp) {
if ((tr_state->vp_size.x != cache->orig_vp.x) || (tr_state->vp_size.y != cache->orig_vp.y)) {
GF_Matrix2D m;
gf_mx2d_init(m);
gf_mx2d_copy(backup, tr_state->transform);
gf_mx2d_add_scale(&m, gf_divfix(tr_state->vp_size.x, cache->orig_vp.x), gf_divfix(tr_state->vp_size.y, cache->orig_vp.y) );
gf_mx2d_pre_multiply(&tr_state->transform, &m);
} else {
auto_fit_vp = 0;
}
}
#endif
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
if (!cache->drawable->mesh) {
cache->drawable->mesh = new_mesh();
mesh_from_path(cache->drawable->mesh, cache->drawable->path);
}
visual_3d_draw_from_context(group_ctx, tr_state);
group_ctx->drawable = NULL;
} else
#endif
drawable_finalize_sort(group_ctx, tr_state, NULL);
#ifndef CACHE_DEBUG_CENTER
if (auto_fit_vp)
#endif
{
gf_mx2d_copy(tr_state->transform, backup);
}
return (force_recompute==1);
}
#ifdef GF_SR_USE_VIDEO_CACHE
static void group_cache_insert_entry(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state)
{
u32 i, count;
GF_List *cache_candidates = tr_state->visual->compositor->cached_groups;
GroupingNode2D *current;
current = NULL;
count = gf_list_count(cache_candidates);
for (i=0; i<count; i++) {
current = gf_list_get(cache_candidates, i);
if (current->priority >= group->priority) {
gf_list_insert(cache_candidates, group, i);
break;
}
}
if (i==count)
gf_list_add(cache_candidates, group);
tr_state->visual->compositor->video_cache_current_size += group->cached_size;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE]\tAdding object %s\tObjects: %d\tSlope: %g\tSize: %d\tTime: %d\n",
gf_node_get_log_name(node),
group->nb_objects,
FIX2FLT(group->priority),
group->cached_size,
group->traverse_time));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Status (KB): Max: %d\tUsed: %d\tNb Groups: %d\n",
tr_state->visual->compositor->video_cache_max_size,
tr_state->visual->compositor->video_cache_current_size,
gf_list_count(tr_state->visual->compositor->cached_groups)
));
}
static Bool gf_cache_remove_entry(GF_Compositor *compositor, GF_Node *node, GroupingNode2D *group)
{
u32 bytes_remove = 0;
GF_List *cache_candidates = compositor->cached_groups;
if (!group) {
group = gf_list_get(cache_candidates, 0);
if (!group) return 0;
gf_list_rem(cache_candidates, 0);
node = NULL;
} else {
if (gf_list_del_item(cache_candidates, group)<0)
return 0;
}
if(group->flags & GROUP_IS_CACHABLE) {
group->flags &= ~GROUP_IS_CACHABLE;
bytes_remove = group->cached_size;
}
if (group->cache && (group->flags & GROUP_IS_CACHED)) {
group->flags &= ~GROUP_IS_CACHED;
bytes_remove = group->cached_size;
}
if (bytes_remove == 0) return 0;
assert(compositor->video_cache_current_size >= bytes_remove);
compositor->video_cache_current_size -= bytes_remove;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Removing cache %s:\t Objects: %d\tSlope: %g\tBytes: %d\tTime: %d\n",
gf_node_get_log_name(node),
group->nb_objects,
FIX2FLT(group->priority),
group->cached_size,
FIX2FLT(group->traverse_time)));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Status (B): Max: %d\tUsed: %d\tNb Groups: %d\n",
compositor->video_cache_max_size,
compositor->video_cache_current_size,
gf_list_count(compositor->cached_groups)
));
return 1;
}
Bool group_2d_cache_traverse(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state)
{
Bool is_dirty = gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY;
Bool zoom_changed = tr_state->visual->compositor->zoom_changed;
Bool needs_recompute = 0;
if (tr_state->in_group_cache) return 0;
if (tr_state->traversing_mode == TRAVERSE_DRAW_2D) {
assert(group->cache);
group_cache_draw(group->cache, tr_state);
return 1;
}
if (tr_state->traversing_mode != TRAVERSE_SORT) return 0;
if (!(group->flags & GROUP_IS_CACHED) ) {
Bool cache_on = 0;
if (!is_dirty && (group->flags & GROUP_IS_CACHABLE)) {
group->flags |= GROUP_IS_CACHED;
group->flags &= ~GROUP_IS_CACHABLE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Turning group %s cache on - size %d\n", gf_node_get_log_name(node), group->cached_size ));
cache_on = 1;
}
else if (group->cache) {
group_cache_del(group->cache);
group->cache = NULL;
group->changed = is_dirty;
group->nb_stats_frame = 0;
group->traverse_time = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Turning group %s cache off\n", gf_node_get_log_name(node) ));
return 0;
}
if (!cache_on) {
if (is_dirty) {
group->changed = 1;
}
else if (group->changed) {
group->changed = 0;
group->nb_stats_frame = 0;
group->traverse_time = 0;
} else if (zoom_changed) {
group->nb_stats_frame = 0;
group->traverse_time = 0;
}
if (is_dirty || (group->nb_stats_frame < NUM_STATS_FRAMES)) {
if (!is_dirty)
tr_state->visual->compositor->traverse_state->invalidate_all = 1;
tr_state->visual->compositor->draw_next_frame = 1;
}
return 0;
}
}
else if (is_dirty) {
if (group->flags & GROUP_PERMANENT_CACHE) {
group->changed = 1;
group->cache->force_recompute = 1;
}
else if (group->cache) {
gf_cache_remove_entry(tr_state->visual->compositor, node, group);
group_cache_del(group->cache);
group->cache = NULL;
group->flags &= ~GROUP_IS_CACHED;
group->changed = 0;
group->nb_stats_frame = 0;
group->traverse_time = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Turning group %s cache off due to sub-tree modifications\n", gf_node_get_log_name(node) ));
return 0;
}
}
else if (zoom_changed) {
if (group->flags & GROUP_PERMANENT_CACHE) {
group->changed = 1;
group->cache->force_recompute = 1;
}
else if (group->cache) {
Fixed scale = MAX(tr_state->transform.m[0], tr_state->transform.m[4]);
if (100*scale >= group->cache->scale*(100 + tr_state->visual->compositor->cache_tolerance))
zoom_changed = 1;
else if ((100+tr_state->visual->compositor->cache_tolerance)*scale <= 100*group->cache->scale)
zoom_changed = 1;
else
zoom_changed = 0;
if (zoom_changed) {
gf_cache_remove_entry(tr_state->visual->compositor, node, group);
group_cache_del(group->cache);
group->cache = NULL;
group->flags &= ~GROUP_IS_CACHED;
group->changed = 0;
group->nb_stats_frame = 0;
group->traverse_time = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Turning group %s cache off due to zoom changes\n", gf_node_get_log_name(node) ));
return 0;
}
}
}
if (!(group->flags & GROUP_PERMANENT_CACHE))
gf_list_add(tr_state->visual->compositor->cached_groups_queue, group);
if (!group->cache) {
group->cache = group_cache_new(tr_state->visual->compositor, node);
needs_recompute = 1;
}
group_cache_traverse(node, group->cache, tr_state, needs_recompute, 1, 0);
return 1;
}
Bool group_cache_compute_stats(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state, DrawableContext *first_child, Bool skip_first_child)
{
GF_Rect group_bounds;
DrawableContext *ctx;
u32 nb_segments, nb_objects;
u32 alpha_pixels, opaque_pixels, area_world;
u32 video_cache_max_size, cache_size, prev_cache_size;
u32 i;
GF_RectArray ra;
nb_objects = 0;
nb_segments = 0;
alpha_pixels = opaque_pixels = 0;
prev_cache_size = group->cached_size;
group_bounds.width = group_bounds.height = 0;
video_cache_max_size = tr_state->visual->compositor->video_cache_max_size;
if (gf_node_get_parent(node, 0) == NULL) goto group_reject;
if (!group->traverse_time) goto group_reject;
ra_init(&ra);
ctx = first_child;
if (!first_child) ctx = tr_state->visual->context;
if (skip_first_child) ctx = ctx->next;
while (ctx && ctx->drawable) {
u32 alpha_comp;
alpha_comp = GF_COL_A(ctx->aspect.fill_color);
gf_rect_union(&group_bounds, &ctx->bi->unclip);
nb_objects++;
if ((alpha_comp==0xFF)
&& (!ctx->aspect.fill_texture || !ctx->aspect.fill_texture->transparent)
) {
ra_union_rect(&ra, &ctx->bi->clip);
}
nb_segments += ctx->drawable->path->n_points;
ctx = ctx->next;
}
if (
(!group_bounds.width || !group_bounds.height)
||
(nb_objects<MIN_OBJECTS_IN_CACHE)
||
(nb_segments && (nb_segments<10))
) {
ra_del(&ra);
goto group_reject;
}
ra_refresh(&ra);
opaque_pixels = 0;
for (i=0; i<ra.count; i++) {
opaque_pixels += ra.list[i].width * ra.list[i].height;
}
ra_del(&ra);
area_world = FIX2INT(group_bounds.width) * FIX2INT(group_bounds.height);
if (10*opaque_pixels < 7*area_world) goto group_reject;
group_bounds.width = tr_state->visual->compositor->cache_scale * group_bounds.width / 100;
group_bounds.height = tr_state->visual->compositor->cache_scale * group_bounds.height / 100;
cache_size = FIX2INT(group_bounds.width) * FIX2INT(group_bounds.height) * 4 ;
if (cache_size < 400) goto group_reject;
if (cache_size>=video_cache_max_size) {
tr_state->cache_too_small = 1;
goto group_reject;
}
group->priority = INT2FIX(nb_objects*1024*group->traverse_time) / cache_size / group->nb_stats_frame;
group->nb_objects = nb_objects;
group->cached_size = cache_size;
if (!(group->flags & GROUP_IS_CACHABLE)) {
group->flags |= GROUP_IS_CACHABLE;
tr_state->visual->compositor->draw_next_frame = 1;
group_cache_insert_entry(node, group, tr_state);
gf_list_add(tr_state->visual->compositor->cached_groups_queue, group);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Turning cache on during stat pass for node %s - %d kb used in all caches\n", gf_node_get_log_name(node), tr_state->visual->compositor->video_cache_current_size ));
}
else {
tr_state->visual->compositor->video_cache_current_size -= prev_cache_size;
tr_state->visual->compositor->video_cache_current_size += group->cached_size;
if (group->cache)
group->cache->force_recompute = 1;
}
return 1;
group_reject:
group->nb_objects = nb_objects;
if ((group->flags & GROUP_IS_CACHABLE) || group->cache) {
group->flags &= ~GROUP_IS_CACHABLE;
if (group->cache) {
group_cache_del(group->cache);
group->cache = NULL;
group->flags &= ~GROUP_IS_CACHED;
}
gf_list_del_item(tr_state->visual->compositor->cached_groups, group);
tr_state->visual->compositor->video_cache_current_size -= cache_size;
}
#if 0
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] REJECT %s\tObjects: %d\tSlope: %g\tBytes: %d\tTime: %d\n",
gf_node_get_log_name(node),
group->nb_objects,
FIX2FLT(group->priority),
group->cached_size,
group->traverse_time
));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Status (B): Max: %d\tUsed: %d\tNb Groups: %d\n",
tr_state->visual->compositor->video_cache_max_size,
tr_state->visual->compositor->video_cache_current_size,
gf_list_count(tr_state->visual->compositor->cached_groups)
));
#endif
return 0;
}
void group_2d_cache_evaluate(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state, DrawableContext *first_child, Bool skip_first_child, u32 last_cache_idx)
{
u32 nb_cache_added, i;
Fixed priority;
GF_Compositor *compositor = tr_state->visual->compositor;
if (!compositor->video_cache_max_size || !compositor->frame_number || group->changed || tr_state->in_group_cache) {
group->traverse_time = 0;
return;
}
if (group->nb_stats_frame < NUM_STATS_FRAMES) {
group->nb_stats_frame++;
tr_state->visual->compositor->draw_next_frame = 1;
return;
}
if (group->nb_stats_frame > NUM_STATS_FRAMES) return;
group->nb_stats_frame++;
if (group_cache_compute_stats(node, group, tr_state, first_child, skip_first_child)) {
Fixed avg_time;
nb_cache_added = gf_list_count(compositor->cached_groups_queue) - last_cache_idx - 1;
tr_state->visual->compositor->draw_next_frame = 1;
avg_time = group->priority * group->cached_size / (1024*group->nb_objects);
for (i=0; i<nb_cache_added; i++) {
Fixed cache_time;
GroupingNode2D *cache = gf_list_get(compositor->cached_groups_queue, last_cache_idx);
if (cache->cache) {
cache_time = cache->priority * cache->cached_size / (1024*group->nb_objects);
avg_time += cache_time;
}
gf_cache_remove_entry(compositor, NULL, cache);
cache->nb_stats_frame = 0;
cache->traverse_time = 0;
gf_list_rem(compositor->cached_groups_queue, last_cache_idx);
}
priority = INT2FIX (group->nb_objects*1024*1024*avg_time) / group->cached_size;
while (compositor->video_cache_current_size > compositor->video_cache_max_size) {
gf_cache_remove_entry(compositor, node, NULL);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Removing low priority cache - current total size %d\n", compositor->video_cache_current_size));
}
}
}
void compositor_set_cache_memory(GF_Compositor *compositor, u32 memory)
{
while (compositor->video_cache_current_size) {
gf_cache_remove_entry(compositor, NULL, NULL);
}
compositor->video_cache_max_size = memory;
compositor->zoom_changed = 1;
}
#endif
void group_2d_destroy_svg(GF_Node *node, GroupingNode2D *group)
{
#ifdef GF_SR_USE_VIDEO_CACHE
GF_Compositor *compositor = gf_sc_get_compositor(node);
if (gf_cache_remove_entry(compositor, node, group)) {
compositor->zoom_changed = 1;
compositor->draw_next_frame = 1;
}
if (group->cache) group_cache_del(group->cache);
#endif
}
void group_2d_destroy(GF_Node *node, GroupingNode2D *group)
{
group_2d_destroy_svg(node, group);
if (group->sensors) gf_list_del(group->sensors);
}