worker: move display_channel_free_some

Author:    Marc-André Lureau <marcandre.lureau@gmail.com>
Acked-by: Fabiano Fidêncio <fabiano@fidencio.org>
This commit is contained in:
Marc-André Lureau 2013-09-26 22:53:57 +02:00 committed by Frediano Ziglio
parent b9ea3c9145
commit 4acf97cae1
5 changed files with 145 additions and 129 deletions

View File

@ -517,6 +517,31 @@ void dcc_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable)
}
}
/*
* Remove from the global lz dictionary some glz_drawables that have no reference to
* Drawable (their qxl drawables are released too).
* NOTE - the caller should prevent encoding using the dictionary during the operation
*/
int dcc_free_some_independent_glz_drawables(DisplayChannelClient *dcc)
{
RingItem *ring_link;
int n = 0;
if (!dcc) {
return 0;
}
ring_link = ring_get_head(&dcc->glz_drawables);
while ((n < RED_RELEASE_BUNCH_SIZE) && (ring_link != NULL)) {
RedGlzDrawable *glz_drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link);
ring_link = ring_next(&dcc->glz_drawables, ring_link);
if (!glz_drawable->drawable) {
dcc_free_glz_drawable(dcc, glz_drawable);
n++;
}
}
return n;
}
void dcc_free_glz_drawables_to_free(DisplayChannelClient* dcc)
{
RingItem *ring_link;

View File

@ -36,13 +36,13 @@ typedef struct RedCompressBuf RedCompressBuf;
typedef struct GlzDrawableInstanceItem GlzDrawableInstanceItem;
typedef struct RedGlzDrawable RedGlzDrawable;
void dcc_encoders_init (DisplayChannelClient *dcc);
void dcc_encoders_free (DisplayChannelClient *dcc);
void dcc_free_glz_drawable_instance (DisplayChannelClient *dcc,
GlzDrawableInstanceItem *item);
void dcc_free_glz_drawable (DisplayChannelClient *dcc,
RedGlzDrawable *drawable);
int dcc_free_some_independent_glz_drawables (DisplayChannelClient *dcc);
void dcc_free_glz_drawables (DisplayChannelClient *dcc);
void dcc_free_glz_drawables_to_free (DisplayChannelClient* dcc);
void dcc_freeze_glz (DisplayChannelClient *dcc);
@ -157,5 +157,6 @@ struct RedGlzDrawable {
DisplayChannelClient *dcc;
};
#define RED_RELEASE_BUNCH_SIZE 64
#endif /* DCC_ENCODERS_H_ */

View File

@ -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;
}

View File

@ -257,11 +257,15 @@ typedef struct SurfaceDestroyItem {
} SurfaceDestroyItem;
void display_channel_free_some (DisplayChannel *display);
void display_channel_set_stream_video (DisplayChannel *display,
int stream_video);
int display_channel_get_streams_timeout (DisplayChannel *display);
void display_channel_compress_stats_print (const DisplayChannel *display);
void display_channel_compress_stats_reset (DisplayChannel *display);
Drawable * display_channel_drawable_try_new (DisplayChannel *display,
int group_id,
int process_commands_generation);
void display_channel_drawable_unref (DisplayChannel *display, Drawable *drawable);
void display_channel_surface_unref (DisplayChannel *display,
uint32_t surface_id);
@ -399,5 +403,7 @@ void red_pipes_remove_drawable(Drawable *drawable);
void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable);
void current_remove(DisplayChannel *display, TreeItem *item);
void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
void drawable_draw(DisplayChannel *display, Drawable *item);
void current_remove_all(DisplayChannel *display, int surface_id);
#endif /* DISPLAY_CHANNEL_H_ */

View File

