brw_state_cache.c

Go to the documentation of this file.
00001 /*
00002  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
00003  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
00004  develop this 3D driver.
00005 
00006  Permission is hereby granted, free of charge, to any person obtaining
00007  a 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, sublicense, 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
00016  portions of the Software.
00017 
00018  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00021  IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
00022  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00023  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00024  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025 
00026  **********************************************************************/
00027  /*
00028   * Authors:
00029   *   Keith Whitwell <keith@tungstengraphics.com>
00030   */
00031 
00032 
00033 #include "brw_state.h"
00034 
00035 #include "brw_wm.h"
00036 #include "brw_vs.h"
00037 #include "brw_clip.h"
00038 #include "brw_sf.h"
00039 #include "brw_gs.h"
00040 
00041 #include "util/u_memory.h"
00042 
00043 
00044 
00045 /***********************************************************************
00046  * Check cache for uploaded version of struct, else upload new one.
00047  * Fail when memory is exhausted.
00048  *
00049  * XXX: FIXME: Currently search is so slow it would be quicker to
00050  * regenerate the data every time...
00051  */
00052 
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 
00068 static struct brw_cache_item *search_cache( struct brw_cache *cache,
00069                                              unsigned hash,
00070                                              const void *key,
00071                                              unsigned key_size)
00072 {
00073    struct brw_cache_item *c;
00074 
00075    for (c = cache->items[hash % cache->size]; c; c = c->next) {
00076       if (c->hash == hash &&
00077           c->key_size == key_size &&
00078           memcmp(c->key, key, key_size) == 0)
00079          return c;
00080    }
00081 
00082    return NULL;
00083 }
00084 
00085 
00086 static void rehash( struct brw_cache *cache )
00087 {
00088    struct brw_cache_item **items;
00089    struct brw_cache_item *c, *next;
00090    unsigned size, i;
00091 
00092    size = cache->size * 3;
00093    items = (struct brw_cache_item**) MALLOC(size * sizeof(*items));
00094    memset(items, 0, size * sizeof(*items));
00095 
00096    for (i = 0; i < cache->size; i++)
00097       for (c = cache->items[i]; c; c = next) {
00098          next = c->next;
00099          c->next = items[c->hash % size];
00100          items[c->hash % size] = c;
00101       }
00102 
00103    FREE(cache->items);
00104    cache->items = items;
00105    cache->size = size;
00106 }
00107 
00108 
00109 boolean brw_search_cache( struct brw_cache *cache,
00110                             const void *key,
00111                             unsigned key_size,
00112                             void *aux_return,
00113                             unsigned *offset_return)
00114 {
00115    struct brw_cache_item *item;
00116    unsigned addr = 0;
00117    unsigned hash = hash_key(key, key_size);
00118 
00119    item = search_cache(cache, hash, key, key_size);
00120 
00121    if (item) {
00122       if (aux_return)
00123          *(void **)aux_return = (void *)((char *)item->key + item->key_size);
00124 
00125       *offset_return = addr = item->offset;
00126    }
00127 
00128    if (item == NULL || addr != cache->last_addr) {
00129       cache->brw->state.dirty.cache |= 1<<cache->id;
00130       cache->last_addr = addr;
00131    }
00132 
00133    return item != NULL;
00134 }
00135 
00136 unsigned brw_upload_cache( struct brw_cache *cache,
00137                          const void *key,
00138                          unsigned key_size,
00139                          const void *data,
00140                          unsigned data_size,
00141                          const void *aux,
00142                          void *aux_return )
00143 {
00144    unsigned offset;
00145    struct brw_cache_item *item = CALLOC_STRUCT(brw_cache_item);
00146    unsigned hash = hash_key(key, key_size);
00147    void *tmp = MALLOC(key_size + cache->aux_size);
00148 
00149    if (!brw_pool_alloc(cache->pool, data_size, 1 << 6, &offset)) {
00150       /* Should not be possible:
00151        */
00152       debug_printf("brw_pool_alloc failed\n");
00153       exit(1);
00154    }
00155 
00156    memcpy(tmp, key, key_size);
00157 
00158    if (cache->aux_size)
00159       memcpy(tmp+key_size, aux, cache->aux_size);
00160 
00161    item->key = tmp;
00162    item->hash = hash;
00163    item->key_size = key_size;
00164    item->offset = offset;
00165    item->data_size = data_size;
00166 
00167    if (++cache->n_items > cache->size * 1.5)
00168       rehash(cache);
00169 
00170    hash %= cache->size;
00171    item->next = cache->items[hash];
00172    cache->items[hash] = item;
00173 
00174    if (aux_return) {
00175       assert(cache->aux_size);
00176       *(void **)aux_return = (void *)((char *)item->key + item->key_size);
00177    }
00178 
00179    if (BRW_DEBUG & DEBUG_STATE)
00180       debug_printf("upload %s: %d bytes to pool buffer %p offset %x\n",
00181              cache->name, 
00182              data_size,
00183              (void*)cache->pool->buffer,
00184              offset);
00185 
00186    /* Copy data to the buffer:
00187     */
00188    cache->brw->winsys->buffer_subdata_typed(cache->brw->winsys,
00189                                             cache->pool->buffer, 
00190                                             offset, 
00191                                             data_size, 
00192                                             data,
00193                                             cache->id);
00194 
00195    cache->brw->state.dirty.cache |= 1<<cache->id;
00196    cache->last_addr = offset;
00197 
00198    return offset;
00199 }
00200 
00201 /* This doesn't really work with aux data.  Use search/upload instead
00202  */
00203 unsigned brw_cache_data_sz(struct brw_cache *cache,
00204                          const void *data,
00205                          unsigned data_size)
00206 {
00207    unsigned addr;
00208 
00209    if (!brw_search_cache(cache, data, data_size, NULL, &addr)) {
00210       addr = brw_upload_cache(cache,
00211                               data, data_size,
00212                               data, data_size,
00213                               NULL, NULL);
00214    }
00215 
00216    return addr;
00217 }
00218 
00219 unsigned brw_cache_data(struct brw_cache *cache,
00220                       const void *data)
00221 {
00222    return brw_cache_data_sz(cache, data, cache->key_size);
00223 }
00224 
00225 enum pool_type {
00226    DW_SURFACE_STATE,
00227    DW_GENERAL_STATE
00228 };
00229 
00230 static void brw_init_cache( struct brw_context *brw,
00231                             const char *name,
00232                             unsigned id,
00233                             unsigned key_size,
00234                             unsigned aux_size,
00235                             enum pool_type pool_type)
00236 {
00237    struct brw_cache *cache = &brw->cache[id];
00238    cache->brw = brw;
00239    cache->id = id;
00240    cache->name = name;
00241    cache->items = NULL;
00242 
00243    cache->size = 7;
00244    cache->n_items = 0;
00245    cache->items = (struct brw_cache_item **)
00246       CALLOC(cache->size, sizeof(struct brw_cache_item));
00247 
00248 
00249    cache->key_size = key_size;
00250    cache->aux_size = aux_size;
00251    switch (pool_type) {
00252    case DW_GENERAL_STATE: cache->pool = &brw->pool[BRW_GS_POOL]; break;
00253    case DW_SURFACE_STATE: cache->pool = &brw->pool[BRW_SS_POOL]; break;
00254    default: assert(0); break;
00255    }
00256 }
00257 
00258 void brw_init_caches( struct brw_context *brw )
00259 {
00260 
00261    brw_init_cache(brw,
00262                   "CC_VP",
00263                   BRW_CC_VP,
00264                   sizeof(struct brw_cc_viewport),
00265                   0,
00266                   DW_GENERAL_STATE);
00267 
00268    brw_init_cache(brw,
00269                   "CC_UNIT",
00270                   BRW_CC_UNIT,
00271                   sizeof(struct brw_cc_unit_state),
00272                   0,
00273                   DW_GENERAL_STATE);
00274 
00275    brw_init_cache(brw,
00276                   "WM_PROG",
00277                   BRW_WM_PROG,
00278                   sizeof(struct brw_wm_prog_key),
00279                   sizeof(struct brw_wm_prog_data),
00280                   DW_GENERAL_STATE);
00281 
00282    brw_init_cache(brw,
00283                   "SAMPLER_DEFAULT_COLOR",
00284                   BRW_SAMPLER_DEFAULT_COLOR,
00285                   sizeof(struct brw_sampler_default_color),
00286                   0,
00287                   DW_GENERAL_STATE);
00288 
00289    brw_init_cache(brw,
00290                   "SAMPLER",
00291                   BRW_SAMPLER,
00292                   0,            /* variable key/data size */
00293                   0,
00294                   DW_GENERAL_STATE);
00295 
00296    brw_init_cache(brw,
00297                   "WM_UNIT",
00298                   BRW_WM_UNIT,
00299                   sizeof(struct brw_wm_unit_state),
00300                   0,
00301                   DW_GENERAL_STATE);
00302 
00303    brw_init_cache(brw,
00304                   "SF_PROG",
00305                   BRW_SF_PROG,
00306                   sizeof(struct brw_sf_prog_key),
00307                   sizeof(struct brw_sf_prog_data),
00308                   DW_GENERAL_STATE);
00309 
00310    brw_init_cache(brw,
00311                   "SF_VP",
00312                   BRW_SF_VP,
00313                   sizeof(struct brw_sf_viewport),
00314                   0,
00315                   DW_GENERAL_STATE);
00316 
00317    brw_init_cache(brw,
00318                   "SF_UNIT",
00319                   BRW_SF_UNIT,
00320                   sizeof(struct brw_sf_unit_state),
00321                   0,
00322                   DW_GENERAL_STATE);
00323 
00324    brw_init_cache(brw,
00325                   "VS_UNIT",
00326                   BRW_VS_UNIT,
00327                   sizeof(struct brw_vs_unit_state),
00328                   0,
00329                   DW_GENERAL_STATE);
00330 
00331    brw_init_cache(brw,
00332                   "VS_PROG",
00333                   BRW_VS_PROG,
00334                   sizeof(struct brw_vs_prog_key),
00335                   sizeof(struct brw_vs_prog_data),
00336                   DW_GENERAL_STATE);
00337 
00338    brw_init_cache(brw,
00339                   "CLIP_UNIT",
00340                   BRW_CLIP_UNIT,
00341                   sizeof(struct brw_clip_unit_state),
00342                   0,
00343                   DW_GENERAL_STATE);
00344 
00345    brw_init_cache(brw,
00346                   "CLIP_PROG",
00347                   BRW_CLIP_PROG,
00348                   sizeof(struct brw_clip_prog_key),
00349                   sizeof(struct brw_clip_prog_data),
00350                   DW_GENERAL_STATE);
00351 
00352    brw_init_cache(brw,
00353                   "GS_UNIT",
00354                   BRW_GS_UNIT,
00355                   sizeof(struct brw_gs_unit_state),
00356                   0,
00357                   DW_GENERAL_STATE);
00358 
00359    brw_init_cache(brw,
00360                   "GS_PROG",
00361                   BRW_GS_PROG,
00362                   sizeof(struct brw_gs_prog_key),
00363                   sizeof(struct brw_gs_prog_data),
00364                   DW_GENERAL_STATE);
00365 
00366    brw_init_cache(brw,
00367                   "SS_SURFACE",
00368                   BRW_SS_SURFACE,
00369                   sizeof(struct brw_surface_state),
00370                   0,
00371                   DW_SURFACE_STATE);
00372 
00373    brw_init_cache(brw,
00374                   "SS_SURF_BIND",
00375                   BRW_SS_SURF_BIND,
00376                   sizeof(struct brw_surface_binding_table),
00377                   0,
00378                   DW_SURFACE_STATE);
00379 }
00380 
00381 
00382 /* When we lose hardware context, need to invalidate the surface cache
00383  * as these structs must be explicitly re-uploaded.  They are subject
00384  * to fixup by the memory manager as they contain absolute agp
00385  * offsets, so we need to ensure there is a fresh version of the
00386  * struct available to receive the fixup.
00387  *
00388  * XXX: Need to ensure that there aren't two versions of a surface or
00389  * bufferobj with different backing data active in the same buffer at
00390  * once?  Otherwise the cache could confuse them.  Maybe better not to
00391  * cache at all?
00392  *
00393  * --> Isn't this the same as saying need to ensure batch is flushed
00394  *         before new data is uploaded to an existing buffer?  We
00395  *         already try to make sure of that.
00396  */
00397 static void clear_cache( struct brw_cache *cache )
00398 {
00399    struct brw_cache_item *c, *next;
00400    unsigned i;
00401 
00402    for (i = 0; i < cache->size; i++) {
00403       for (c = cache->items[i]; c; c = next) {
00404          next = c->next;
00405          free((void *)c->key);
00406          free(c);
00407       }
00408       cache->items[i] = NULL;
00409    }
00410 
00411    cache->n_items = 0;
00412 }
00413 
00414 void brw_clear_all_caches( struct brw_context *brw )
00415 {
00416    int i;
00417 
00418    if (BRW_DEBUG & DEBUG_STATE)
00419       debug_printf("%s\n", __FUNCTION__);
00420 
00421    for (i = 0; i < BRW_MAX_CACHE; i++)
00422       clear_cache(&brw->cache[i]);
00423 
00424    if (brw->curbe.last_buf) {
00425       FREE(brw->curbe.last_buf);
00426       brw->curbe.last_buf = NULL;
00427    }
00428 
00429    brw->state.dirty.brw |= ~0;
00430    brw->state.dirty.cache |= ~0;
00431 }
00432 
00433 
00434 
00435 
00436 
00437 void brw_destroy_caches( struct brw_context *brw )
00438 {
00439    unsigned i;
00440 
00441    for (i = 0; i < BRW_MAX_CACHE; i++)
00442       clear_cache(&brw->cache[i]);
00443 }

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