Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / drivers / dri / i965 / brw_state_cache.c
index d614316ab6036ebfde09b1cda79beddc3a3e3f51..d5b51664066a0da6a8e861d105926e51fa5af23b 100644 (file)
@@ -44,8 +44,8 @@
  * consumers use structured keys).
  *
  * Replacement is not implemented.  Instead, when the cache gets too big, at
- * a safe point (unlock) we throw out all of the cache data let it regenerate
- * it for the next rendering operation.
+ * a safe point (unlock) we throw out all of the cache data and let it
+ * regenerate for the next rendering operation.
  *
  * The reloc_buf pointers need to be included as key data, otherwise the
  * non-unique values stuffed in the offset in key data through
@@ -58,7 +58,7 @@
 
 #include "brw_state.h"
 #include "intel_batchbuffer.h"
-#include "imports.h"
+#include "main/imports.h"
 
 /* XXX: Fixme - have to include these to get the sizes of the prog_key
  * structs:
@@ -69,7 +69,8 @@
 #include "brw_sf.h"
 #include "brw_gs.h"
 
-static GLuint hash_key( const void *key, GLuint key_size )
+static GLuint hash_key( const void *key, GLuint key_size,
+                       dri_bo **reloc_bufs, GLuint nr_reloc_bufs)
 {
    GLuint *ikey = (GLuint *)key;
    GLuint hash = 0, i;
@@ -78,8 +79,18 @@ static GLuint hash_key( const void *key, GLuint key_size )
 
    /* I'm sure this can be improved on:
     */
-   for (i = 0; i < key_size/4; i++)
+   for (i = 0; i < key_size/4; i++) {
       hash ^= ikey[i];
+      hash = (hash << 5) | (hash >> 27);
+   }
+
+   /* Include the BO pointers as key data as well */
+   ikey = (GLuint *)reloc_bufs;
+   key_size = nr_reloc_bufs * sizeof(dri_bo *);
+   for (i = 0; i < key_size/4; i++) {
+      hash ^= ikey[i];
+      hash = (hash << 5) | (hash >> 27);
+   }
 
    return hash;
 }