@ -152,13 +152,11 @@ typedef struct BitmapData {
static inline int validate_surface(DisplayChannel *display, uint32_t surface_id);
static void drawable_draw(DisplayChannel *display, Drawable *item);
static void red_update_area(DisplayChannel *display, const SpiceRect *area, int surface_id);
static void red_update_area_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
Drawable *last);
static inline void display_begin_send_message(RedChannelClient *rcc);
static void dcc_release_glz(DisplayChannelClient *dcc);
static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc);
static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
PipeItem *item);
static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
@ -300,7 +298,6 @@ static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
return 1;
}
static inline void red_handle_drawable_surfaces_client_synced(
DisplayChannelClient *dcc, Drawable *drawable)
{
@ -473,20 +470,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
}
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;
}
static void drawable_free(DisplayChannel *display, Drawable *drawable)
{
((_Drawable *)drawable)->u.next = display->free_drawables;
@ -678,7 +661,7 @@ void current_remove(DisplayChannel *display, TreeItem *item)
}
}
static void current_remove_all(DisplayChannel *display, int surface_id)
void current_remove_all(DisplayChannel *display, int surface_id)
{
Ring *ring = &display->surfaces[surface_id].current;
RingItem *ring_item;
@ -1048,31 +1031,6 @@ static inline int red_handle_self_bitmap(RedWorker *worker, Drawable *drawable)
return TRUE;
}
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;
}
static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *red_drawable,
uint32_t group_id)
{
@ -1090,29 +1048,17 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
}
}
while (!(drawable = drawable_try_new(display))) {
if (!free_one_drawable(display, FALSE))
return NULL;
drawable = display_channel_drawable_try_new(display, group_id, worker->process_commands_generation);
if (!drawable) {
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);
drawable->tree_item.effect = effect;
drawable->red_drawable = red_drawable_ref(red_drawable);
drawable->group_id = group_id;
drawable->surface_id = red_drawable->surface_id;
memcpy(drawable->surface_deps, red_drawable->surface_deps, sizeof(drawable->surface_deps));
ring_init(&drawable->pipes);
ring_init(&drawable->glz_ring);
drawable->process_commands_generation = worker->process_commands_generation;
return drawable;
}
@ -1324,7 +1270,7 @@ static void image_surface_init(DisplayChannel *display)
display->image_surfaces.ops = &image_surfaces_ops;
}
static void drawable_draw(DisplayChannel *display, Drawable *drawable)
void drawable_draw(DisplayChannel *display, Drawable *drawable)
{
RedSurface *surface;
SpiceCanvas *canvas;
@ -1792,49 +1738,6 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
return n;
}
#define RED_RELEASE_BUNCH_SIZE 64
static void red_free_some(RedWorker *worker)
{
DisplayChannel *display = worker->display_channel;
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(worker->display_channel, 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 = red_display_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(worker->display_channel, item, next, dcc) {
GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
if (glz_dict) {
pthread_rwlock_unlock(&glz_dict->encode_lock);
}
}
}
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);
}
static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
{
SpiceMsgDisplayBase base;
@ -1846,31 +1749,6 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
spice_marshall_DisplayBase(base_marshaller, &base);
}
/*
* Remove from the global lz dictionary some glz_drawables that have no reference to
* Drawable (their qxl drawables are released too).
* NOTE - the caller should prevent encoding using the dictionary during the operation
*/
static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc)
{
RingItem *ring_link;
int n = 0;
if (!dcc) {
return 0;
}
ring_link = ring_get_head(&dcc->glz_drawables);
while ((n < RED_RELEASE_BUNCH_SIZE) && (ring_link != NULL)) {
RedGlzDrawable *glz_drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link);
ring_link = ring_next(&dcc->glz_drawables, ring_link);
if (!glz_drawable->drawable) {
dcc_free_glz_drawable(dcc, glz_drawable);
n++;
}
}
return n;
}
static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
SpiceImage *image, SpiceImage *io_image,
int is_lossy)
@ -5828,7 +5706,7 @@ static void handle_dev_oom(void *opaque, void *payload)
red_channel_push(&worker->display_channel->common.base);
}
if (worker->qxl->st->qif->flush_resources(worker->qxl) == 0) {
red_free_some(worker);
display_channel_free_some(worker->display_channel);
worker->qxl->st->qif->flush_resources(worker->qxl);
}
spice_debug("OOM2 #draw=%u, #red_draw=%u, #glz_draw=%u current %u pipes %u",