mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-03 15:58:43 +00:00
server: move some pixmap cache code in own file
Remove that hideous template header that should really be regular code since it's specialized and instanciated only for pixmap. Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
parent
c749853d08
commit
b15527e063
@ -88,7 +88,6 @@ libspice_server_la_SOURCES = \
|
||||
red_channel.c \
|
||||
red_channel.h \
|
||||
red_client_cache.h \
|
||||
red_client_shared_cache.h \
|
||||
red_common.h \
|
||||
dispatcher.c \
|
||||
dispatcher.h \
|
||||
@ -128,6 +127,8 @@ libspice_server_la_SOURCES = \
|
||||
spice_server_utils.h \
|
||||
spice_image_cache.h \
|
||||
spice_image_cache.c \
|
||||
pixmap-cache.h \
|
||||
pixmap-cache.c \
|
||||
$(NULL)
|
||||
|
||||
if SUPPORT_GL
|
||||
|
||||
142
server/pixmap-cache.c
Normal file
142
server/pixmap-cache.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright (C) 2009-2015 Red Hat, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "pixmap-cache.h"
|
||||
|
||||
int pixmap_cache_unlocked_set_lossy(PixmapCache *cache, uint64_t id, int lossy)
|
||||
{
|
||||
NewCacheItem *item;
|
||||
|
||||
item = cache->hash_table[BITS_CACHE_HASH_KEY(id)];
|
||||
|
||||
while (item) {
|
||||
if (item->id == id) {
|
||||
item->lossy = lossy;
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
return !!item;
|
||||
}
|
||||
|
||||
void pixmap_cache_clear(PixmapCache *cache)
|
||||
{
|
||||
NewCacheItem *item;
|
||||
|
||||
if (cache->freezed) {
|
||||
cache->lru.next = cache->freezed_head;
|
||||
cache->lru.prev = cache->freezed_tail;
|
||||
cache->freezed = FALSE;
|
||||
}
|
||||
|
||||
while ((item = (NewCacheItem *)ring_get_head(&cache->lru))) {
|
||||
ring_remove(&item->lru_link);
|
||||
free(item);
|
||||
}
|
||||
memset(cache->hash_table, 0, sizeof(*cache->hash_table) * BITS_CACHE_HASH_SIZE);
|
||||
|
||||
cache->available = cache->size;
|
||||
cache->items = 0;
|
||||
}
|
||||
|
||||
int pixmap_cache_freeze(PixmapCache *cache)
|
||||
{
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
|
||||
if (cache->freezed) {
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cache->freezed_head = cache->lru.next;
|
||||
cache->freezed_tail = cache->lru.prev;
|
||||
ring_init(&cache->lru);
|
||||
memset(cache->hash_table, 0, sizeof(*cache->hash_table) * BITS_CACHE_HASH_SIZE);
|
||||
cache->available = -1;
|
||||
cache->freezed = TRUE;
|
||||
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void pixmap_cache_destroy(PixmapCache *cache)
|
||||
{
|
||||
spice_assert(cache);
|
||||
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
pixmap_cache_clear(cache);
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
|
||||
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static Ring pixmap_cache_list = {&pixmap_cache_list, &pixmap_cache_list};
|
||||
|
||||
static PixmapCache *pixmap_cache_new(RedClient *client, uint8_t id, int64_t size)
|
||||
{
|
||||
PixmapCache *cache = spice_new0(PixmapCache, 1);
|
||||
|
||||
ring_item_init(&cache->base);
|
||||
pthread_mutex_init(&cache->lock, NULL);
|
||||
cache->id = id;
|
||||
cache->refs = 1;
|
||||
ring_init(&cache->lru);
|
||||
cache->available = size;
|
||||
cache->size = size;
|
||||
cache->client = client;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
PixmapCache *pixmap_cache_get(RedClient *client, uint8_t id, int64_t size)
|
||||
{
|
||||
PixmapCache *ret = NULL;
|
||||
RingItem *now;
|
||||
pthread_mutex_lock(&cache_lock);
|
||||
|
||||
now = &pixmap_cache_list;
|
||||
while ((now = ring_next(&pixmap_cache_list, now))) {
|
||||
PixmapCache *cache = (PixmapCache *)now;
|
||||
if ((cache->client == client) && (cache->id == id)) {
|
||||
ret = cache;
|
||||
ret->refs++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
ret = pixmap_cache_new(client, id, size);
|
||||
ring_add(&pixmap_cache_list, &ret->base);
|
||||
}
|
||||
pthread_mutex_unlock(&cache_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void pixmap_cache_unref(PixmapCache *cache)
|
||||
{
|
||||
if (!cache)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&cache_lock);
|
||||
if (--cache->refs) {
|
||||
pthread_mutex_unlock(&cache_lock);
|
||||
return;
|
||||
}
|
||||
ring_remove(&cache->base);
|
||||
pthread_mutex_unlock(&cache_lock);
|
||||
pixmap_cache_destroy(cache);
|
||||
free(cache);
|
||||
}
|
||||
76
server/pixmap-cache.h
Normal file
76
server/pixmap-cache.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/*
|
||||
Copyright (C) 2009-2015 Red Hat, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _PIXMAP_CACHE_H
|
||||
# define _PIXMAP_CACHE_H
|
||||
|
||||
#include "red_channel.h"
|
||||
#include "spice_server_utils.h"
|
||||
|
||||
#define MAX_CACHE_CLIENTS 4
|
||||
|
||||
#define BITS_CACHE_HASH_SHIFT 10
|
||||
#define BITS_CACHE_HASH_SIZE (1 << BITS_CACHE_HASH_SHIFT)
|
||||
#define BITS_CACHE_HASH_MASK (BITS_CACHE_HASH_SIZE - 1)
|
||||
#define BITS_CACHE_HASH_KEY(id) ((id) & BITS_CACHE_HASH_MASK)
|
||||
|
||||
typedef struct DisplayChannelClient DisplayChannelClient;
|
||||
|
||||
typedef struct PixmapCache PixmapCache;
|
||||
typedef struct NewCacheItem NewCacheItem;
|
||||
|
||||
struct NewCacheItem {
|
||||
RingItem lru_link;
|
||||
NewCacheItem *next;
|
||||
uint64_t id;
|
||||
uint64_t sync[MAX_CACHE_CLIENTS];
|
||||
size_t size;
|
||||
int lossy;
|
||||
};
|
||||
|
||||
struct PixmapCache {
|
||||
RingItem base;
|
||||
pthread_mutex_t lock;
|
||||
uint8_t id;
|
||||
uint32_t refs;
|
||||
NewCacheItem *hash_table[BITS_CACHE_HASH_SIZE];
|
||||
Ring lru;
|
||||
int64_t available;
|
||||
int64_t size;
|
||||
int32_t items;
|
||||
|
||||
int freezed;
|
||||
RingItem *freezed_head;
|
||||
RingItem *freezed_tail;
|
||||
|
||||
uint32_t generation;
|
||||
struct {
|
||||
uint8_t client;
|
||||
uint64_t message;
|
||||
} generation_initiator;
|
||||
uint64_t sync[MAX_CACHE_CLIENTS]; // here CLIENTS refer to different channel
|
||||
// clients of the same client
|
||||
RedClient *client;
|
||||
};
|
||||
|
||||
PixmapCache *pixmap_cache_get(RedClient *client, uint8_t id, int64_t size);
|
||||
void pixmap_cache_unref(PixmapCache *cache);
|
||||
void pixmap_cache_clear(PixmapCache *cache);
|
||||
int pixmap_cache_unlocked_set_lossy(PixmapCache *cache, uint64_t id, int lossy);
|
||||
int pixmap_cache_freeze(PixmapCache *cache);
|
||||
|
||||
#endif /* _PIXMAP_CACHE_H */
|
||||
@ -1,235 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2009 Red Hat, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(CLIENT_PIXMAPS_CACHE)
|
||||
|
||||
#define CACHE PixmapCache
|
||||
|
||||
#define CACHE_NAME bits_cache
|
||||
#define CACHE_HASH_KEY BITS_CACHE_HASH_KEY
|
||||
#define CACHE_HASH_SIZE BITS_CACHE_HASH_SIZE
|
||||
#define PIPE_ITEM_TYPE PIPE_ITEM_TYPE_INVAL_PIXMAP
|
||||
#define FUNC_NAME(name) pixmap_cache_##name
|
||||
#define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name
|
||||
#define CHANNEL DisplayChannel
|
||||
#define CACH_GENERATION pixmap_cache_generation
|
||||
#define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS
|
||||
#else
|
||||
|
||||
#error "no cache type."
|
||||
|
||||
#endif
|
||||
|
||||
#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
|
||||
|
||||
static int FUNC_NAME(unlocked_hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc)
|
||||
{
|
||||
NewCacheItem *item;
|
||||
uint64_t serial;
|
||||
|
||||
serial = red_channel_client_get_message_serial(&dcc->common.base);
|
||||
item = cache->hash_table[CACHE_HASH_KEY(id)];
|
||||
|
||||
while (item) {
|
||||
if (item->id == id) {
|
||||
ring_remove(&item->lru_link);
|
||||
ring_add(&cache->lru, &item->lru_link);
|
||||
spice_assert(dcc->common.id < MAX_CACHE_CLIENTS);
|
||||
item->sync[dcc->common.id] = serial;
|
||||
cache->sync[dcc->common.id] = serial;
|
||||
*lossy = item->lossy;
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
return !!item;
|
||||
}
|
||||
|
||||
static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc)
|
||||
{
|
||||
int hit;
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
hit = FUNC_NAME(unlocked_hit)(cache,id,lossy, dcc);
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
return hit;
|
||||
}
|
||||
|
||||
static int FUNC_NAME(unlocked_set_lossy)(CACHE *cache, uint64_t id, int lossy)
|
||||
{
|
||||
NewCacheItem *item;
|
||||
|
||||
item = cache->hash_table[CACHE_HASH_KEY(id)];
|
||||
|
||||
while (item) {
|
||||
if (item->id == id) {
|
||||
item->lossy = lossy;
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
return !!item;
|
||||
}
|
||||
|
||||
static int FUNC_NAME(unlocked_add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, DisplayChannelClient *dcc)
|
||||
{
|
||||
NewCacheItem *item;
|
||||
uint64_t serial;
|
||||
int key;
|
||||
|
||||
spice_assert(size > 0);
|
||||
|
||||
item = spice_new(NewCacheItem, 1);
|
||||
serial = red_channel_client_get_message_serial(&dcc->common.base);
|
||||
|
||||
if (cache->generation != dcc->CACH_GENERATION) {
|
||||
if (!dcc->pending_pixmaps_sync) {
|
||||
red_channel_client_pipe_add_type(
|
||||
&dcc->common.base, 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[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;
|
||||
display_channel_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
|
||||
free(tail);
|
||||
}
|
||||
++cache->items;
|
||||
item->next = cache->hash_table[(key = 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;
|
||||
}
|
||||
|
||||
static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
|
||||
{
|
||||
NewCacheItem *item;
|
||||
|
||||
if (cache->freezed) {
|
||||
cache->lru.next = cache->freezed_head;
|
||||
cache->lru.prev = cache->freezed_tail;
|
||||
cache->freezed = FALSE;
|
||||
}
|
||||
|
||||
while ((item = (NewCacheItem *)ring_get_head(&cache->lru))) {
|
||||
ring_remove(&item->lru_link);
|
||||
free(item);
|
||||
}
|
||||
memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE);
|
||||
|
||||
cache->available = cache->size;
|
||||
cache->items = 0;
|
||||
}
|
||||
|
||||
static void FUNC_NAME(reset)(CACHE *cache, DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data)
|
||||
{
|
||||
uint8_t wait_count;
|
||||
uint64_t serial;
|
||||
uint32_t i;
|
||||
|
||||
serial = red_channel_client_get_message_serial(&dcc->common.base);
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
PRIVATE_FUNC_NAME(clear)(cache);
|
||||
|
||||
dcc->CACH_GENERATION = ++cache->generation;
|
||||
cache->generation_initiator.client = dcc->common.id;
|
||||
cache->generation_initiator.message = serial;
|
||||
cache->sync[dcc->common.id] = serial;
|
||||
|
||||
wait_count = 0;
|
||||
for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
|
||||
if (cache->sync[i] && i != dcc->common.id) {
|
||||
sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY;
|
||||
sync_data->wait_list[wait_count].channel_id = i;
|
||||
sync_data->wait_list[wait_count++].message_serial = cache->sync[i];
|
||||
}
|
||||
}
|
||||
sync_data->wait_count = wait_count;
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
static int FUNC_NAME(freeze)(CACHE *cache)
|
||||
{
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
|
||||
if (cache->freezed) {
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cache->freezed_head = cache->lru.next;
|
||||
cache->freezed_tail = cache->lru.prev;
|
||||
ring_init(&cache->lru);
|
||||
memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE);
|
||||
cache->available = -1;
|
||||
cache->freezed = TRUE;
|
||||
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void FUNC_NAME(destroy)(CACHE *cache)
|
||||
{
|
||||
spice_assert(cache);
|
||||
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
PRIVATE_FUNC_NAME(clear)(cache);
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
#undef CACHE_NAME
|
||||
#undef CACHE_HASH_KEY
|
||||
#undef CACHE_HASH_SIZE
|
||||
#undef CACHE_INVAL_TYPE
|
||||
#undef CACHE_MAX_CLIENT_SIZE
|
||||
#undef FUNC_NAME
|
||||
#undef VAR_NAME
|
||||
#undef CHANNEL
|
||||
#undef CHANNEL_FROM_RCC
|
||||
@ -92,6 +92,7 @@
|
||||
#include "red_time.h"
|
||||
#include "spice_bitmap_utils.h"
|
||||
#include "spice_image_cache.h"
|
||||
#include "pixmap-cache.h"
|
||||
|
||||
//#define COMPRESS_STAT
|
||||
//#define DUMP_BITMAP
|
||||
@ -306,20 +307,8 @@ typedef struct VerbItem {
|
||||
uint16_t verb;
|
||||
} VerbItem;
|
||||
|
||||
#define MAX_CACHE_CLIENTS 4
|
||||
#define MAX_LZ_ENCODERS MAX_CACHE_CLIENTS
|
||||
|
||||
typedef struct NewCacheItem NewCacheItem;
|
||||
|
||||
struct NewCacheItem {
|
||||
RingItem lru_link;
|
||||
NewCacheItem *next;
|
||||
uint64_t id;
|
||||
uint64_t sync[MAX_CACHE_CLIENTS];
|
||||
size_t size;
|
||||
int lossy;
|
||||
};
|
||||
|
||||
typedef struct CacheItem CacheItem;
|
||||
|
||||
struct CacheItem {
|
||||
@ -388,11 +377,6 @@ typedef struct LocalCursor {
|
||||
#define WIDE_CLIENT_ACK_WINDOW 40
|
||||
#define NARROW_CLIENT_ACK_WINDOW 20
|
||||
|
||||
#define BITS_CACHE_HASH_SHIFT 10
|
||||
#define BITS_CACHE_HASH_SIZE (1 << BITS_CACHE_HASH_SHIFT)
|
||||
#define BITS_CACHE_HASH_MASK (BITS_CACHE_HASH_SIZE - 1)
|
||||
#define BITS_CACHE_HASH_KEY(id) ((id) & BITS_CACHE_HASH_MASK)
|
||||
|
||||
#define CLIENT_CURSOR_CACHE_SIZE 256
|
||||
|
||||
#define CURSOR_CACHE_HASH_SHIFT 8
|
||||
@ -425,7 +409,6 @@ typedef struct ImageItem {
|
||||
typedef struct Drawable Drawable;
|
||||
|
||||
typedef struct DisplayChannel DisplayChannel;
|
||||
typedef struct DisplayChannelClient DisplayChannelClient;
|
||||
|
||||
enum {
|
||||
STREAM_FRAME_NONE,
|
||||
@ -514,35 +497,6 @@ static const int BITMAP_FMP_BYTES_PER_PIXEL[] = {0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 1
|
||||
(bitmap_fmt_is_rgb(f) && \
|
||||
((f) != SPICE_BITMAP_FMT_8BIT_A))
|
||||
|
||||
pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
Ring pixmap_cache_list = {&pixmap_cache_list, &pixmap_cache_list};
|
||||
|
||||
typedef struct PixmapCache PixmapCache;
|
||||
struct PixmapCache {
|
||||
RingItem base;
|
||||
pthread_mutex_t lock;
|
||||
uint8_t id;
|
||||
uint32_t refs;
|
||||
NewCacheItem *hash_table[BITS_CACHE_HASH_SIZE];
|
||||
Ring lru;
|
||||
int64_t available;
|
||||
int64_t size;
|
||||
int32_t items;
|
||||
|
||||
int freezed;
|
||||
RingItem *freezed_head;
|
||||
RingItem *freezed_tail;
|
||||
|
||||
uint32_t generation;
|
||||
struct {
|
||||
uint8_t client;
|
||||
uint64_t message;
|
||||
} generation_initiator;
|
||||
uint64_t sync[MAX_CACHE_CLIENTS]; // here CLIENTS refer to different channel
|
||||
// clients of the same client
|
||||
RedClient *client;
|
||||
};
|
||||
|
||||
#define NUM_STREAMS 50
|
||||
|
||||
typedef struct WaitForChannels {
|
||||
@ -1046,7 +1000,6 @@ static inline void red_detach_stream(RedWorker *worker, Stream *stream, int deta
|
||||
static void red_stop_stream(RedWorker *worker, Stream *stream);
|
||||
static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
|
||||
static inline void display_begin_send_message(RedChannelClient *rcc);
|
||||
static void red_release_pixmap_cache(DisplayChannelClient *dcc);
|
||||
static void red_release_glz(DisplayChannelClient *dcc);
|
||||
static void red_freeze_glz(DisplayChannelClient *dcc);
|
||||
static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id,
|
||||
@ -1628,10 +1581,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
|
||||
}
|
||||
}
|
||||
|
||||
#define CLIENT_PIXMAPS_CACHE
|
||||
#include "red_client_shared_cache.h"
|
||||
#undef CLIENT_PIXMAPS_CACHE
|
||||
|
||||
#define CLIENT_CURSOR_CACHE
|
||||
#include "red_client_cache.h"
|
||||
#undef CLIENT_CURSOR_CACHE
|
||||
@ -6400,6 +6349,70 @@ static inline int red_compress_image(DisplayChannelClient *dcc,
|
||||
}
|
||||
}
|
||||
|
||||
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(&dcc->common.base);
|
||||
|
||||
if (cache->generation != dcc->pixmap_cache_generation) {
|
||||
if (!dcc->pending_pixmaps_sync) {
|
||||
red_channel_client_pipe_add_type(
|
||||
&dcc->common.base, 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;
|
||||
display_channel_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;
|
||||
}
|
||||
|
||||
static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
|
||||
SpiceImage *image, SpiceImage *io_image,
|
||||
int is_lossy)
|
||||
@ -6410,9 +6423,9 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
|
||||
if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
|
||||
spice_assert(image->descriptor.width * image->descriptor.height > 0);
|
||||
if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) {
|
||||
if (pixmap_cache_unlocked_add(dcc->pixmap_cache, image->descriptor.id,
|
||||
image->descriptor.width * image->descriptor.height, is_lossy,
|
||||
dcc)) {
|
||||
if (dcc_pixmap_cache_unlocked_add(dcc, image->descriptor.id,
|
||||
image->descriptor.width * image->descriptor.height,
|
||||
is_lossy)) {
|
||||
io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
|
||||
dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] =
|
||||
image->descriptor.id;
|
||||
@ -6426,6 +6439,43 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
|
||||
}
|
||||
}
|
||||
|
||||
static int dcc_pixmap_cache_unlocked_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy)
|
||||
{
|
||||
PixmapCache *cache = dcc->pixmap_cache;
|
||||
NewCacheItem *item;
|
||||
uint64_t serial;
|
||||
|
||||
serial = red_channel_client_get_message_serial(&dcc->common.base);
|
||||
item = cache->hash_table[BITS_CACHE_HASH_KEY(id)];
|
||||
|
||||
while (item) {
|
||||
if (item->id == id) {
|
||||
ring_remove(&item->lru_link);
|
||||
ring_add(&cache->lru, &item->lru_link);
|
||||
spice_assert(dcc->common.id < MAX_CACHE_CLIENTS);
|
||||
item->sync[dcc->common.id] = serial;
|
||||
cache->sync[dcc->common.id] = serial;
|
||||
*lossy = item->lossy;
|
||||
break;
|
||||
}
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
return !!item;
|
||||
}
|
||||
|
||||
static int dcc_pixmap_cache_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy)
|
||||
{
|
||||
int hit;
|
||||
PixmapCache *cache = dcc->pixmap_cache;
|
||||
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
hit = dcc_pixmap_cache_unlocked_hit(dcc, id, lossy);
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
||||
typedef enum {
|
||||
FILL_BITS_TYPE_INVALID,
|
||||
FILL_BITS_TYPE_CACHE,
|
||||
@ -6461,8 +6511,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
|
||||
|
||||
if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
|
||||
int lossy_cache_item;
|
||||
if (pixmap_cache_unlocked_hit(dcc->pixmap_cache, image.descriptor.id,
|
||||
&lossy_cache_item, dcc)) {
|
||||
if (dcc_pixmap_cache_unlocked_hit(dcc, image.descriptor.id, &lossy_cache_item)) {
|
||||
dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] =
|
||||
image.descriptor.id;
|
||||
if (can_lossy || !lossy_cache_item) {
|
||||
@ -6712,8 +6761,7 @@ static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *
|
||||
int is_hit_lossy;
|
||||
|
||||
out_data->id = image->descriptor.id;
|
||||
if (pixmap_cache_hit(dcc->pixmap_cache, image->descriptor.id,
|
||||
&is_hit_lossy, dcc)) {
|
||||
if (dcc_pixmap_cache_hit(dcc, image->descriptor.id, &is_hit_lossy)) {
|
||||
out_data->type = BITMAP_DATA_TYPE_CACHE;
|
||||
if (is_hit_lossy) {
|
||||
return TRUE;
|
||||
@ -8134,8 +8182,7 @@ static inline void display_channel_send_free_list(RedChannelClient *rcc)
|
||||
* But all this message pixmaps cache references used its old serial.
|
||||
* we use pixmap_cache_items to collect these pixmaps, and we update their serial
|
||||
* by calling pixmap_cache_hit. */
|
||||
pixmap_cache_hit(dcc->pixmap_cache, dcc->send_data.pixmap_cache_items[i],
|
||||
&dummy, dcc);
|
||||
dcc_pixmap_cache_hit(dcc, dcc->send_data.pixmap_cache_items[i], &dummy);
|
||||
}
|
||||
|
||||
if (free_list->wait.header.wait_count) {
|
||||
@ -8514,6 +8561,34 @@ static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc,
|
||||
spice_marshall_msg_wait_for_channels(base_marshaller, &wait);
|
||||
}
|
||||
|
||||
static void dcc_pixmap_cache_reset(DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data)
|
||||
{
|
||||
PixmapCache *cache = dcc->pixmap_cache;
|
||||
uint8_t wait_count;
|
||||
uint64_t serial;
|
||||
uint32_t i;
|
||||
|
||||
serial = red_channel_client_get_message_serial(&dcc->common.base);
|
||||
pthread_mutex_lock(&cache->lock);
|
||||
pixmap_cache_clear(cache);
|
||||
|
||||
dcc->pixmap_cache_generation = ++cache->generation;
|
||||
cache->generation_initiator.client = dcc->common.id;
|
||||
cache->generation_initiator.message = serial;
|
||||
cache->sync[dcc->common.id] = serial;
|
||||
|
||||
wait_count = 0;
|
||||
for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
|
||||
if (cache->sync[i] && i != dcc->common.id) {
|
||||
sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY;
|
||||
sync_data->wait_list[wait_count].channel_id = i;
|
||||
sync_data->wait_list[wait_count++].message_serial = cache->sync[i];
|
||||
}
|
||||
}
|
||||
sync_data->wait_count = wait_count;
|
||||
pthread_mutex_unlock(&cache->lock);
|
||||
}
|
||||
|
||||
static void display_channel_marshall_reset_cache(RedChannelClient *rcc,
|
||||
SpiceMarshaller *base_marshaller)
|
||||
{
|
||||
@ -8521,7 +8596,7 @@ static void display_channel_marshall_reset_cache(RedChannelClient *rcc,
|
||||
SpiceMsgWaitForChannels wait;
|
||||
|
||||
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL);
|
||||
pixmap_cache_reset(dcc->pixmap_cache, dcc, &wait);
|
||||
dcc_pixmap_cache_reset(dcc, &wait);
|
||||
|
||||
spice_marshall_msg_display_inval_all_pixmaps(base_marshaller,
|
||||
&wait);
|
||||
@ -9137,7 +9212,8 @@ static void display_channel_client_on_disconnect(RedChannelClient *rcc)
|
||||
#ifdef COMPRESS_STAT
|
||||
print_compress_stats(display_channel);
|
||||
#endif
|
||||
red_release_pixmap_cache(dcc);
|
||||
pixmap_cache_unref(dcc->pixmap_cache);
|
||||
dcc->pixmap_cache = NULL;
|
||||
red_release_glz(dcc);
|
||||
red_reset_palette_cache(dcc);
|
||||
free(dcc->send_data.stream_outbuf);
|
||||
@ -9705,67 +9781,12 @@ static void red_release_glz(DisplayChannelClient *dcc)
|
||||
free(shared_dict);
|
||||
}
|
||||
|
||||
static PixmapCache *red_create_pixmap_cache(RedClient *client, uint8_t id, int64_t size)
|
||||
{
|
||||
PixmapCache *cache = spice_new0(PixmapCache, 1);
|
||||
ring_item_init(&cache->base);
|
||||
pthread_mutex_init(&cache->lock, NULL);
|
||||
cache->id = id;
|
||||
cache->refs = 1;
|
||||
ring_init(&cache->lru);
|
||||
cache->available = size;
|
||||
cache->size = size;
|
||||
cache->client = client;
|
||||
return cache;
|
||||
}
|
||||
|
||||
static PixmapCache *red_get_pixmap_cache(RedClient *client, uint8_t id, int64_t size)
|
||||
{
|
||||
PixmapCache *ret = NULL;
|
||||
RingItem *now;
|
||||
pthread_mutex_lock(&cache_lock);
|
||||
|
||||
now = &pixmap_cache_list;
|
||||
while ((now = ring_next(&pixmap_cache_list, now))) {
|
||||
PixmapCache *cache = (PixmapCache *)now;
|
||||
if ((cache->client == client) && (cache->id == id)) {
|
||||
ret = cache;
|
||||
ret->refs++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
ret = red_create_pixmap_cache(client, id, size);
|
||||
ring_add(&pixmap_cache_list, &ret->base);
|
||||
}
|
||||
pthread_mutex_unlock(&cache_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void red_release_pixmap_cache(DisplayChannelClient *dcc)
|
||||
{
|
||||
PixmapCache *cache;
|
||||
if (!(cache = dcc->pixmap_cache)) {
|
||||
return;
|
||||
}
|
||||
dcc->pixmap_cache = NULL;
|
||||
pthread_mutex_lock(&cache_lock);
|
||||
if (--cache->refs) {
|
||||
pthread_mutex_unlock(&cache_lock);
|
||||
return;
|
||||
}
|
||||
ring_remove(&cache->base);
|
||||
pthread_mutex_unlock(&cache_lock);
|
||||
pixmap_cache_destroy(cache);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
static int display_channel_init_cache(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
|
||||
{
|
||||
spice_assert(!dcc->pixmap_cache);
|
||||
return !!(dcc->pixmap_cache = red_get_pixmap_cache(dcc->common.base.client,
|
||||
init_info->pixmap_cache_id,
|
||||
init_info->pixmap_cache_size));
|
||||
return !!(dcc->pixmap_cache = pixmap_cache_get(dcc->common.base.client,
|
||||
init_info->pixmap_cache_id,
|
||||
init_info->pixmap_cache_size));
|
||||
}
|
||||
|
||||
static int display_channel_init_glz_dictionary(DisplayChannelClient *dcc,
|
||||
@ -9899,8 +9920,8 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s
|
||||
* channel client that froze the cache on the src size receives the migrate
|
||||
* data and unfreezes the cache by setting its size > 0 and by triggering
|
||||
* pixmap_cache_reset */
|
||||
dcc->pixmap_cache = red_get_pixmap_cache(dcc->common.base.client,
|
||||
migrate_data->pixmap_cache_id, -1);
|
||||
dcc->pixmap_cache = pixmap_cache_get(dcc->common.base.client,
|
||||
migrate_data->pixmap_cache_id, -1);
|
||||
if (!dcc->pixmap_cache) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user