Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2007 VMware, Inc.
  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 VMWARE 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 <zackr@vmware.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.  
  39. struct cso_cache {
  40.    struct cso_hash *hashes[CSO_CACHE_MAX];
  41.    int    max_size;
  42.  
  43.    cso_sanitize_callback sanitize_cb;
  44.    void                 *sanitize_data;
  45. };
  46.  
  47. #if 1
  48. static unsigned hash_key(const void *key, unsigned key_size)
  49. {
  50.    unsigned *ikey = (unsigned *)key;
  51.    unsigned hash = 0, i;
  52.  
  53.    assert(key_size % 4 == 0);
  54.  
  55.    /* I'm sure this can be improved on:
  56.     */
  57.    for (i = 0; i < key_size/4; i++)
  58.       hash ^= ikey[i];
  59.  
  60.    return hash;
  61. }
  62. #else
  63. static unsigned hash_key(const unsigned char *p, int n)
  64. {
  65.    unsigned h = 0;
  66.    unsigned g;
  67.  
  68.    while (n--) {
  69.       h = (h << 4) + *p++;
  70.       if ((g = (h & 0xf0000000)) != 0)
  71.          h ^= g >> 23;
  72.       h &= ~g;
  73.    }
  74.    return h;
  75. }
  76. #endif
  77.  
  78. unsigned cso_construct_key(void *item, int item_size)
  79. {
  80.    return hash_key((item), item_size);
  81. }
  82.  
  83. static INLINE struct cso_hash *_cso_hash_for_type(struct cso_cache *sc, enum cso_cache_type type)
  84. {
  85.    struct cso_hash *hash;
  86.    hash = sc->hashes[type];
  87.    return hash;
  88. }
  89.  
  90. static void delete_blend_state(void *state, void *data)
  91. {
  92.    struct cso_blend *cso = (struct cso_blend *)state;
  93.    if (cso->delete_state)
  94.       cso->delete_state(cso->context, cso->data);
  95.    FREE(state);
  96. }
  97.  
  98. static void delete_depth_stencil_state(void *state, void *data)
  99. {
  100.    struct cso_depth_stencil_alpha *cso = (struct cso_depth_stencil_alpha *)state;
  101.    if (cso->delete_state)
  102.       cso->delete_state(cso->context, cso->data);
  103.    FREE(state);
  104. }
  105.  
  106. static void delete_sampler_state(void *state, void *data)
  107. {
  108.    struct cso_sampler *cso = (struct cso_sampler *)state;
  109.    if (cso->delete_state)
  110.       cso->delete_state(cso->context, cso->data);
  111.    FREE(state);
  112. }
  113.  
  114. static void delete_rasterizer_state(void *state, void *data)
  115. {
  116.    struct cso_rasterizer *cso = (struct cso_rasterizer *)state;
  117.    if (cso->delete_state)
  118.       cso->delete_state(cso->context, cso->data);
  119.    FREE(state);
  120. }
  121.  
  122. static void delete_velements(void *state, void *data)
  123. {
  124.    struct cso_velements *cso = (struct cso_velements *)state;
  125.    if (cso->delete_state)
  126.       cso->delete_state(cso->context, cso->data);
  127.    FREE(state);
  128. }
  129.  
  130. static INLINE void delete_cso(void *state, enum cso_cache_type type)
  131. {
  132.    switch (type) {
  133.    case CSO_BLEND:
  134.       delete_blend_state(state, 0);
  135.       break;
  136.    case CSO_SAMPLER:
  137.       delete_sampler_state(state, 0);
  138.       break;
  139.    case CSO_DEPTH_STENCIL_ALPHA:
  140.       delete_depth_stencil_state(state, 0);
  141.       break;
  142.    case CSO_RASTERIZER:
  143.       delete_rasterizer_state(state, 0);
  144.       break;
  145.    case CSO_VELEMENTS:
  146.       delete_velements(state, 0);
  147.       break;
  148.    default:
  149.       assert(0);
  150.       FREE(state);
  151.    }
  152. }
  153.  
  154.  
  155. static INLINE void sanitize_hash(struct cso_cache *sc,
  156.                                  struct cso_hash *hash,
  157.                                  enum cso_cache_type type,
  158.                                  int max_size)
  159. {
  160.    if (sc->sanitize_cb)
  161.       sc->sanitize_cb(hash, type, max_size, sc->sanitize_data);
  162. }
  163.  
  164.  
  165. static INLINE void sanitize_cb(struct cso_hash *hash, enum cso_cache_type type,
  166.                                int max_size, void *user_data)
  167. {
  168.    /* if we're approach the maximum size, remove fourth of the entries
  169.     * otherwise every subsequent call will go through the same */
  170.    int hash_size = cso_hash_size(hash);
  171.    int max_entries = (max_size > hash_size) ? max_size : hash_size;
  172.    int to_remove =  (max_size < max_entries) * max_entries/4;
  173.    if (hash_size > max_size)
  174.       to_remove += hash_size - max_size;
  175.    while (to_remove) {
  176.       /*remove elements until we're good */
  177.       /*fixme: currently we pick the nodes to remove at random*/
  178.       struct cso_hash_iter iter = cso_hash_first_node(hash);
  179.       void  *cso = cso_hash_take(hash, cso_hash_iter_key(iter));
  180.       delete_cso(cso, type);
  181.       --to_remove;
  182.    }
  183. }
  184.  
  185. struct cso_hash_iter
  186. cso_insert_state(struct cso_cache *sc,
  187.                  unsigned hash_key, enum cso_cache_type type,
  188.                  void *state)
  189. {
  190.    struct cso_hash *hash = _cso_hash_for_type(sc, type);
  191.    sanitize_hash(sc, hash, type, sc->max_size);
  192.  
  193.    return cso_hash_insert(hash, hash_key, state);
  194. }
  195.  
  196. struct cso_hash_iter
  197. cso_find_state(struct cso_cache *sc,
  198.                unsigned hash_key, enum cso_cache_type type)
  199. {
  200.    struct cso_hash *hash = _cso_hash_for_type(sc, type);
  201.  
  202.    return cso_hash_find(hash, hash_key);
  203. }
  204.  
  205.  
  206. void *cso_hash_find_data_from_template( struct cso_hash *hash,
  207.                                         unsigned hash_key,
  208.                                         void *templ,
  209.                                         int size )
  210. {
  211.    struct cso_hash_iter iter = cso_hash_find(hash, hash_key);
  212.    while (!cso_hash_iter_is_null(iter)) {
  213.       void *iter_data = cso_hash_iter_data(iter);
  214.       if (!memcmp(iter_data, templ, size)) {
  215.          /* We found a match
  216.           */
  217.          return iter_data;
  218.       }
  219.       iter = cso_hash_iter_next(iter);
  220.    }
  221.    return NULL;
  222. }
  223.  
  224.  
  225. struct cso_hash_iter cso_find_state_template(struct cso_cache *sc,
  226.                                              unsigned hash_key, enum cso_cache_type type,
  227.                                              void *templ, unsigned size)
  228. {
  229.    struct cso_hash_iter iter = cso_find_state(sc, hash_key, type);
  230.    while (!cso_hash_iter_is_null(iter)) {
  231.       void *iter_data = cso_hash_iter_data(iter);
  232.       if (!memcmp(iter_data, templ, size))
  233.          return iter;
  234.       iter = cso_hash_iter_next(iter);
  235.    }
  236.    return iter;
  237. }
  238.  
  239. void * cso_take_state(struct cso_cache *sc,
  240.                       unsigned hash_key, enum cso_cache_type type)
  241. {
  242.    struct cso_hash *hash = _cso_hash_for_type(sc, type);
  243.    return cso_hash_take(hash, hash_key);
  244. }
  245.  
  246. struct cso_cache *cso_cache_create(void)
  247. {
  248.    struct cso_cache *sc = MALLOC_STRUCT(cso_cache);
  249.    int i;
  250.    if (sc == NULL)
  251.       return NULL;
  252.  
  253.    sc->max_size           = 4096;
  254.    for (i = 0; i < CSO_CACHE_MAX; i++)
  255.       sc->hashes[i] = cso_hash_create();
  256.  
  257.    sc->sanitize_cb        = sanitize_cb;
  258.    sc->sanitize_data      = 0;
  259.  
  260.    return sc;
  261. }
  262.  
  263. void cso_for_each_state(struct cso_cache *sc, enum cso_cache_type type,
  264.                         cso_state_callback func, void *user_data)
  265. {
  266.    struct cso_hash *hash = _cso_hash_for_type(sc, type);
  267.    struct cso_hash_iter iter;
  268.  
  269.    iter = cso_hash_first_node(hash);
  270.    while (!cso_hash_iter_is_null(iter)) {
  271.       void *state = cso_hash_iter_data(iter);
  272.       iter = cso_hash_iter_next(iter);
  273.       if (state) {
  274.          func(state, user_data);
  275.       }
  276.    }
  277. }
  278.  
  279. void cso_cache_delete(struct cso_cache *sc)
  280. {
  281.    int i;
  282.    assert(sc);
  283.  
  284.    if (!sc)
  285.       return;
  286.  
  287.    /* delete driver data */
  288.    cso_for_each_state(sc, CSO_BLEND, delete_blend_state, 0);
  289.    cso_for_each_state(sc, CSO_DEPTH_STENCIL_ALPHA, delete_depth_stencil_state, 0);
  290.    cso_for_each_state(sc, CSO_RASTERIZER, delete_rasterizer_state, 0);
  291.    cso_for_each_state(sc, CSO_SAMPLER, delete_sampler_state, 0);
  292.    cso_for_each_state(sc, CSO_VELEMENTS, delete_velements, 0);
  293.  
  294.    for (i = 0; i < CSO_CACHE_MAX; i++)
  295.       cso_hash_delete(sc->hashes[i]);
  296.  
  297.    FREE(sc);
  298. }
  299.  
  300. void cso_set_maximum_cache_size(struct cso_cache *sc, int number)
  301. {
  302.    int i;
  303.  
  304.    sc->max_size = number;
  305.  
  306.    for (i = 0; i < CSO_CACHE_MAX; i++)
  307.       sanitize_hash(sc, sc->hashes[i], i, sc->max_size);
  308. }
  309.  
  310. int cso_maximum_cache_size(const struct cso_cache *sc)
  311. {
  312.    return sc->max_size;
  313. }
  314.  
  315. void cso_cache_set_sanitize_callback(struct cso_cache *sc,
  316.                                      cso_sanitize_callback cb,
  317.                                      void *user_data)
  318. {
  319.    sc->sanitize_cb   = cb;
  320.    sc->sanitize_data = user_data;
  321. }
  322.  
  323.