1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2003 VMware, Inc. 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the 8848b8605Smrg * "Software"), to deal in the Software without restriction, including 9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 12848b8605Smrg * the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice (including the 15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 16848b8605Smrg * of the Software. 17848b8605Smrg * 18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25848b8605Smrg * 26848b8605Smrg **************************************************************************/ 27848b8605Smrg 28848b8605Smrg 29848b8605Smrg#include "main/glheader.h" 30848b8605Smrg#include "main/mtypes.h" 31848b8605Smrg#include "main/imports.h" 32848b8605Smrg#include "main/shaderobj.h" 33848b8605Smrg#include "program/prog_cache.h" 34848b8605Smrg#include "program/program.h" 35848b8605Smrg 36848b8605Smrg 37848b8605Smrgstruct cache_item 38848b8605Smrg{ 39848b8605Smrg GLuint hash; 40848b8605Smrg unsigned keysize; 41848b8605Smrg void *key; 42848b8605Smrg struct gl_program *program; 43848b8605Smrg struct cache_item *next; 44848b8605Smrg}; 45848b8605Smrg 46848b8605Smrgstruct gl_program_cache 47848b8605Smrg{ 48848b8605Smrg struct cache_item **items; 49848b8605Smrg struct cache_item *last; 50848b8605Smrg GLuint size, n_items; 51848b8605Smrg}; 52848b8605Smrg 53848b8605Smrg 54848b8605Smrg 55848b8605Smrg/** 56848b8605Smrg * Compute hash index from state key. 57848b8605Smrg */ 58848b8605Smrgstatic GLuint 59848b8605Smrghash_key(const void *key, GLuint key_size) 60848b8605Smrg{ 61848b8605Smrg const GLuint *ikey = (const GLuint *) key; 62848b8605Smrg GLuint hash = 0, i; 63848b8605Smrg 64848b8605Smrg assert(key_size >= 4); 65848b8605Smrg 66848b8605Smrg /* Make a slightly better attempt at a hash function: 67848b8605Smrg */ 68848b8605Smrg for (i = 0; i < key_size / sizeof(*ikey); i++) 69848b8605Smrg { 70848b8605Smrg hash += ikey[i]; 71848b8605Smrg hash += (hash << 10); 72848b8605Smrg hash ^= (hash >> 6); 73848b8605Smrg } 74848b8605Smrg 75848b8605Smrg return hash; 76848b8605Smrg} 77848b8605Smrg 78848b8605Smrg 79848b8605Smrg/** 80b8e80941Smrg * Rebuild/expand the hash table to accommodate more entries 81848b8605Smrg */ 82848b8605Smrgstatic void 83848b8605Smrgrehash(struct gl_program_cache *cache) 84848b8605Smrg{ 85848b8605Smrg struct cache_item **items; 86848b8605Smrg struct cache_item *c, *next; 87848b8605Smrg GLuint size, i; 88848b8605Smrg 89848b8605Smrg cache->last = NULL; 90848b8605Smrg 91848b8605Smrg size = cache->size * 3; 92848b8605Smrg items = malloc(size * sizeof(*items)); 93848b8605Smrg memset(items, 0, size * sizeof(*items)); 94848b8605Smrg 95848b8605Smrg for (i = 0; i < cache->size; i++) 96848b8605Smrg for (c = cache->items[i]; c; c = next) { 97848b8605Smrg next = c->next; 98848b8605Smrg c->next = items[c->hash % size]; 99848b8605Smrg items[c->hash % size] = c; 100848b8605Smrg } 101848b8605Smrg 102848b8605Smrg free(cache->items); 103848b8605Smrg cache->items = items; 104848b8605Smrg cache->size = size; 105848b8605Smrg} 106848b8605Smrg 107848b8605Smrg 108848b8605Smrgstatic void 109848b8605Smrgclear_cache(struct gl_context *ctx, struct gl_program_cache *cache, 110848b8605Smrg GLboolean shader) 111848b8605Smrg{ 112848b8605Smrg struct cache_item *c, *next; 113848b8605Smrg GLuint i; 114848b8605Smrg 115848b8605Smrg cache->last = NULL; 116848b8605Smrg 117848b8605Smrg for (i = 0; i < cache->size; i++) { 118848b8605Smrg for (c = cache->items[i]; c; c = next) { 119848b8605Smrg next = c->next; 120848b8605Smrg free(c->key); 121848b8605Smrg if (shader) { 122848b8605Smrg _mesa_reference_shader_program(ctx, 123848b8605Smrg (struct gl_shader_program **)&c->program, 124848b8605Smrg NULL); 125848b8605Smrg } else { 126848b8605Smrg _mesa_reference_program(ctx, &c->program, NULL); 127848b8605Smrg } 128848b8605Smrg free(c); 129848b8605Smrg } 130848b8605Smrg cache->items[i] = NULL; 131848b8605Smrg } 132848b8605Smrg 133848b8605Smrg 134848b8605Smrg cache->n_items = 0; 135848b8605Smrg} 136848b8605Smrg 137848b8605Smrg 138848b8605Smrg 139848b8605Smrgstruct gl_program_cache * 140848b8605Smrg_mesa_new_program_cache(void) 141848b8605Smrg{ 142848b8605Smrg struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache); 143848b8605Smrg if (cache) { 144848b8605Smrg cache->size = 17; 145848b8605Smrg cache->items = 146b8e80941Smrg calloc(cache->size, sizeof(struct cache_item *)); 147848b8605Smrg if (!cache->items) { 148848b8605Smrg free(cache); 149848b8605Smrg return NULL; 150848b8605Smrg } 151848b8605Smrg } 152848b8605Smrg return cache; 153848b8605Smrg} 154848b8605Smrg 155848b8605Smrg 156848b8605Smrgvoid 157848b8605Smrg_mesa_delete_program_cache(struct gl_context *ctx, struct gl_program_cache *cache) 158848b8605Smrg{ 159848b8605Smrg clear_cache(ctx, cache, GL_FALSE); 160848b8605Smrg free(cache->items); 161848b8605Smrg free(cache); 162848b8605Smrg} 163848b8605Smrg 164848b8605Smrgvoid 165848b8605Smrg_mesa_delete_shader_cache(struct gl_context *ctx, 166848b8605Smrg struct gl_program_cache *cache) 167848b8605Smrg{ 168848b8605Smrg clear_cache(ctx, cache, GL_TRUE); 169848b8605Smrg free(cache->items); 170848b8605Smrg free(cache); 171848b8605Smrg} 172848b8605Smrg 173848b8605Smrg 174848b8605Smrgstruct gl_program * 175848b8605Smrg_mesa_search_program_cache(struct gl_program_cache *cache, 176848b8605Smrg const void *key, GLuint keysize) 177848b8605Smrg{ 178848b8605Smrg if (cache->last && 179848b8605Smrg cache->last->keysize == keysize && 180848b8605Smrg memcmp(cache->last->key, key, keysize) == 0) { 181848b8605Smrg return cache->last->program; 182848b8605Smrg } 183848b8605Smrg else { 184848b8605Smrg const GLuint hash = hash_key(key, keysize); 185848b8605Smrg struct cache_item *c; 186848b8605Smrg 187848b8605Smrg for (c = cache->items[hash % cache->size]; c; c = c->next) { 188848b8605Smrg if (c->hash == hash && 189848b8605Smrg c->keysize == keysize && 190848b8605Smrg memcmp(c->key, key, keysize) == 0) { 191848b8605Smrg 192848b8605Smrg cache->last = c; 193848b8605Smrg return c->program; 194848b8605Smrg } 195848b8605Smrg } 196848b8605Smrg 197848b8605Smrg return NULL; 198848b8605Smrg } 199848b8605Smrg} 200848b8605Smrg 201848b8605Smrg 202848b8605Smrgvoid 203848b8605Smrg_mesa_program_cache_insert(struct gl_context *ctx, 204848b8605Smrg struct gl_program_cache *cache, 205848b8605Smrg const void *key, GLuint keysize, 206848b8605Smrg struct gl_program *program) 207848b8605Smrg{ 208848b8605Smrg const GLuint hash = hash_key(key, keysize); 209848b8605Smrg struct cache_item *c = CALLOC_STRUCT(cache_item); 210848b8605Smrg 211848b8605Smrg c->hash = hash; 212848b8605Smrg 213848b8605Smrg c->key = malloc(keysize); 214848b8605Smrg memcpy(c->key, key, keysize); 215848b8605Smrg c->keysize = keysize; 216848b8605Smrg 217848b8605Smrg c->program = program; /* no refcount change */ 218848b8605Smrg 219848b8605Smrg if (cache->n_items > cache->size * 1.5) { 220848b8605Smrg if (cache->size < 1000) 221848b8605Smrg rehash(cache); 222848b8605Smrg else 223848b8605Smrg clear_cache(ctx, cache, GL_FALSE); 224848b8605Smrg } 225848b8605Smrg 226848b8605Smrg cache->n_items++; 227848b8605Smrg c->next = cache->items[hash % cache->size]; 228848b8605Smrg cache->items[hash % cache->size] = c; 229848b8605Smrg} 230848b8605Smrg 231848b8605Smrgvoid 232848b8605Smrg_mesa_shader_cache_insert(struct gl_context *ctx, 233848b8605Smrg struct gl_program_cache *cache, 234848b8605Smrg const void *key, GLuint keysize, 235848b8605Smrg struct gl_shader_program *program) 236848b8605Smrg{ 237848b8605Smrg const GLuint hash = hash_key(key, keysize); 238848b8605Smrg struct cache_item *c = CALLOC_STRUCT(cache_item); 239848b8605Smrg 240848b8605Smrg c->hash = hash; 241848b8605Smrg 242848b8605Smrg c->key = malloc(keysize); 243848b8605Smrg memcpy(c->key, key, keysize); 244848b8605Smrg c->keysize = keysize; 245848b8605Smrg 246848b8605Smrg c->program = (struct gl_program *)program; /* no refcount change */ 247848b8605Smrg 248848b8605Smrg if (cache->n_items > cache->size * 1.5) { 249848b8605Smrg if (cache->size < 1000) 250848b8605Smrg rehash(cache); 251848b8605Smrg else 252848b8605Smrg clear_cache(ctx, cache, GL_TRUE); 253848b8605Smrg } 254848b8605Smrg 255848b8605Smrg cache->n_items++; 256848b8605Smrg c->next = cache->items[hash % cache->size]; 257848b8605Smrg cache->items[hash % cache->size] = c; 258848b8605Smrg} 259