mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 22:48:19 +00:00
139 lines
3.2 KiB
C
139 lines
3.2 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include "spice_image_cache.h"
|
|
|
|
static ImageCacheItem *image_cache_find(ImageCache *cache, uint64_t id)
|
|
{
|
|
ImageCacheItem *item = cache->hash_table[id % IMAGE_CACHE_HASH_SIZE];
|
|
|
|
while (item) {
|
|
if (item->id == id) {
|
|
return item;
|
|
}
|
|
item = item->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int image_cache_hit(ImageCache *cache, uint64_t id)
|
|
{
|
|
ImageCacheItem *item;
|
|
if (!(item = image_cache_find(cache, id))) {
|
|
return FALSE;
|
|
}
|
|
#ifdef IMAGE_CACHE_AGE
|
|
item->age = cache->age;
|
|
#endif
|
|
ring_remove(&item->lru_link);
|
|
ring_add(&cache->lru, &item->lru_link);
|
|
return TRUE;
|
|
}
|
|
|
|
static void image_cache_remove(ImageCache *cache, ImageCacheItem *item)
|
|
{
|
|
ImageCacheItem **now;
|
|
|
|
now = &cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
|
|
for (;;) {
|
|
spice_assert(*now);
|
|
if (*now == item) {
|
|
*now = item->next;
|
|
break;
|
|
}
|
|
now = &(*now)->next;
|
|
}
|
|
ring_remove(&item->lru_link);
|
|
pixman_image_unref(item->image);
|
|
free(item);
|
|
#ifndef IMAGE_CACHE_AGE
|
|
cache->num_items--;
|
|
#endif
|
|
}
|
|
|
|
#define IMAGE_CACHE_MAX_ITEMS 2
|
|
|
|
static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, pixman_image_t *image)
|
|
{
|
|
ImageCache *cache = (ImageCache *)spice_cache;
|
|
ImageCacheItem *item;
|
|
|
|
#ifndef IMAGE_CACHE_AGE
|
|
if (cache->num_items == IMAGE_CACHE_MAX_ITEMS) {
|
|
ImageCacheItem *tail = (ImageCacheItem *)ring_get_tail(&cache->lru);
|
|
spice_assert(tail);
|
|
image_cache_remove(cache, tail);
|
|
}
|
|
#endif
|
|
|
|
item = spice_new(ImageCacheItem, 1);
|
|
item->id = id;
|
|
#ifdef IMAGE_CACHE_AGE
|
|
item->age = cache->age;
|
|
#else
|
|
cache->num_items++;
|
|
#endif
|
|
item->image = pixman_image_ref(image);
|
|
ring_item_init(&item->lru_link);
|
|
|
|
item->next = cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE];
|
|
cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE] = item;
|
|
|
|
ring_add(&cache->lru, &item->lru_link);
|
|
}
|
|
|
|
static pixman_image_t *image_cache_get(SpiceImageCache *spice_cache, uint64_t id)
|
|
{
|
|
ImageCache *cache = (ImageCache *)spice_cache;
|
|
|
|
ImageCacheItem *item = image_cache_find(cache, id);
|
|
if (!item) {
|
|
spice_error("not found");
|
|
}
|
|
return pixman_image_ref(item->image);
|
|
}
|
|
|
|
void image_cache_init(ImageCache *cache)
|
|
{
|
|
static SpiceImageCacheOps image_cache_ops = {
|
|
image_cache_put,
|
|
image_cache_get,
|
|
};
|
|
|
|
cache->base.ops = &image_cache_ops;
|
|
memset(cache->hash_table, 0, sizeof(cache->hash_table));
|
|
ring_init(&cache->lru);
|
|
#ifdef IMAGE_CACHE_AGE
|
|
cache->age = 0;
|
|
#else
|
|
cache->num_items = 0;
|
|
#endif
|
|
}
|
|
|
|
void image_cache_reset(ImageCache *cache)
|
|
{
|
|
ImageCacheItem *item;
|
|
|
|
while ((item = (ImageCacheItem *)ring_get_head(&cache->lru))) {
|
|
image_cache_remove(cache, item);
|
|
}
|
|
#ifdef IMAGE_CACHE_AGE
|
|
cache->age = 0;
|
|
#endif
|
|
}
|
|
|
|
#define IMAGE_CACHE_DEPTH 4
|
|
|
|
void image_cache_aging(ImageCache *cache)
|
|
{
|
|
#ifdef IMAGE_CACHE_AGE
|
|
ImageCacheItem *item;
|
|
|
|
cache->age++;
|
|
while ((item = (ImageCacheItem *)ring_get_tail(&cache->lru)) &&
|
|
cache->age - item->age > IMAGE_CACHE_DEPTH) {
|
|
image_cache_remove(cache, item);
|
|
}
|
|
#endif
|
|
}
|