Home | History | Annotate | Download | only in program
      1 /**************************************************************************
      2  *
      3  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 
     29 #include "main/glheader.h"
     30 #include "main/mtypes.h"
     31 #include "main/imports.h"
     32 #include "main/shaderobj.h"
     33 #include "program/prog_cache.h"
     34 #include "program/program.h"
     35 
     36 
     37 struct cache_item
     38 {
     39    GLuint hash;
     40    void *key;
     41    struct gl_program *program;
     42    struct cache_item *next;
     43 };
     44 
     45 struct gl_program_cache
     46 {
     47    struct cache_item **items;
     48    struct cache_item *last;
     49    GLuint size, n_items;
     50 };
     51 
     52 
     53 
     54 /**
     55  * Compute hash index from state key.
     56  */
     57 static GLuint
     58 hash_key(const void *key, GLuint key_size)
     59 {
     60    const GLuint *ikey = (const GLuint *) key;
     61    GLuint hash = 0, i;
     62 
     63    assert(key_size >= 4);
     64 
     65    /* Make a slightly better attempt at a hash function:
     66     */
     67    for (i = 0; i < key_size / sizeof(*ikey); i++)
     68    {
     69       hash += ikey[i];
     70       hash += (hash << 10);
     71       hash ^= (hash >> 6);
     72    }
     73 
     74    return hash;
     75 }
     76 
     77 
     78 /**
     79  * Rebuild/expand the hash table to accomodate more entries
     80  */
     81 static void
     82 rehash(struct gl_program_cache *cache)
     83 {
     84    struct cache_item **items;
     85    struct cache_item *c, *next;
     86    GLuint size, i;
     87 
     88    cache->last = NULL;
     89 
     90    size = cache->size * 3;
     91    items = (struct cache_item**) malloc(size * sizeof(*items));
     92    memset(items, 0, size * sizeof(*items));
     93 
     94    for (i = 0; i < cache->size; i++)
     95       for (c = cache->items[i]; c; c = next) {
     96 	 next = c->next;
     97 	 c->next = items[c->hash % size];
     98 	 items[c->hash % size] = c;
     99       }
    100 
    101    free(cache->items);
    102    cache->items = items;
    103    cache->size = size;
    104 }
    105 
    106 
    107 static void
    108 clear_cache(struct gl_context *ctx, struct gl_program_cache *cache,
    109 	    GLboolean shader)
    110 {
    111    struct cache_item *c, *next;
    112    GLuint i;
    113 
    114    cache->last = NULL;
    115 
    116    for (i = 0; i < cache->size; i++) {
    117       for (c = cache->items[i]; c; c = next) {
    118 	 next = c->next;
    119 	 free(c->key);
    120 	 if (shader) {
    121 	    _mesa_reference_shader_program(ctx,
    122 					   (struct gl_shader_program **)&c->program,
    123 					   NULL);
    124 	 } else {
    125 	    _mesa_reference_program(ctx, &c->program, NULL);
    126 	 }
    127 	 free(c);
    128       }
    129       cache->items[i] = NULL;
    130    }
    131 
    132 
    133    cache->n_items = 0;
    134 }
    135 
    136 
    137 
    138 struct gl_program_cache *
    139 _mesa_new_program_cache(void)
    140 {
    141    struct gl_program_cache *cache = CALLOC_STRUCT(gl_program_cache);
    142    if (cache) {
    143       cache->size = 17;
    144       cache->items = (struct cache_item **)
    145          calloc(1, cache->size * sizeof(struct cache_item));
    146       if (!cache->items) {
    147          free(cache);
    148          return NULL;
    149       }
    150    }
    151    return cache;
    152 }
    153 
    154 
    155 void
    156 _mesa_delete_program_cache(struct gl_context *ctx, struct gl_program_cache *cache)
    157 {
    158    clear_cache(ctx, cache, GL_FALSE);
    159    free(cache->items);
    160    free(cache);
    161 }
    162 
    163 void
    164 _mesa_delete_shader_cache(struct gl_context *ctx,
    165 			  struct gl_program_cache *cache)
    166 {
    167    clear_cache(ctx, cache, GL_TRUE);
    168    free(cache->items);
    169    free(cache);
    170 }
    171 
    172 
    173 struct gl_program *
    174 _mesa_search_program_cache(struct gl_program_cache *cache,
    175                            const void *key, GLuint keysize)
    176 {
    177    if (cache->last &&
    178        memcmp(cache->last->key, key, keysize) == 0) {
    179       return cache->last->program;
    180    }
    181    else {
    182       const GLuint hash = hash_key(key, keysize);
    183       struct cache_item *c;
    184 
    185       for (c = cache->items[hash % cache->size]; c; c = c->next) {
    186          if (c->hash == hash && memcmp(c->key, key, keysize) == 0) {
    187             cache->last = c;
    188             return c->program;
    189          }
    190       }
    191 
    192       return NULL;
    193    }
    194 }
    195 
    196 
    197 void
    198 _mesa_program_cache_insert(struct gl_context *ctx,
    199                            struct gl_program_cache *cache,
    200                            const void *key, GLuint keysize,
    201                            struct gl_program *program)
    202 {
    203    const GLuint hash = hash_key(key, keysize);
    204    struct cache_item *c = CALLOC_STRUCT(cache_item);
    205 
    206    c->hash = hash;
    207 
    208    c->key = malloc(keysize);
    209    memcpy(c->key, key, keysize);
    210 
    211    c->program = program;  /* no refcount change */
    212 
    213    if (cache->n_items > cache->size * 1.5) {
    214       if (cache->size < 1000)
    215 	 rehash(cache);
    216       else
    217 	 clear_cache(ctx, cache, GL_FALSE);
    218    }
    219 
    220    cache->n_items++;
    221    c->next = cache->items[hash % cache->size];
    222    cache->items[hash % cache->size] = c;
    223 }
    224 
    225 void
    226 _mesa_shader_cache_insert(struct gl_context *ctx,
    227 			  struct gl_program_cache *cache,
    228 			  const void *key, GLuint keysize,
    229 			  struct gl_shader_program *program)
    230 {
    231    const GLuint hash = hash_key(key, keysize);
    232    struct cache_item *c = CALLOC_STRUCT(cache_item);
    233 
    234    c->hash = hash;
    235 
    236    c->key = malloc(keysize);
    237    memcpy(c->key, key, keysize);
    238 
    239    c->program = (struct gl_program *)program;  /* no refcount change */
    240 
    241    if (cache->n_items > cache->size * 1.5) {
    242       if (cache->size < 1000)
    243 	 rehash(cache);
    244       else
    245 	 clear_cache(ctx, cache, GL_TRUE);
    246    }
    247 
    248    cache->n_items++;
    249    c->next = cache->items[hash % cache->size];
    250    cache->items[hash % cache->size] = c;
    251 }
    252