cso_cache.c revision f311893bf4cd4e20e5b43fa404c4a2f656791943
1/**************************************************************************
2 *
3 * Copyright 2007 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/* Authors:  Zack Rusin <zack@tungstengraphics.com>
29 */
30
31#include "util/u_debug.h"
32
33#include "util/u_memory.h"
34
35#include "cso_cache.h"
36#include "cso_hash.h"
37
38
39struct cso_cache {
40   struct cso_hash *blend_hash;
41   struct cso_hash *depth_stencil_hash;
42   struct cso_hash *fs_hash;
43   struct cso_hash *vs_hash;
44   struct cso_hash *rasterizer_hash;
45   struct cso_hash *sampler_hash;
46   int    max_size;
47
48   cso_sanitize_callback sanitize_cb;
49   void                 *sanitize_data;
50};
51
52#if 1
53static unsigned hash_key(const void *key, unsigned key_size)
54{
55   unsigned *ikey = (unsigned *)key;
56   unsigned hash = 0, i;
57
58   assert(key_size % 4 == 0);
59
60   /* I'm sure this can be improved on:
61    */
62   for (i = 0; i < key_size/4; i++)
63      hash ^= ikey[i];
64
65   return hash;
66}
67#else
68static unsigned hash_key(const unsigned char *p, int n)
69{
70   unsigned h = 0;
71   unsigned g;
72
73   while (n--) {
74      h = (h << 4) + *p++;
75      if ((g = (h & 0xf0000000)) != 0)
76         h ^= g >> 23;
77      h &= ~g;
78   }
79   return h;
80}
81#endif
82
83unsigned cso_construct_key(void *item, int item_size)
84{
85   return hash_key((item), item_size);
86}
87
88static struct cso_hash *_cso_hash_for_type(struct cso_cache *sc, enum cso_cache_type type)
89{
90   struct cso_hash *hash = 0;
91
92   switch(type) {
93   case CSO_BLEND:
94      hash = sc->blend_hash;
95      break;
96   case CSO_SAMPLER:
97      hash = sc->sampler_hash;
98      break;
99   case CSO_DEPTH_STENCIL_ALPHA:
100      hash = sc->depth_stencil_hash;
101      break;
102   case CSO_RASTERIZER:
103      hash = sc->rasterizer_hash;
104      break;
105   case CSO_FRAGMENT_SHADER:
106      hash = sc->fs_hash;
107      break;
108   case CSO_VERTEX_SHADER:
109      hash = sc->vs_hash;
110      break;
111   }
112
113   return hash;
114}
115
116static int _cso_size_for_type(enum cso_cache_type type)
117{
118   switch(type) {
119   case CSO_BLEND:
120      return sizeof(struct pipe_blend_state);
121   case CSO_SAMPLER:
122      return sizeof(struct pipe_sampler_state);
123   case CSO_DEPTH_STENCIL_ALPHA:
124      return sizeof(struct pipe_depth_stencil_alpha_state);
125   case CSO_RASTERIZER:
126      return sizeof(struct pipe_rasterizer_state);
127   case CSO_FRAGMENT_SHADER:
128      return sizeof(struct pipe_shader_state);
129   case CSO_VERTEX_SHADER:
130      return sizeof(struct pipe_shader_state);
131   }
132   return 0;
133}
134
135
136static void delete_blend_state(void *state, void *data)
137{
138   struct cso_blend *cso = (struct cso_blend *)state;
139   if (cso->delete_state)
140      cso->delete_state(cso->context, cso->data);
141   FREE(state);
142}
143
144static void delete_depth_stencil_state(void *state, void *data)
145{
146   struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state;
147   if (cso->delete_state)
148      cso->delete_state(cso->context, cso->data);
149   FREE(state);
150}
151
152static void delete_sampler_state(void *state, void *data)
153{
154   struct cso_sampler *cso = (struct cso_sampler *)state;
155   if (cso->delete_state)
156      cso->delete_state(cso->context, cso->data);
157   FREE(state);
158}
159
160static void delete_rasterizer_state(void *state, void *data)
161{
162   struct cso_rasterizer *cso = (struct cso_rasterizer *)state;
163   if (cso->delete_state)
164      cso->delete_state(cso->context, cso->data);
165   FREE(state);
166}
167
168static void delete_fs_state(void *state, void *data)
169{
170   struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state;
171   if (cso->delete_state)
172      cso->delete_state(cso->context, cso->data);
173   FREE(state);
174}
175
176static void delete_vs_state(void *state, void *data)
177{
178   struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state;
179   if (cso->delete_state)
180      cso->delete_state(cso->context, cso->data);
181   FREE(state);
182}
183
184
185static INLINE void delete_cso(void *state, enum cso_cache_type type)
186{
187   switch (type) {
188   case CSO_BLEND:
189      delete_blend_state(state, 0);
190      break;
191   case CSO_SAMPLER:
192      delete_sampler_state(state, 0);
193      break;
194   case CSO_DEPTH_STENCIL_ALPHA:
195      delete_depth_stencil_state(state, 0);
196      break;
197   case CSO_RASTERIZER:
198      delete_rasterizer_state(state, 0);
199      break;
200   case CSO_FRAGMENT_SHADER:
201      delete_fs_state(state, 0);
202      break;
203   case CSO_VERTEX_SHADER:
204      delete_vs_state(state, 0);
205      break;
206   default:
207      assert(0);
208      FREE(state);
209   }
210}
211
212
213static INLINE void sanitize_hash(struct cso_cache *sc,
214                                 struct cso_hash *hash,
215                                 enum cso_cache_type type,
216                                 int max_size)
217{
218   if (sc->sanitize_cb)
219      sc->sanitize_cb(hash, type, max_size, sc->sanitize_data);
220}
221
222
223static INLINE void sanitize_cb(struct cso_hash *hash, enum cso_cache_type type,
224                               int max_size, void *user_data)
225{
226   /* if we're approach the maximum size, remove fourth of the entries
227    * otherwise every subsequent call will go through the same */
228   int hash_size = cso_hash_size(hash);
229   int max_entries = (max_size > hash_size) ? max_size : hash_size;
230   int to_remove =  (max_size < max_entries) * max_entries/4;
231   if (hash_size > max_size)
232      to_remove += hash_size - max_size;
233   while (to_remove) {
234      /*remove elements until we're good */
235      /*fixme: currently we pick the nodes to remove at random*/
236      struct cso_hash_iter iter = cso_hash_first_node(hash);
237      void  *cso = cso_hash_take(hash, cso_hash_iter_key(iter));
238      delete_cso(cso, type);
239      --to_remove;
240   }
241}
242
243struct cso_hash_iter
244cso_insert_state(struct cso_cache *sc,
245                 unsigned hash_key, enum cso_cache_type type,
246                 void *state)
247{
248   struct cso_hash *hash = _cso_hash_for_type(sc, type);
249   sanitize_hash(sc, hash, type, sc->max_size);
250
251   return cso_hash_insert(hash, hash_key, state);
252}
253
254struct cso_hash_iter
255cso_find_state(struct cso_cache *sc,
256               unsigned hash_key, enum cso_cache_type type)
257{
258   struct cso_hash *hash = _cso_hash_for_type(sc, type);
259
260   return cso_hash_find(hash, hash_key);
261}
262
263
264void *cso_hash_find_data_from_template( struct cso_hash *hash,
265				        unsigned hash_key,
266				        void *templ,
267				        int size )
268{
269   struct cso_hash_iter iter = cso_hash_find(hash, hash_key);
270   while (!cso_hash_iter_is_null(iter)) {
271      void *iter_data = cso_hash_iter_data(iter);
272      if (!memcmp(iter_data, templ, size)) {
273	 /* We found a match
274	  */
275         return iter_data;
276      }
277      iter = cso_hash_iter_next(iter);
278   }
279   return NULL;
280}
281
282
283struct cso_hash_iter cso_find_state_template(struct cso_cache *sc,
284                                             unsigned hash_key, enum cso_cache_type type,
285                                             void *templ)
286{
287   struct cso_hash_iter iter = cso_find_state(sc, hash_key, type);
288   int size = _cso_size_for_type(type);
289   while (!cso_hash_iter_is_null(iter)) {
290      void *iter_data = cso_hash_iter_data(iter);
291      if (!memcmp(iter_data, templ, size))
292         return iter;
293      iter = cso_hash_iter_next(iter);
294   }
295   return iter;
296}
297
298void * cso_take_state(struct cso_cache *sc,
299                      unsigned hash_key, enum cso_cache_type type)
300{
301   struct cso_hash *hash = _cso_hash_for_type(sc, type);
302   return cso_hash_take(hash, hash_key);
303}
304
305struct cso_cache *cso_cache_create(void)
306{
307   struct cso_cache *sc = MALLOC_STRUCT(cso_cache);
308   if (sc == NULL)
309      return NULL;
310
311   sc->max_size           = 4096;
312   sc->blend_hash         = cso_hash_create();
313   sc->sampler_hash       = cso_hash_create();
314   sc->depth_stencil_hash = cso_hash_create();
315   sc->rasterizer_hash    = cso_hash_create();
316   sc->fs_hash            = cso_hash_create();
317   sc->vs_hash            = cso_hash_create();
318   sc->sanitize_cb        = sanitize_cb;
319   sc->sanitize_data      = 0;
320
321   return sc;
322}
323
324void cso_for_each_state(struct cso_cache *sc, enum cso_cache_type type,
325                        cso_state_callback func, void *user_data)
326{
327   struct cso_hash *hash = 0;
328   struct cso_hash_iter iter;
329
330   switch (type) {
331   case CSO_BLEND:
332      hash = sc->blend_hash;
333      break;
334   case CSO_SAMPLER:
335      hash = sc->sampler_hash;
336      break;
337   case CSO_DEPTH_STENCIL_ALPHA:
338      hash = sc->depth_stencil_hash;
339      break;
340   case CSO_RASTERIZER:
341      hash = sc->rasterizer_hash;
342      break;
343   case CSO_FRAGMENT_SHADER:
344      hash = sc->fs_hash;
345      break;
346   case CSO_VERTEX_SHADER:
347      hash = sc->vs_hash;
348      break;
349   }
350
351   iter = cso_hash_first_node(hash);
352   while (!cso_hash_iter_is_null(iter)) {
353      void *state = cso_hash_iter_data(iter);
354      iter = cso_hash_iter_next(iter);
355      if (state) {
356         func(state, user_data);
357      }
358   }
359}
360
361void cso_cache_delete(struct cso_cache *sc)
362{
363   assert(sc);
364
365   if (!sc)
366      return;
367
368   /* delete driver data */
369   cso_for_each_state(sc, CSO_BLEND, delete_blend_state, 0);
370   cso_for_each_state(sc, CSO_DEPTH_STENCIL_ALPHA, delete_depth_stencil_state, 0);
371   cso_for_each_state(sc, CSO_FRAGMENT_SHADER, delete_fs_state, 0);
372   cso_for_each_state(sc, CSO_VERTEX_SHADER, delete_vs_state, 0);
373   cso_for_each_state(sc, CSO_RASTERIZER, delete_rasterizer_state, 0);
374   cso_for_each_state(sc, CSO_SAMPLER, delete_sampler_state, 0);
375
376   cso_hash_delete(sc->blend_hash);
377   cso_hash_delete(sc->sampler_hash);
378   cso_hash_delete(sc->depth_stencil_hash);
379   cso_hash_delete(sc->rasterizer_hash);
380   cso_hash_delete(sc->fs_hash);
381   cso_hash_delete(sc->vs_hash);
382   FREE(sc);
383}
384
385void cso_set_maximum_cache_size(struct cso_cache *sc, int number)
386{
387   sc->max_size = number;
388
389   sanitize_hash(sc, sc->blend_hash, CSO_BLEND, sc->max_size);
390   sanitize_hash(sc, sc->depth_stencil_hash, CSO_DEPTH_STENCIL_ALPHA,
391                 sc->max_size);
392   sanitize_hash(sc, sc->fs_hash, CSO_FRAGMENT_SHADER, sc->max_size);
393   sanitize_hash(sc, sc->vs_hash, CSO_VERTEX_SHADER, sc->max_size);
394   sanitize_hash(sc, sc->rasterizer_hash, CSO_RASTERIZER, sc->max_size);
395   sanitize_hash(sc, sc->sampler_hash, CSO_SAMPLER, sc->max_size);
396}
397
398int cso_maximum_cache_size(const struct cso_cache *sc)
399{
400   return sc->max_size;
401}
402
403void cso_cache_set_sanitize_callback(struct cso_cache *sc,
404                                     cso_sanitize_callback cb,
405                                     void *user_data)
406{
407   sc->sanitize_cb   = cb;
408   sc->sanitize_data = user_data;
409}
410
411