diff options
Diffstat (limited to 'server/display-channel.c')
-rw-r--r-- | server/display-channel.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/server/display-channel.c b/server/display-channel.c index d455a0db..f443dd01 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -873,3 +873,109 @@ void display_channel_free_glz_drawables(DisplayChannel *display) dcc_free_glz_drawables(dcc); } } + +static bool free_one_drawable(DisplayChannel *display, int force_glz_free) +{ + RingItem *ring_item = ring_get_tail(&display->current_list); + Drawable *drawable; + Container *container; + + if (!ring_item) { + return FALSE; + } + + drawable = SPICE_CONTAINEROF(ring_item, Drawable, list_link); + if (force_glz_free) { + RingItem *glz_item, *next_item; + RedGlzDrawable *glz; + DRAWABLE_FOREACH_GLZ_SAFE(drawable, glz_item, next_item, glz) { + dcc_free_glz_drawable(glz->dcc, glz); + } + } + drawable_draw(display, drawable); + container = drawable->tree_item.base.container; + + current_remove_drawable(display, drawable); + container_cleanup(container); + return TRUE; +} + +void display_channel_current_flush(DisplayChannel *display, int surface_id) +{ + while (!ring_is_empty(&display->surfaces[surface_id].current_list)) { + free_one_drawable(display, FALSE); + } + current_remove_all(display, surface_id); +} + +void display_channel_free_some(DisplayChannel *display) +{ + int n = 0; + DisplayChannelClient *dcc; + RingItem *item, *next; + + spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d", display->drawable_count, + display->red_drawable_count, display->glz_drawable_count); + FOREACH_DCC(display, item, next, dcc) { + GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL; + + if (glz_dict) { + // encoding using the dictionary is prevented since the following operations might + // change the dictionary + pthread_rwlock_wrlock(&glz_dict->encode_lock); + n = dcc_free_some_independent_glz_drawables(dcc); + } + } + + while (!ring_is_empty(&display->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) { + free_one_drawable(display, TRUE); + } + + FOREACH_DCC(display, item, next, dcc) { + GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL; + + if (glz_dict) { + pthread_rwlock_unlock(&glz_dict->encode_lock); + } + } +} + +static Drawable* drawable_try_new(DisplayChannel *display) +{ + Drawable *drawable; + + if (!display->free_drawables) + return NULL; + + drawable = &display->free_drawables->u.drawable; + display->free_drawables = display->free_drawables->u.next; + display->drawable_count++; + + return drawable; +} + +Drawable *display_channel_drawable_try_new(DisplayChannel *display, + int group_id, int process_commands_generation) +{ + Drawable *drawable; + + while (!(drawable = drawable_try_new(display))) { + if (!free_one_drawable(display, FALSE)) + return NULL; + } + + bzero(drawable, sizeof(Drawable)); + drawable->refs = 1; + drawable->creation_time = red_get_monotonic_time(); + ring_item_init(&drawable->list_link); + ring_item_init(&drawable->surface_list_link); + ring_item_init(&drawable->tree_item.base.siblings_link); + drawable->tree_item.base.type = TREE_ITEM_TYPE_DRAWABLE; + region_init(&drawable->tree_item.base.rgn); + ring_init(&drawable->pipes); + ring_init(&drawable->glz_ring); + drawable->process_commands_generation = process_commands_generation; + drawable->group_id = group_id; + + return drawable; +} |