[intel] Add a simple relocation cache to the fake buffer manager.
authorEric Anholt <eric@anholt.net>
Fri, 16 Nov 2007 22:45:26 +0000 (14:45 -0800)
committerEric Anholt <eric@anholt.net>
Fri, 16 Nov 2007 23:36:18 +0000 (15:36 -0800)
This is required for 965 performance, as it avoids a lot of repeated data
uploads of the state caches due to surface offsets in them.

src/mesa/drivers/dri/common/dri_bufmgr_fake.c

index 863484c..48a0a3c 100644 (file)
@@ -125,8 +125,21 @@ typedef struct _bufmgr_fake {
    struct fake_buffer_reloc reloc[MAX_RELOCS];
    GLuint nr_relocs;
    GLboolean performed_rendering;
+   GLboolean in_relocation;
 } dri_bufmgr_fake;
 
+#define RELOC_CACHE_COUNT 10
+/**
+ * Relocation cache entry.
+ *
+ * These are used in buffer relocation to avoid re-mapping (and therefore
+ * dirtying) a buffer to emit constant relocations.
+ */
+struct reloc_cache {
+   unsigned int offset;
+   uint32_t data;
+};
+
 typedef struct _dri_bo_fake {
    dri_bo bo;
 
@@ -143,13 +156,20 @@ typedef struct _dri_bo_fake {
    unsigned int alignment;
    GLboolean is_static, validated;
    unsigned int map_count;
-   /* Relocation count to assist in determining the order to perform
-    * relocations.
+   /**
+    *  Relocation count with this as reloc_buffer, to assist in determining the
+    * order to perform relocations.
     */
    unsigned int nr_relocs;
+   struct reloc_cache reloc_cache[RELOC_CACHE_COUNT];
+
    /* Flags for the buffer to be validated with in command submission */
    uint64_t validate_flags;
 
+   /* Number of entries in the relocation data cache */
+   unsigned int reloc_cache_count;
+   
+
    struct block *block;
    void *backing_store;
    void (*invalidate_cb)(dri_bufmgr *bufmgr, void * );
@@ -669,6 +689,11 @@ dri_fake_bo_map(dri_bo *bo, GLboolean write_enable)
       return 0;
    }
 
+   /* Clear the relocation cache if unknown data is going to be written in. */
+   if (!bufmgr_fake->in_relocation && write_enable) {
+      bo_fake->reloc_cache_count = 0;
+   }
+
    {
       DBG("drm_bo_map: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
          bo_fake->bo.size / 1024);
@@ -925,6 +950,7 @@ dri_fake_process_relocs(dri_bo *batch_buf, GLuint *count_p)
    int ret;
 
    bufmgr_fake->performed_rendering = GL_FALSE;
+   bufmgr_fake->in_relocation = GL_TRUE;
 
    /* Loop over the relocation list validating and writing the relocation
     * entries for target buffers that don't contain any remaining relocations.
@@ -938,53 +964,82 @@ dri_fake_process_relocs(dri_bo *batch_buf, GLuint *count_p)
         struct fake_buffer_reloc *r = &bufmgr_fake->reloc[i];
         dri_bo_fake *reloc_fake = (dri_bo_fake *)r->reloc_buf;
         dri_bo_fake *target_fake = (dri_bo_fake *)r->target_buf;
+        uint32_t reloc_data;
+        int c;
+        GLboolean cached = GL_FALSE;
 
         if (r->relocated)
            continue;
 
-        if (target_fake->nr_relocs == 0) {
-           /* Validate the target if it hasn't been.  If we fail, fence to
-            * clear the unfenced list and bail out.
-            */
-           if (!target_fake->validated) {
-              int ret;
-
-              ret = dri_fake_bo_validate(r->target_buf,
-                                         target_fake->validate_flags);
-              if (ret != 0) {
-                 dri_fence *fo;
-
-                 dri_bo_unmap(r->reloc_buf);
-                 fo = dri_fake_fence_validated(batch_buf->bufmgr,
-                                               "batchbuffer failure fence",
-                                               GL_TRUE);
-                 dri_fence_unreference(fo);
-                 goto done;
-              }
-              if (target_fake->validate_flags & DRM_BO_FLAG_WRITE)
-                 bufmgr_fake->performed_rendering = GL_TRUE;
-              count++;
+        /* If there are still relocations to be done in the buffer, don't
+         * validate it yet.
+         */
+        if (target_fake->nr_relocs != 0)
+           continue;
+
+        /* Validate the target buffer if that hasn't been done. */
+        if (!target_fake->validated) {
+           ret = dri_fake_bo_validate(r->target_buf,
+                                      target_fake->validate_flags);
+           if (ret != 0) {
+              dri_fence *fo;
+
+              dri_bo_unmap(r->reloc_buf);
+              fo = dri_fake_fence_validated(batch_buf->bufmgr,
+                                            "batchbuffer failure fence",
+                                            GL_TRUE);
+              dri_fence_unreference(fo);
+              goto done;
+           }
+           if (target_fake->validate_flags & DRM_BO_FLAG_WRITE)
+              bufmgr_fake->performed_rendering = GL_TRUE;
+           count++;
+        }
+
+        /* Calculate the value of the relocation entry. */
+
+        reloc_data = r->target_buf->offset + r->delta;
+
+        /* Check the relocation cache of the buffer to see if we don't need
+         * to bother writing this one.
+         */
+        for (c = 0; c < reloc_fake->reloc_cache_count; c++) {
+           if (reloc_fake->reloc_cache[c].offset == r->offset &&
+               reloc_fake->reloc_cache[c].data == reloc_data) {
+              cached = GL_TRUE;
            }
+        }
 
+        if (!cached) {
            /* Map and write in the relocation to reloc_buf */
            if (reloc_fake->map_count == 0)
               dri_bo_map(r->reloc_buf, GL_TRUE);
 
-           *(uint32_t *)(r->reloc_buf->virtual + r->offset) =
-              r->target_buf->offset + r->delta;
+           *(uint32_t *)(r->reloc_buf->virtual + r->offset) = reloc_data;
 
-           /* Mark this relocation in reloc_buf as done.  If it was the last
-            * one to be done to it, unmap the buffer so it can be validated
-            * next.
-            */
-           reloc_fake->nr_relocs--;
-           if (reloc_fake->nr_relocs == 0)
-              dri_bo_unmap(r->reloc_buf);
+           /* Stick this new entry in the relocation cache if possible */
+           if (reloc_fake->reloc_cache_count < RELOC_CACHE_COUNT) {
+              struct reloc_cache *entry;
 
-           r->relocated = GL_TRUE;
+              entry = &reloc_fake->reloc_cache[reloc_fake->reloc_cache_count];
+              entry->offset = r->offset;
+              entry->data = reloc_data;
 
-           cont = GL_TRUE;
+              reloc_fake->reloc_cache_count++;
+           }
         }
+
+        /* Mark this relocation in reloc_buf as done.  If it was the last
+         * reloc to be done to it, unmap the buffer so it can be validated
+         * next.
+         */
+        reloc_fake->nr_relocs--;
+        if (reloc_fake->nr_relocs == 0 && reloc_fake->map_count != 0)
+           dri_bo_unmap(r->reloc_buf);
+
+        r->relocated = GL_TRUE;
+
+        cont = GL_TRUE;
       }
    } while (cont);
 
@@ -992,6 +1047,7 @@ dri_fake_process_relocs(dri_bo *batch_buf, GLuint *count_p)
    assert(ret == 0);
 
    *count_p = count;
+   bufmgr_fake->in_relocation = GL_FALSE;
  done:
    return NULL;
 }