cso_cache.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  *
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  *
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  *
00026  **************************************************************************/
00027 
00028 /* Authors:  Zack Rusin <zack@tungstengraphics.com>
00029  */
00030 
00031 #include "pipe/p_debug.h"
00032 
00033 #include "util/u_memory.h"
00034 
00035 #include "cso_cache.h"
00036 #include "cso_hash.h"
00037 
00038 
00039 struct cso_cache {
00040    struct cso_hash *blend_hash;
00041    struct cso_hash *depth_stencil_hash;
00042    struct cso_hash *fs_hash;
00043    struct cso_hash *vs_hash;
00044    struct cso_hash *rasterizer_hash;
00045    struct cso_hash *sampler_hash;
00046    int    max_size;
00047 
00048    cso_sanitize_callback sanitize_cb;
00049    void                 *sanitize_data;
00050 };
00051 
00052 #if 1
00053 static unsigned hash_key(const void *key, unsigned key_size)
00054 {
00055    unsigned *ikey = (unsigned *)key;
00056    unsigned hash = 0, i;
00057 
00058    assert(key_size % 4 == 0);
00059 
00060    /* I'm sure this can be improved on:
00061     */
00062    for (i = 0; i < key_size/4; i++)
00063       hash ^= ikey[i];
00064 
00065    return hash;
00066 }
00067 #else
00068 static unsigned hash_key(const unsigned char *p, int n)
00069 {
00070    unsigned h = 0;
00071    unsigned g;
00072 
00073    while (n--) {
00074       h = (h << 4) + *p++;
00075       if ((g = (h & 0xf0000000)) != 0)
00076          h ^= g >> 23;
00077       h &= ~g;
00078    }
00079    return h;
00080 }
00081 #endif
00082 
00083 unsigned cso_construct_key(void *item, int item_size)
00084 {
00085    return hash_key((item), item_size);
00086 }
00087 
00088 static struct cso_hash *_cso_hash_for_type(struct cso_cache *sc, enum cso_cache_type type)
00089 {
00090    struct cso_hash *hash = 0;
00091 
00092    switch(type) {
00093    case CSO_BLEND:
00094       hash = sc->blend_hash;
00095       break;
00096    case CSO_SAMPLER:
00097       hash = sc->sampler_hash;
00098       break;
00099    case CSO_DEPTH_STENCIL_ALPHA:
00100       hash = sc->depth_stencil_hash;
00101       break;
00102    case CSO_RASTERIZER:
00103       hash = sc->rasterizer_hash;
00104       break;
00105    case CSO_FRAGMENT_SHADER:
00106       hash = sc->fs_hash;
00107       break;
00108    case CSO_VERTEX_SHADER:
00109       hash = sc->vs_hash;
00110       break;
00111    }
00112 
00113    return hash;
00114 }
00115 
00116 static int _cso_size_for_type(enum cso_cache_type type)
00117 {
00118    switch(type) {
00119    case CSO_BLEND:
00120       return sizeof(struct pipe_blend_state);
00121    case CSO_SAMPLER:
00122       return sizeof(struct pipe_sampler_state);
00123    case CSO_DEPTH_STENCIL_ALPHA:
00124       return sizeof(struct pipe_depth_stencil_alpha_state);
00125    case CSO_RASTERIZER:
00126       return sizeof(struct pipe_rasterizer_state);
00127    case CSO_FRAGMENT_SHADER:
00128       return sizeof(struct pipe_shader_state);
00129    case CSO_VERTEX_SHADER:
00130       return sizeof(struct pipe_shader_state);
00131    }
00132    return 0;
00133 }
00134 
00135 
00136 static void delete_blend_state(void *state, void *data)
00137 {
00138    struct cso_blend *cso = (struct cso_blend *)state;
00139    if (cso->delete_state)
00140       cso->delete_state(cso->context, cso->data);
00141    FREE(state);
00142 }
00143 
00144 static void delete_depth_stencil_state(void *state, void *data)
00145 {
00146    struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state;
00147    if (cso->delete_state)
00148       cso->delete_state(cso->context, cso->data);
00149    FREE(state);
00150 }
00151 
00152 static void delete_sampler_state(void *state, void *data)
00153 {
00154    struct cso_sampler *cso = (struct cso_sampler *)state;
00155    if (cso->delete_state)
00156       cso->delete_state(cso->context, cso->data);
00157    FREE(state);
00158 }
00159 
00160 static void delete_rasterizer_state(void *state, void *data)
00161 {
00162    struct cso_rasterizer *cso = (struct cso_rasterizer *)state;
00163    if (cso->delete_state)
00164       cso->delete_state(cso->context, cso->data);
00165    FREE(state);
00166 }
00167 
00168 static void delete_fs_state(void *state, void *data)
00169 {
00170    struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state;
00171    if (cso->delete_state)
00172       cso->delete_state(cso->context, cso->data);
00173    FREE(state);
00174 }
00175 
00176 static void delete_vs_state(void *state, void *data)
00177 {
00178    struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state;
00179    if (cso->delete_state)
00180       cso->delete_state(cso->context, cso->data);
00181    FREE(state);
00182 }
00183 
00184 
00185 static INLINE void delete_cso(void *state, enum cso_cache_type type)
00186 {
00187    switch (type) {
00188    case CSO_BLEND:
00189       delete_blend_state(state, 0);
00190       break;
00191    case CSO_SAMPLER:
00192       delete_sampler_state(state, 0);
00193       break;
00194    case CSO_DEPTH_STENCIL_ALPHA:
00195       delete_depth_stencil_state(state, 0);
00196       break;
00197    case CSO_RASTERIZER:
00198       delete_rasterizer_state(state, 0);
00199       break;
00200    case CSO_FRAGMENT_SHADER:
00201       delete_fs_state(state, 0);
00202       break;
00203    case CSO_VERTEX_SHADER:
00204       delete_vs_state(state, 0);
00205       break;
00206    default:
00207       assert(0);
00208       FREE(state);
00209    }
00210 }
00211 
00212 
00213 static INLINE void sanitize_hash(struct cso_cache *sc,
00214                                  struct cso_hash *hash,
00215                                  enum cso_cache_type type,
00216                                  int max_size)
00217 {
00218    if (sc->sanitize_cb)
00219       sc->sanitize_cb(hash, type, max_size, sc->sanitize_data);
00220 }
00221 
00222 
00223 static INLINE void sanitize_cb(struct cso_hash *hash, enum cso_cache_type type,
00224                                int max_size, void *user_data)
00225 {
00226    /* if we're approach the maximum size, remove fourth of the entries
00227     * otherwise every subsequent call will go through the same */
00228    int hash_size = cso_hash_size(hash);
00229    int max_entries = (max_size > hash_size) ? max_size : hash_size;
00230    int to_remove =  (max_size < max_entries) * max_entries/4;
00231    if (hash_size > max_size)
00232       to_remove += hash_size - max_size;
00233    while (to_remove) {
00234       /*remove elements until we're good */
00235       /*fixme: currently we pick the nodes to remove at random*/
00236       struct cso_hash_iter iter = cso_hash_first_node(hash);
00237       void  *cso = cso_hash_take(hash, cso_hash_iter_key(iter));
00238       delete_cso(cso, type);
00239       --to_remove;
00240    }
00241 }
00242 
00243 struct cso_hash_iter
00244 cso_insert_state(struct cso_cache *sc,
00245                  unsigned hash_key, enum cso_cache_type type,
00246                  void *state)
00247 {
00248    struct cso_hash *hash = _cso_hash_for_type(sc, type);
00249    sanitize_hash(sc, hash, type, sc->max_size);
00250 
00251    return cso_hash_insert(hash, hash_key, state);
00252 }
00253 
00254 struct cso_hash_iter
00255 cso_find_state(struct cso_cache *sc,
00256                unsigned hash_key, enum cso_cache_type type)
00257 {
00258    struct cso_hash *hash = _cso_hash_for_type(sc, type);
00259 
00260    return cso_hash_find(hash, hash_key);
00261 }
00262 
00263 
00264 void *cso_hash_find_data_from_template( struct cso_hash *hash,
00265                                         unsigned hash_key, 
00266                                         void *templ,
00267                                         int size )
00268 {
00269    struct cso_hash_iter iter = cso_hash_find(hash, hash_key);
00270    while (!cso_hash_iter_is_null(iter)) {
00271       void *iter_data = cso_hash_iter_data(iter);
00272       if (!memcmp(iter_data, templ, size)) {
00273          /* We found a match
00274           */
00275          return iter_data;
00276       }
00277       iter = cso_hash_iter_next(iter);
00278    }
00279    return NULL;
00280 }
00281 
00282 
00283 struct cso_hash_iter cso_find_state_template(struct cso_cache *sc,
00284                                              unsigned hash_key, enum cso_cache_type type,
00285                                              void *templ)
00286 {
00287    struct cso_hash_iter iter = cso_find_state(sc, hash_key, type);
00288    int size = _cso_size_for_type(type);
00289    while (!cso_hash_iter_is_null(iter)) {
00290       void *iter_data = cso_hash_iter_data(iter);
00291       if (!memcmp(iter_data, templ, size))
00292          return iter;
00293       iter = cso_hash_iter_next(iter);
00294    }
00295    return iter;
00296 }
00297 
00298 void * cso_take_state(struct cso_cache *sc,
00299                       unsigned hash_key, enum cso_cache_type type)
00300 {
00301    struct cso_hash *hash = _cso_hash_for_type(sc, type);
00302    return cso_hash_take(hash, hash_key);
00303 }
00304 
00305 struct cso_cache *cso_cache_create(void)
00306 {
00307    struct cso_cache *sc = MALLOC_STRUCT(cso_cache);
00308    if (sc == NULL)
00309       return NULL;
00310 
00311    sc->max_size           = 4096;
00312    sc->blend_hash         = cso_hash_create();
00313    sc->sampler_hash       = cso_hash_create();
00314    sc->depth_stencil_hash = cso_hash_create();
00315    sc->rasterizer_hash    = cso_hash_create();
00316    sc->fs_hash            = cso_hash_create();
00317    sc->vs_hash            = cso_hash_create();
00318    sc->sanitize_cb        = sanitize_cb;
00319    sc->sanitize_data      = 0;
00320 
00321    return sc;
00322 }
00323 
00324 void cso_for_each_state(struct cso_cache *sc, enum cso_cache_type type,
00325                         cso_state_callback func, void *user_data)
00326 {
00327    struct cso_hash *hash = 0;
00328    struct cso_hash_iter iter;
00329 
00330    switch (type) {
00331    case CSO_BLEND:
00332       hash = sc->blend_hash;
00333       break;
00334    case CSO_SAMPLER:
00335       hash = sc->sampler_hash;
00336       break;
00337    case CSO_DEPTH_STENCIL_ALPHA:
00338       hash = sc->depth_stencil_hash;
00339       break;
00340    case CSO_RASTERIZER:
00341       hash = sc->rasterizer_hash;
00342       break;
00343    case CSO_FRAGMENT_SHADER:
00344       hash = sc->fs_hash;
00345       break;
00346    case CSO_VERTEX_SHADER:
00347       hash = sc->vs_hash;
00348       break;
00349    }
00350 
00351    iter = cso_hash_first_node(hash);
00352    while (!cso_hash_iter_is_null(iter)) {
00353       void *state = cso_hash_iter_data(iter);
00354       iter = cso_hash_iter_next(iter);
00355       if (state) {
00356          func(state, user_data);
00357       }
00358    }
00359 }
00360 
00361 void cso_cache_delete(struct cso_cache *sc)
00362 {
00363    assert(sc);
00364    /* delete driver data */
00365    cso_for_each_state(sc, CSO_BLEND, delete_blend_state, 0);
00366    cso_for_each_state(sc, CSO_DEPTH_STENCIL_ALPHA, delete_depth_stencil_state, 0);
00367    cso_for_each_state(sc, CSO_FRAGMENT_SHADER, delete_fs_state, 0);
00368    cso_for_each_state(sc, CSO_VERTEX_SHADER, delete_vs_state, 0);
00369    cso_for_each_state(sc, CSO_RASTERIZER, delete_rasterizer_state, 0);
00370    cso_for_each_state(sc, CSO_SAMPLER, delete_sampler_state, 0);
00371 
00372    cso_hash_delete(sc->blend_hash);
00373    cso_hash_delete(sc->sampler_hash);
00374    cso_hash_delete(sc->depth_stencil_hash);
00375    cso_hash_delete(sc->rasterizer_hash);
00376    cso_hash_delete(sc->fs_hash);
00377    cso_hash_delete(sc->vs_hash);
00378    FREE(sc);
00379 }
00380 
00381 void cso_set_maximum_cache_size(struct cso_cache *sc, int number)
00382 {
00383    sc->max_size = number;
00384 
00385    sanitize_hash(sc, sc->blend_hash, CSO_BLEND, sc->max_size);
00386    sanitize_hash(sc, sc->depth_stencil_hash, CSO_DEPTH_STENCIL_ALPHA,
00387                  sc->max_size);
00388    sanitize_hash(sc, sc->fs_hash, CSO_FRAGMENT_SHADER, sc->max_size);
00389    sanitize_hash(sc, sc->vs_hash, CSO_VERTEX_SHADER, sc->max_size);
00390    sanitize_hash(sc, sc->rasterizer_hash, CSO_RASTERIZER, sc->max_size);
00391    sanitize_hash(sc, sc->sampler_hash, CSO_SAMPLER, sc->max_size);
00392 }
00393 
00394 int cso_maximum_cache_size(const struct cso_cache *sc)
00395 {
00396    return sc->max_size;
00397 }
00398 
00399 void cso_cache_set_sanitize_callback(struct cso_cache *sc,
00400                                      cso_sanitize_callback cb,
00401                                      void *user_data)
00402 {
00403    sc->sanitize_cb   = cb;
00404    sc->sanitize_data = user_data;
00405 }
00406 

Generated on Tue Sep 29 06:25:14 2009 for Gallium3D by  doxygen 1.5.4