Path: blob/21.2-virgl/src/gallium/winsys/virgl/common/virgl_resource_cache.c
4573 views
/*1* Copyright 2019 Collabora Ltd.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*/2223#include "virgl_resource_cache.h"24#include "util/os_time.h"2526/* Checks whether the resource represented by a cache entry is able to hold27* data of the specified size, bind and format.28*/29static bool30virgl_resource_cache_entry_is_compatible(struct virgl_resource_cache_entry *entry,31uint32_t size, uint32_t bind,32uint32_t format, uint32_t flags)33{34return (entry->bind == bind &&35entry->format == format &&36entry->size >= size &&37entry->flags == flags &&38/* We don't want to waste space, so don't reuse resource storage to39* hold much smaller (< 50%) sizes.40*/41entry->size <= size * 2);42}4344static void45virgl_resource_cache_entry_release(struct virgl_resource_cache *cache,46struct virgl_resource_cache_entry *entry)47{48list_del(&entry->head);49cache->entry_release_func(entry, cache->user_data);50}5152static void53virgl_resource_cache_destroy_expired(struct virgl_resource_cache *cache, int64_t now)54{55list_for_each_entry_safe(struct virgl_resource_cache_entry,56entry, &cache->resources, head) {57/* Entries are in non-decreasing timeout order, so we can stop58* at the first entry which hasn't expired.59*/60if (!os_time_timeout(entry->timeout_start, entry->timeout_end, now))61break;62virgl_resource_cache_entry_release(cache, entry);63}64}6566void67virgl_resource_cache_init(struct virgl_resource_cache *cache,68unsigned timeout_usecs,69virgl_resource_cache_entry_is_busy_func is_busy_func,70virgl_resource_cache_entry_release_func destroy_func,71void *user_data)72{73list_inithead(&cache->resources);74cache->timeout_usecs = timeout_usecs;75cache->entry_is_busy_func = is_busy_func;76cache->entry_release_func = destroy_func;77cache->user_data = user_data;78}7980void81virgl_resource_cache_add(struct virgl_resource_cache *cache,82struct virgl_resource_cache_entry *entry)83{84const int64_t now = os_time_get();8586/* Entry should not already be in the cache. */87assert(entry->head.next == NULL);88assert(entry->head.prev == NULL);8990virgl_resource_cache_destroy_expired(cache, now);9192entry->timeout_start = now;93entry->timeout_end = entry->timeout_start + cache->timeout_usecs;94list_addtail(&entry->head, &cache->resources);95}9697struct virgl_resource_cache_entry *98virgl_resource_cache_remove_compatible(struct virgl_resource_cache *cache,99uint32_t size, uint32_t bind,100uint32_t format, uint32_t flags)101{102const int64_t now = os_time_get();103struct virgl_resource_cache_entry *compat_entry = NULL;104bool check_expired = true;105106/* Iterate through the cache to find a compatible resource, while also107* destroying any expired resources we come across.108*/109list_for_each_entry_safe(struct virgl_resource_cache_entry,110entry, &cache->resources, head) {111const bool compatible =112virgl_resource_cache_entry_is_compatible(entry, size, bind, format,113flags);114115if (compatible) {116if (!cache->entry_is_busy_func(entry, cache->user_data))117compat_entry = entry;118119/* We either have found a compatible resource, in which case we are120* done, or the resource is busy, which means resources later in121* the cache list will also be busy, so there is no point in122* searching further.123*/124break;125}126127/* If we aren't using this resource, check to see if it has expired.128* Once we have found the first non-expired resource, we can stop checking129* since the cache holds resources in non-decreasing timeout order.130*/131if (check_expired) {132if (os_time_timeout(entry->timeout_start, entry->timeout_end, now))133virgl_resource_cache_entry_release(cache, entry);134else135check_expired = false;136}137}138139if (compat_entry)140list_del(&compat_entry->head);141142return compat_entry;143}144145void146virgl_resource_cache_flush(struct virgl_resource_cache *cache)147{148list_for_each_entry_safe(struct virgl_resource_cache_entry,149entry, &cache->resources, head) {150virgl_resource_cache_entry_release(cache, entry);151}152}153154155