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