From: Stefan Dösinger stefan@codeweavers.com
---
The exit(1) should obviously go before merging this. --- libs/vkd3d/cache.c | 122 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/cache.c b/libs/vkd3d/cache.c index c1d155746..250d3b825 100644 --- a/libs/vkd3d/cache.c +++ b/libs/vkd3d/cache.c @@ -73,6 +73,16 @@ static int vkd3d_shader_cache_compare_key(const void *key, const struct rb_entry return 0; }
+static void vkd3d_shader_cache_add_item(struct vkd3d_shader_cache *cache, struct shader_cache_entry *e) +{ + rb_put(&cache->tree, &e->d.hash, &e->entry); +} + +static void vkd3d_shader_cache_remove_item(struct vkd3d_shader_cache *cache, struct shader_cache_entry *e) +{ + rb_remove(&cache->tree, &e->entry); +} + int vkd3d_shader_cache_open(const char *name, const struct vkd3d_shader_cache_desc *desc, struct vkd3d_shader_cache **cache) { @@ -154,11 +164,119 @@ void vkd3d_shader_cache_close(struct vkd3d_shader_cache *cache) vkd3d_free(cache); }
+/* As the name implies this is taken from moltenvk. */ +#define MVKHASH_SEED 5381 +static inline uint64_t mvkHash64(const uint64_t *pVals, size_t count, uint64_t seed) +{ + uint64_t hash = seed; + for (size_t i = 0; i < count; ++i) + hash = ((hash << 5) + hash) ^ pVals[i]; + + return hash; +} + +static uint64_t hash_key(const void *key, size_t size) +{ + uint64_t last = 0, ret; + + ret = mvkHash64(key, size / sizeof(uint64_t), MVKHASH_SEED); + if (size % sizeof(uint64_t)) + { + const char *c = key; + /* FIXME: Endianess? */ + c += align(size, sizeof(uint64_t)) - sizeof(uint64_t); + memcpy(&last, c, size % sizeof(uint64_t)); + ret = mvkHash64(&last, 1, ret); + } + return ret; +} + +static bool vkd3d_shader_cache_trylock(struct vkd3d_shader_cache *cache) +{ + /* Not yet implemented. */ + return true; +} + +static void vkd3d_shader_cache_unlock(struct vkd3d_shader_cache *cache) +{ + /* Not yet implemented. */ +} + int vkd3d_shader_cache_put(struct vkd3d_shader_cache *cache, const void *key, uint32_t key_size, const void *value, uint32_t value_size) { - FIXME("%p, %p, %#x, %p, %#x stub!\n", cache, key, key_size, value, value_size); - return VKD3D_ERROR_NOT_IMPLEMENTED; + struct shader_cache_entry *e; + struct rb_entry *entry; + enum vkd3d_result ret; + uint64_t hash; + + TRACE("%p, %p, %#x, %p, %#x.\n", cache, key, key_size, value, value_size); + + if (!vkd3d_shader_cache_trylock(cache)) + { + WARN("Cache lock not available.\n"); + return VKD3D_ERROR_LOCK_NOT_AVAILABLE; + } + + hash = hash_key(key, key_size); + entry = rb_get(&cache->tree, &hash); + e = entry ? RB_ENTRY_VALUE(entry, struct shader_cache_entry, entry) : NULL; + + if (e && (e->d.key_size != key_size || memcmp(e->payload, key, key_size))) + { + FIXME("Actual case of hash collission found.\n"); + exit(1); + } + + if (e && e->d.value_size >= value_size) + { + if (e->d.value_size == value_size && !memcmp(e->payload + e->d.key_size, value, value_size)) + { + TRACE("No-op store call, existing item unchanged.\n"); + } + else + { + e->d.value_size = value_size; + memcpy(e->payload + e->d.key_size, value, value_size); + TRACE("Cache item %"PRIu64" overwritten.\n", hash); + } + ret = VKD3D_OK; + goto unlock; + } + else if (e) + { + vkd3d_free(e->payload); + vkd3d_shader_cache_remove_item(cache, e); + vkd3d_free(e); + } + + e = vkd3d_calloc(1, sizeof(*e)); + if (!e) + { + ret = VKD3D_ERROR_OUT_OF_MEMORY; + goto unlock; + } + e->payload = vkd3d_malloc(key_size + value_size); + if (!e->payload) + { + vkd3d_free(e); + ret = VKD3D_ERROR_OUT_OF_MEMORY; + goto unlock; + } + + e->d.key_size = key_size; + e->d.value_size = value_size; + e->d.hash = hash; + memcpy(e->payload, key, key_size); + memcpy(e->payload + key_size, value, value_size); + + vkd3d_shader_cache_add_item(cache, e); + TRACE("Cache item %"PRIu64" stored.\n", hash); + ret = VKD3D_OK; + +unlock: + vkd3d_shader_cache_unlock(cache); + return ret; }
int vkd3d_shader_cache_get(struct vkd3d_shader_cache *cache,