13464ebd5Sriastradh/************************************************************************** 27ec681f3Smrg * 3af69d88dSmrg * Copyright 2003 VMware, Inc. 43464ebd5Sriastradh * All Rights Reserved. 57ec681f3Smrg * 63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 73464ebd5Sriastradh * copy of this software and associated documentation files (the 83464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including 93464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish, 103464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to 113464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to 123464ebd5Sriastradh * the following conditions: 137ec681f3Smrg * 143464ebd5Sriastradh * The above copyright notice and this permission notice (including the 153464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions 163464ebd5Sriastradh * of the Software. 177ec681f3Smrg * 183464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 193464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 203464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21af69d88dSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 223464ebd5Sriastradh * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 233464ebd5Sriastradh * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 243464ebd5Sriastradh * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257ec681f3Smrg * 263464ebd5Sriastradh **************************************************************************/ 273464ebd5Sriastradh 283464ebd5Sriastradh 293464ebd5Sriastradh#include "main/glheader.h" 303464ebd5Sriastradh#include "main/mtypes.h" 317ec681f3Smrg 323464ebd5Sriastradh#include "main/shaderobj.h" 333464ebd5Sriastradh#include "program/prog_cache.h" 343464ebd5Sriastradh#include "program/program.h" 357ec681f3Smrg#include "util/u_memory.h" 363464ebd5Sriastradh 373464ebd5Sriastradh 383464ebd5Sriastradhstruct cache_item 393464ebd5Sriastradh{ 403464ebd5Sriastradh GLuint hash; 41af69d88dSmrg unsigned keysize; 423464ebd5Sriastradh void *key; 433464ebd5Sriastradh struct gl_program *program; 443464ebd5Sriastradh struct cache_item *next; 453464ebd5Sriastradh}; 463464ebd5Sriastradh 473464ebd5Sriastradhstruct gl_program_cache 483464ebd5Sriastradh{ 493464ebd5Sriastradh struct cache_item **items; 503464ebd5Sriastradh struct cache_item *last; 513464ebd5Sriastradh GLuint size, n_items; 523464ebd5Sriastradh}; 533464ebd5Sriastradh 543464ebd5Sriastradh 553464ebd5Sriastradh 563464ebd5Sriastradh/** 573464ebd5Sriastradh * Compute hash index from state key. 583464ebd5Sriastradh */ 593464ebd5Sriastradhstatic GLuint 603464ebd5Sriastradhhash_key(const void *key, GLuint key_size) 613464ebd5Sriastradh{ 623464ebd5Sriastradh const GLuint *ikey = (const GLuint *) key; 633464ebd5Sriastradh GLuint hash = 0, i; 643464ebd5Sriastradh 653464ebd5Sriastradh assert(key_size >= 4); 663464ebd5Sriastradh 673464ebd5Sriastradh /* Make a slightly better attempt at a hash function: 683464ebd5Sriastradh */ 693464ebd5Sriastradh for (i = 0; i < key_size / sizeof(*ikey); i++) 703464ebd5Sriastradh { 713464ebd5Sriastradh hash += ikey[i]; 723464ebd5Sriastradh hash += (hash << 10); 733464ebd5Sriastradh hash ^= (hash >> 6); 743464ebd5Sriastradh } 753464ebd5Sriastradh 763464ebd5Sriastradh return hash; 773464ebd5Sriastradh} 783464ebd5Sriastradh 793464ebd5Sriastradh 803464ebd5Sriastradh/** 8101e04c3fSmrg * Rebuild/expand the hash table to accommodate more entries 823464ebd5Sriastradh */ 833464ebd5Sriastradhstatic void 843464ebd5Sriastradhrehash(struct gl_program_cache *cache) 853464ebd5Sriastradh{ 863464ebd5Sriastradh struct cache_item **items; 873464ebd5Sriastradh struct cache_item *c, *next; 883464ebd5Sriastradh GLuint size, i; 893464ebd5Sriastradh 903464ebd5Sriastradh cache->last = NULL; 913464ebd5Sriastradh 923464ebd5Sriastradh size = cache->size * 3; 93af69d88dSmrg items = malloc(size * sizeof(*items)); 943464ebd5Sriastradh memset(items, 0, size * sizeof(*items)); 953464ebd5Sriastradh 963464ebd5Sriastradh for (i = 0; i < cache->size; i++) 973464ebd5Sriastradh for (c = cache->items[i]; c; c = next) { 983464ebd5Sriastradh next = c->next; 993464ebd5Sriastradh c->next = items[c->hash % size]; 1003464ebd5Sriastradh items[c->hash % size] = c; 1013464ebd5Sriastradh } 1023464ebd5Sriastradh 1033464ebd5Sriastradh free(cache->items); 1043464ebd5Sriastradh cache->items = items; 1053464ebd5Sriastradh cache->size = size; 1063464ebd5Sriastradh} 1073464ebd5Sriastradh 1083464ebd5Sriastradh 1093464ebd5Sriastradhstatic void 1103464ebd5Sriastradhclear_cache(struct gl_context *ctx, struct gl_program_cache *cache, 1113464ebd5Sriastradh GLboolean shader) 1123464ebd5Sriastradh{ 1133464ebd5Sriastradh struct cache_item *c, *next; 1143464ebd5Sriastradh GLuint i; 1157ec681f3Smrg 1163464ebd5Sriastradh cache->last = NULL; 1173464ebd5Sriastradh 1183464ebd5Sriastradh for (i = 0; i < cache->size; i++) { 1193464ebd5Sriastradh for (c = cache->items[i]; c; c = next) { 1203464ebd5Sriastradh next = c->next; 1213464ebd5Sriastradh free(c->key); 1223464ebd5Sriastradh if (shader) { 1233464ebd5Sriastradh _mesa_reference_shader_program(ctx, 1243464ebd5Sriastradh (struct gl_shader_program **)&c->program, 1253464ebd5Sriastradh NULL); 1263464ebd5Sriastradh } else { 1273464ebd5Sriastradh _mesa_reference_program(ctx, &c->program, NULL); 1283464ebd5Sriastradh } 1293464ebd5Sriastradh free(c); 1303464ebd5Sriastradh } 1313464ebd5Sriastradh cache->items[i] = NULL; 1323464ebd5Sriastradh } 1333464ebd5Sriastradh 1343464ebd5Sriastradh 1353464ebd5Sriastradh cache->n_items = 0; 1363464ebd5Sriastradh} 1373464ebd5Sriastradh 1383464ebd5Sriastradh 1393464ebd5Sriastradh 1403464ebd5Sriastradhstruct gl_program_cache * 1413464ebd5Sriastradh_mesa_new_program_cache(void) 1423464ebd5Sriastradh{ 1433464ebd5Sriastradh struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache); 1443464ebd5Sriastradh if (cache) { 1453464ebd5Sriastradh cache->size = 17; 146af69d88dSmrg cache->items = 14701e04c3fSmrg calloc(cache->size, sizeof(struct cache_item *)); 1483464ebd5Sriastradh if (!cache->items) { 1493464ebd5Sriastradh free(cache); 1503464ebd5Sriastradh return NULL; 1513464ebd5Sriastradh } 1523464ebd5Sriastradh } 1533464ebd5Sriastradh return cache; 1543464ebd5Sriastradh} 1553464ebd5Sriastradh 1563464ebd5Sriastradh 1573464ebd5Sriastradhvoid 1583464ebd5Sriastradh_mesa_delete_program_cache(struct gl_context *ctx, struct gl_program_cache *cache) 1593464ebd5Sriastradh{ 1603464ebd5Sriastradh clear_cache(ctx, cache, GL_FALSE); 1613464ebd5Sriastradh free(cache->items); 1623464ebd5Sriastradh free(cache); 1633464ebd5Sriastradh} 1643464ebd5Sriastradh 1653464ebd5Sriastradhvoid 1663464ebd5Sriastradh_mesa_delete_shader_cache(struct gl_context *ctx, 1673464ebd5Sriastradh struct gl_program_cache *cache) 1683464ebd5Sriastradh{ 1693464ebd5Sriastradh clear_cache(ctx, cache, GL_TRUE); 1703464ebd5Sriastradh free(cache->items); 1713464ebd5Sriastradh free(cache); 1723464ebd5Sriastradh} 1733464ebd5Sriastradh 1743464ebd5Sriastradh 1753464ebd5Sriastradhstruct gl_program * 1763464ebd5Sriastradh_mesa_search_program_cache(struct gl_program_cache *cache, 1773464ebd5Sriastradh const void *key, GLuint keysize) 1783464ebd5Sriastradh{ 179af69d88dSmrg if (cache->last && 180af69d88dSmrg cache->last->keysize == keysize && 1813464ebd5Sriastradh memcmp(cache->last->key, key, keysize) == 0) { 1823464ebd5Sriastradh return cache->last->program; 1833464ebd5Sriastradh } 1843464ebd5Sriastradh else { 1853464ebd5Sriastradh const GLuint hash = hash_key(key, keysize); 1863464ebd5Sriastradh struct cache_item *c; 1873464ebd5Sriastradh 1883464ebd5Sriastradh for (c = cache->items[hash % cache->size]; c; c = c->next) { 189af69d88dSmrg if (c->hash == hash && 190af69d88dSmrg c->keysize == keysize && 191af69d88dSmrg memcmp(c->key, key, keysize) == 0) { 192af69d88dSmrg 1933464ebd5Sriastradh cache->last = c; 1943464ebd5Sriastradh return c->program; 1953464ebd5Sriastradh } 1963464ebd5Sriastradh } 1973464ebd5Sriastradh 1983464ebd5Sriastradh return NULL; 1993464ebd5Sriastradh } 2003464ebd5Sriastradh} 2013464ebd5Sriastradh 2023464ebd5Sriastradh 2033464ebd5Sriastradhvoid 2043464ebd5Sriastradh_mesa_program_cache_insert(struct gl_context *ctx, 2053464ebd5Sriastradh struct gl_program_cache *cache, 2063464ebd5Sriastradh const void *key, GLuint keysize, 2073464ebd5Sriastradh struct gl_program *program) 2083464ebd5Sriastradh{ 2093464ebd5Sriastradh const GLuint hash = hash_key(key, keysize); 2103464ebd5Sriastradh struct cache_item *c = CALLOC_STRUCT(cache_item); 2113464ebd5Sriastradh 2123464ebd5Sriastradh c->hash = hash; 2133464ebd5Sriastradh 2143464ebd5Sriastradh c->key = malloc(keysize); 2153464ebd5Sriastradh memcpy(c->key, key, keysize); 216af69d88dSmrg c->keysize = keysize; 2173464ebd5Sriastradh 2183464ebd5Sriastradh c->program = program; /* no refcount change */ 2193464ebd5Sriastradh 2203464ebd5Sriastradh if (cache->n_items > cache->size * 1.5) { 2213464ebd5Sriastradh if (cache->size < 1000) 2223464ebd5Sriastradh rehash(cache); 2237ec681f3Smrg else 2243464ebd5Sriastradh clear_cache(ctx, cache, GL_FALSE); 2253464ebd5Sriastradh } 2263464ebd5Sriastradh 2273464ebd5Sriastradh cache->n_items++; 2283464ebd5Sriastradh c->next = cache->items[hash % cache->size]; 2293464ebd5Sriastradh cache->items[hash % cache->size] = c; 2303464ebd5Sriastradh} 2313464ebd5Sriastradh 2323464ebd5Sriastradhvoid 2333464ebd5Sriastradh_mesa_shader_cache_insert(struct gl_context *ctx, 2343464ebd5Sriastradh struct gl_program_cache *cache, 2353464ebd5Sriastradh const void *key, GLuint keysize, 2363464ebd5Sriastradh struct gl_shader_program *program) 2373464ebd5Sriastradh{ 2383464ebd5Sriastradh const GLuint hash = hash_key(key, keysize); 2393464ebd5Sriastradh struct cache_item *c = CALLOC_STRUCT(cache_item); 2403464ebd5Sriastradh 2413464ebd5Sriastradh c->hash = hash; 2423464ebd5Sriastradh 2433464ebd5Sriastradh c->key = malloc(keysize); 2443464ebd5Sriastradh memcpy(c->key, key, keysize); 245af69d88dSmrg c->keysize = keysize; 2463464ebd5Sriastradh 2473464ebd5Sriastradh c->program = (struct gl_program *)program; /* no refcount change */ 2483464ebd5Sriastradh 2493464ebd5Sriastradh if (cache->n_items > cache->size * 1.5) { 2503464ebd5Sriastradh if (cache->size < 1000) 2513464ebd5Sriastradh rehash(cache); 2523464ebd5Sriastradh else 2533464ebd5Sriastradh clear_cache(ctx, cache, GL_TRUE); 2543464ebd5Sriastradh } 2553464ebd5Sriastradh 2563464ebd5Sriastradh cache->n_items++; 2573464ebd5Sriastradh c->next = cache->items[hash % cache->size]; 2583464ebd5Sriastradh cache->items[hash % cache->size] = c; 2593464ebd5Sriastradh} 260