@@ -91,6 +102,9 @@ static void
 update_cache_last(struct brw_cache *cache, enum brw_cache_id cache_id,
                  dri_bo *bo)
 {
+   if (bo == cache->last_bo[cache_id])
+      return; /* no change */
+
    dri_bo_unreference(cache->last_bo[cache_id]);
    cache->last_bo[cache_id] = bo;
    dri_bo_reference(cache->last_bo[cache_id]);
@@ -104,6 +118,16 @@ search_cache(struct brw_cache *cache, enum brw_cache_id cache_id,
 {
    struct brw_cache_item *c;
 
+#if 0
+   int bucketcount = 0;
+
+   for (c = cache->items[hash % cache->size]; c; c = c->next)
+      bucketcount++;
+
+   fprintf(stderr, "bucket %d/%d = %d/%d items\n", hash % cache->size,
+          cache->size, bucketcount, cache->n_items);
+#endif
+
    for (c = cache->items[hash % cache->size]; c; c = c->next) {
       if (c->cache_id == cache_id &&
          c->hash == hash &&
@@ -151,7 +175,7 @@ dri_bo *brw_search_cache( struct brw_cache *cache,
                          void *aux_return )
 {
    struct brw_cache_item *item;
-   GLuint hash = hash_key(key, key_size);
+   GLuint hash = hash_key(key, key_size, reloc_bufs, nr_reloc_bufs);
 
    item = search_cache(cache, cache_id, hash, key, key_size,
                       reloc_bufs, nr_reloc_bufs);
@@ -181,7 +205,7 @@ brw_upload_cache( struct brw_cache *cache,
                  void *aux_return )
 {
    struct brw_cache_item *item = CALLOC_STRUCT(brw_cache_item);
-   GLuint hash = hash_key(key, key_size);
+   GLuint hash = hash_key(key, key_size, reloc_bufs, nr_reloc_bufs);
    GLuint relocs_size = nr_reloc_bufs * sizeof(dri_bo *);
    GLuint aux_size = cache->aux_size[cache_id];
    void *tmp;
@@ -190,10 +214,7 @@ brw_upload_cache( struct brw_cache *cache,
 
    /* Create the buffer object to contain the data */
    bo = dri_bo_alloc(cache->brw->intel.bufmgr,
-                    cache->name[cache_id], data_size, 1 << 6,
-                    DRM_BO_FLAG_MEM_LOCAL |
-                    DRM_BO_FLAG_CACHED |
-                    DRM_BO_FLAG_CACHED_MAPPED);
+                    cache->name[cache_id], data_size, 1 << 6);
 
 
    /* Set up the memory containing the key, aux_data, and reloc_bufs */
@@ -234,7 +255,7 @@ brw_upload_cache( struct brw_cache *cache,
    if (INTEL_DEBUG & DEBUG_STATE)
       _mesa_printf("upload %s: %d bytes to cache id %d\n",
                   cache->name[cache_id],
-                  data_size);
+                  data_size, cache_id);
 
    /* Copy data to the buffer */
    dri_bo_subdata(bo, 0, data_size, data);
@@ -256,11 +277,12 @@ brw_cache_data_sz(struct brw_cache *cache,
 {
    dri_bo *bo;
    struct brw_cache_item *item;
-   GLuint hash = hash_key(data, data_size);
+   GLuint hash = hash_key(data, data_size, reloc_bufs, nr_reloc_bufs);
 
    item = search_cache(cache, cache_id, hash, data, data_size,
                       reloc_bufs, nr_reloc_bufs);
    if (item) {
+      update_cache_last(cache, cache_id, item->bo);
       dri_bo_reference(item->bo);
       return item->bo;
    }
@@ -426,29 +448,17 @@ void brw_init_cache( struct brw_context *brw )
                     0);
 }
 
-
-/* When we lose hardware context, need to invalidate the surface cache
- * as these structs must be explicitly re-uploaded.  They are subject
- * to fixup by the memory manager as they contain absolute agp
- * offsets, so we need to ensure there is a fresh version of the
- * struct available to receive the fixup.
- *
- * XXX: Need to ensure that there aren't two versions of a surface or
- * bufferobj with different backing data active in the same buffer at
- * once?  Otherwise the cache could confuse them.  Maybe better not to
- * cache at all?
- * 
- * --> Isn't this the same as saying need to ensure batch is flushed
- *         before new data is uploaded to an existing buffer?  We
- *         already try to make sure of that.
- */
-static void clear_cache( struct brw_cache *cache )
+static void
+brw_clear_cache( struct brw_context *brw )
 {
    struct brw_cache_item *c, *next;
    GLuint i;
 
-   for (i = 0; i < cache->size; i++) {
-      for (c = cache->items[i]; c; c = next) {
+   if (INTEL_DEBUG & DEBUG_STATE)
+      _mesa_printf("%s\n", __FUNCTION__);
+
+   for (i = 0; i < brw->cache.size; i++) {
+      for (c = brw->cache.items[i]; c; c = next) {
         int j;
 
         next = c->next;
@@ -458,18 +468,10 @@ static void clear_cache( struct brw_cache *cache )
         free((void *)c->key);
         free(c);
       }
-      cache->items[i] = NULL;
+      brw->cache.items[i] = NULL;
    }
 
-   cache->n_items = 0;
-}
-
-void brw_clear_cache( struct brw_context *brw )
-{
-   if (INTEL_DEBUG & DEBUG_STATE)
-      _mesa_printf("%s\n", __FUNCTION__);
-
-   clear_cache(&brw->cache);
+   brw->cache.n_items = 0;
 
    if (brw->curbe.last_buf) {
       _mesa_free(brw->curbe.last_buf);
@@ -494,10 +496,11 @@ void brw_destroy_cache( struct brw_context *brw )
 {
    GLuint i;
 
-   clear_cache(&brw->cache);
-   for (i = 0; i < BRW_MAX_CACHE; i++)
+   brw_clear_cache(brw);
+   for (i = 0; i < BRW_MAX_CACHE; i++) {
+      dri_bo_unreference(brw->cache.last_bo[i]);
       free(brw->cache.name[i]);
-
+   }
    free(brw->cache.items);
    brw->cache.items = NULL;
    brw->cache.size = 0;