gallium: Several fixes to buffer caching.
authorJosé Fonseca <jrfonseca@tungstengraphics.com>
Tue, 15 Apr 2008 06:41:08 +0000 (15:41 +0900)
committerJosé Fonseca <jrfonseca@tungstengraphics.com>
Tue, 15 Apr 2008 06:41:08 +0000 (15:41 +0900)
src/gallium/auxiliary/pipebuffer/pb_buffer.h
src/gallium/auxiliary/pipebuffer/pb_bufmgr_cache.c
src/gallium/auxiliary/pipebuffer/pb_bufmgr_slab.c

index 4b09c80b2a1d992fe7f61dfd60795fdaaa5cd941..49705cb862733b30a953b6d77cf7c3dec8fe2bdb 100644 (file)
@@ -192,6 +192,17 @@ pb_reference(struct pb_buffer **dst,
 }
 
 
+/**
+ * Utility function to check whether a requested alignment is consistent with
+ * the provided alignment or not.
+ */
+static INLINE int
+pb_check_alignment(size_t requested, size_t provided)
+{
+   return requested <= provided && (provided % requested) == 0;
+}
+
+
 /**
  * Malloc-based buffer to store data that can't be used by the graphics 
  * hardware.
index 06de0bb6c37884e6f1c54c3fcc6860cce99bb9bf..543fd51253cce899be33a157b289e3aa6d73a7f4 100644 (file)
@@ -136,7 +136,7 @@ _pb_cache_buffer_list_check_free(struct pb_cache_manager *mgr)
    while(curr != &mgr->delayed) {
       buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
 
-      if(util_time_timeout(&buf->start, &buf->end, &now) != 0)
+      if(!util_time_timeout(&buf->start, &buf->end, &now))
         break;
         
       _pb_cache_buffer_destroy(buf);
@@ -202,6 +202,24 @@ pb_cache_buffer_vtbl = {
 };
 
 
+static INLINE boolean
+pb_cache_is_buffer_compat(struct pb_cache_buffer *buf,  
+                          size_t size,
+                          const struct pb_desc *desc)
+{
+   /* TODO: be more lenient with size */
+   if(buf->base.base.size != size)
+      return FALSE;
+   
+   if(!pb_check_alignment(desc->alignment, buf->base.base.alignment))
+      return FALSE;
+   
+   /* XXX: check usage too? */
+   
+   return TRUE;
+}
+
+
 static struct pb_buffer *
 pb_cache_manager_create_buffer(struct pb_manager *_mgr, 
                                size_t size,
@@ -209,29 +227,45 @@ pb_cache_manager_create_buffer(struct pb_manager *_mgr,
 {
    struct pb_cache_manager *mgr = pb_cache_manager(_mgr);
    struct pb_cache_buffer *buf;
+   struct pb_cache_buffer *curr_buf;
    struct list_head *curr, *next;
    struct util_time now;
    
-   util_time_get(&now);
+   _glthread_LOCK_MUTEX(mgr->mutex);
+
+   buf = NULL;
    curr = mgr->delayed.next;
    next = curr->next;
+   
+   /* search in the expired buffers, freeing them in the process */
+   util_time_get(&now);
    while(curr != &mgr->delayed) {
-      buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
-
-      if(buf->base.base.size == size &&
-        buf->base.base.alignment >= desc->alignment &&
-        (buf->base.base.alignment % desc->alignment) == 0 &&
-        /* buf->base.base.usage == usage */ 1) {
-        ++buf->base.base.refcount;
-        return &buf->base;
-      }
-      
-      if(util_time_timeout(&buf->start, &buf->end, &now) != 0)
-        _pb_cache_buffer_destroy(buf);
+      curr_buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
+      if(!buf && pb_cache_is_buffer_compat(curr_buf, size, desc))
+        buf = curr_buf;
+      else if(util_time_timeout(&curr_buf->start, &curr_buf->end, &now))
+        _pb_cache_buffer_destroy(curr_buf);
+      curr = next; 
+      next = curr->next;
+   }
 
+   /* keep searching in the hot buffers */
+   while(!buf && curr != &mgr->delayed) {
+      curr_buf = LIST_ENTRY(struct pb_cache_buffer, curr, head);
+      if(pb_cache_is_buffer_compat(curr_buf, size, desc))
+        buf = curr_buf;
       curr = next; 
       next = curr->next;
    }
+   
+   if(buf) {
+      LIST_DEL(&buf->head);
+      _glthread_UNLOCK_MUTEX(mgr->mutex);
+      ++buf->base.base.refcount;
+      return &buf->base;
+   }
+   
+   _glthread_UNLOCK_MUTEX(mgr->mutex);
 
    buf = CALLOC_STRUCT(pb_cache_buffer);
    if(!buf)
@@ -243,6 +277,11 @@ pb_cache_manager_create_buffer(struct pb_manager *_mgr,
       return NULL;
    }
    
+   assert(buf->buffer->base.refcount >= 1);
+   assert(pb_check_alignment(desc->alignment, buf->buffer->base.alignment));
+   assert((buf->buffer->base.usage & desc->usage) == desc->usage);
+   assert(buf->buffer->base.size >= size);
+   
    buf->base.base.refcount = 1;
    buf->base.base.alignment = buf->buffer->base.alignment;
    buf->base.base.usage = buf->buffer->base.usage;
index 9506ac9ae1042daf8aabf637b772e9a6fd86c0e4..b931455056e4b6013a15d37f19cade8470a74b55 100644 (file)
@@ -304,13 +304,6 @@ out_err0:
 }
 
 
-static int
-check_alignment(size_t requested, size_t provided)
-{
-   return requested <= provided && (provided % requested) == 0;
-}
-
-
 static struct pb_buffer *
 pb_slab_manager_create_buffer(struct pb_manager *_mgr,
                               size_t size,
@@ -328,11 +321,11 @@ pb_slab_manager_create_buffer(struct pb_manager *_mgr,
       return NULL;
    
    /* check if we can provide the requested alignment */
-   assert(check_alignment(desc->alignment, mgr->desc.alignment));
-   if(!check_alignment(desc->alignment, mgr->desc.alignment))
+   assert(pb_check_alignment(desc->alignment, mgr->desc.alignment));
+   if(!pb_check_alignment(desc->alignment, mgr->desc.alignment))
       return NULL;
-   assert(check_alignment(desc->alignment, mgr->bufSize));
-   if(!check_alignment(desc->alignment, mgr->bufSize))
+   assert(pb_check_alignment(desc->alignment, mgr->bufSize));
+   if(!pb_check_alignment(desc->alignment, mgr->bufSize))
       return NULL;
 
    /* XXX: check for compatible buffer usage too? */