diff options
Diffstat (limited to 'server/dcc.c')
-rw-r--r-- | server/dcc.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/server/dcc.c b/server/dcc.c index 1e188140..9af6d842 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -940,3 +940,93 @@ void dcc_palette_cache_reset(DisplayChannelClient *dcc) { red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE); } + +static void dcc_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id, + uint64_t* sync_data) +{ + FreeList *free_list = &dcc->send_data.free_list; + int i; + + for (i = 0; i < MAX_CACHE_CLIENTS; i++) { + free_list->sync[i] = MAX(free_list->sync[i], sync_data[i]); + } + + if (free_list->res->count == free_list->res_size) { + SpiceResourceList *new_list; + new_list = spice_malloc(sizeof(*new_list) + + free_list->res_size * sizeof(SpiceResourceID) * 2); + new_list->count = free_list->res->count; + memcpy(new_list->resources, free_list->res->resources, + new_list->count * sizeof(SpiceResourceID)); + free(free_list->res); + free_list->res = new_list; + free_list->res_size *= 2; + } + free_list->res->resources[free_list->res->count].type = type; + free_list->res->resources[free_list->res->count++].id = id; +} + +int dcc_pixmap_cache_unlocked_add(DisplayChannelClient *dcc, uint64_t id, + uint32_t size, int lossy) +{ + PixmapCache *cache = dcc->pixmap_cache; + NewCacheItem *item; + uint64_t serial; + int key; + + spice_assert(size > 0); + + item = spice_new(NewCacheItem, 1); + serial = red_channel_client_get_message_serial(RED_CHANNEL_CLIENT(dcc)); + + if (cache->generation != dcc->pixmap_cache_generation) { + if (!dcc->pending_pixmaps_sync) { + red_channel_client_pipe_add_type( + RED_CHANNEL_CLIENT(dcc), PIPE_ITEM_TYPE_PIXMAP_SYNC); + dcc->pending_pixmaps_sync = TRUE; + } + free(item); + return FALSE; + } + + cache->available -= size; + while (cache->available < 0) { + NewCacheItem *tail; + NewCacheItem **now; + + if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) || + tail->sync[dcc->common.id] == serial) { + cache->available += size; + free(item); + return FALSE; + } + + now = &cache->hash_table[BITS_CACHE_HASH_KEY(tail->id)]; + for (;;) { + spice_assert(*now); + if (*now == tail) { + *now = tail->next; + break; + } + now = &(*now)->next; + } + ring_remove(&tail->lru_link); + cache->items--; + cache->available += tail->size; + cache->sync[dcc->common.id] = serial; + dcc_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync); + free(tail); + } + ++cache->items; + item->next = cache->hash_table[(key = BITS_CACHE_HASH_KEY(id))]; + cache->hash_table[key] = item; + ring_item_init(&item->lru_link); + ring_add(&cache->lru, &item->lru_link); + item->id = id; + item->size = size; + item->lossy = lossy; + memset(item->sync, 0, sizeof(item->sync)); + item->sync[dcc->common.id] = serial; + cache->sync[dcc->common.id] = serial; + return TRUE; +} |