gallium: Reusable pipe buffer library.
authorJosé Fonseca <jrfonseca@tungstengraphics.com>
Fri, 23 Nov 2007 17:22:54 +0000 (17:22 +0000)
committerJosé Fonseca <jrfonseca@tungstengraphics.com>
Sun, 9 Dec 2007 14:06:00 +0000 (14:06 +0000)
This is an optional library that winsys drivers can use to simplify memory
management, and help meet the winsys interface requirements.

16 files changed:
src/mesa/pipe/Makefile
src/mesa/pipe/pipebuffer/Makefile [new file with mode: 0644]
src/mesa/pipe/pipebuffer/linked_list.h [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer.h [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_client.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_fenced.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_fenced.h [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_handle.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_handle.h [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_malloc.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_buffer_null.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_bufmgr.h [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c [new file with mode: 0644]
src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c [new file with mode: 0644]

index a9dc393417d785982409d2523d6bc09bbe2a0d9c..2bf7318d59a3e8fc637645cb88fe6c1e1d3c3c7f 100644 (file)
@@ -1,4 +1,3 @@
-
 TOP = ../../..
 include $(TOP)/configs/current
 
@@ -7,7 +6,7 @@ ifeq ($(CONFIG_NAME), linux-cell)
 CELL_DIR = cell
 endif
 
-SUBDIRS = softpipe i915simple failover $(CELL_DIR)
+SUBDIRS = softpipe i915simple failover pipebuffer $(CELL_DIR)
 
 
 default: subdirs
@@ -22,4 +21,4 @@ subdirs:
 
 
 clean:
-       rm -f `find . -name \*.[oa]`
\ No newline at end of file
+       rm -f `find . -name \*.[oa]`
diff --git a/src/mesa/pipe/pipebuffer/Makefile b/src/mesa/pipe/pipebuffer/Makefile
new file mode 100644 (file)
index 0000000..061d8a0
--- /dev/null
@@ -0,0 +1,27 @@
+
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = pipebuffer
+
+       
+DRIVER_SOURCES = \
+       pb_buffer.c \
+       pb_buffer_client.c \
+       pb_buffer_handle.c \
+       pb_buffer_fenced.c \
+       pb_buffer_malloc.c \
+       pb_buffer_null.c \
+       pb_bufmgr_fenced.c \
+       pb_bufmgr_mm.c \
+       pb_bufmgr_pool.c
+
+C_SOURCES = \
+       $(DRIVER_SOURCES)
+
+ASM_SOURCES = 
+
+include ../Makefile.template
+
+symlinks:
+
diff --git a/src/mesa/pipe/pipebuffer/linked_list.h b/src/mesa/pipe/pipebuffer/linked_list.h
new file mode 100644 (file)
index 0000000..e99817f
--- /dev/null
@@ -0,0 +1,91 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ **************************************************************************/
+
+/**
+ * \file
+ * List macros heavily inspired by the Linux kernel
+ * list handling. No list looping yet.
+ * 
+ * Is not threadsafe, so common operations need to
+ * be protected using an external mutex.
+ */
+
+#ifndef LINKED_LIST_H_
+#define LINKED_LIST_H_
+
+
+#include <stddef.h>
+
+
+struct list_head
+{
+    struct list_head *prev;
+    struct list_head *next;
+};
+
+
+#define LIST_INITHEAD(__item)                  \
+  do {                                         \
+    (__item)->prev = (__item);                 \
+    (__item)->next = (__item);                 \
+  } while (0)
+
+#define LIST_ADD(__item, __list)               \
+  do {                                         \
+    (__item)->prev = (__list);                 \
+    (__item)->next = (__list)->next;           \
+    (__list)->next->prev = (__item);           \
+    (__list)->next = (__item);                 \
+  } while (0)
+
+#define LIST_ADDTAIL(__item, __list)           \
+  do {                                         \
+    (__item)->next = (__list);                 \
+    (__item)->prev = (__list)->prev;           \
+    (__list)->prev->next = (__item);           \
+    (__list)->prev = (__item);                 \
+  } while(0)
+
+#define LIST_DEL(__item)                       \
+  do {                                         \
+    (__item)->prev->next = (__item)->next;     \
+    (__item)->next->prev = (__item)->prev;     \
+  } while(0)
+
+#define LIST_DELINIT(__item)                   \
+  do {                                         \
+    (__item)->prev->next = (__item)->next;     \
+    (__item)->next->prev = (__item)->prev;     \
+    (__item)->next = (__item);                 \
+    (__item)->prev = (__item);                 \
+  } while(0)
+
+#define LIST_ENTRY(__type, __item, __field)   \
+    ((__type *)(((char *)(__item)) - offsetof(__type, __field)))
+
+
+#endif /*LINKED_LIST_H_*/
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer.c b/src/mesa/pipe/pipebuffer/pb_buffer.c
new file mode 100644 (file)
index 0000000..99c960b
--- /dev/null
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Buffer implementation.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+#include "pb_buffer.h"
+
+
+void
+buffer_reference(struct pipe_buffer **dst,
+                 struct pipe_buffer *src)
+{
+   if(*dst != src) {
+      if (src)
+         src->vtbl->reference(src);
+      
+      if (*dst)
+         (*dst)->vtbl->release(*dst);
+   
+      *dst = src;
+   }
+}
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer.h b/src/mesa/pipe/pipebuffer/pb_buffer.h
new file mode 100644 (file)
index 0000000..0523531
--- /dev/null
@@ -0,0 +1,175 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Generic code for buffers.
+ * 
+ * Behind a pipe buffle handle there can be DMA buffers, client (or user) 
+ * buffers, regular malloced buffers, etc. This file provides an abstract base 
+ * buffer handle that allows the driver to cope with all those kinds of buffers 
+ * in a more flexible way.
+ * 
+ * There is no obligation of a winsys driver to use this library. And a pipe
+ * driver should be completly agnostic about it.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+#ifndef PB_BUFFER_H_
+#define PB_BUFFER_H_
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+struct pipe_buffer_vtbl;
+
+
+/**
+ * Base class for all pipe buffers.
+ */
+struct pipe_buffer 
+{
+   /**
+    * Pointer to the virtual function table.
+    *
+    * Avoid accessing this table directly. Use the inline functions below 
+    * instead to avoid mistakes. 
+    */
+   const struct pipe_buffer_vtbl *vtbl;
+};
+
+
+/**
+ * Virtual function table for the buffer storage operations.
+ * 
+ * Note that creation is not done through this table.
+ */
+struct pipe_buffer_vtbl
+{
+   /**
+    * Add a reference to the buffer.
+    *
+    * This method can be a no-op for buffers that don't need reference
+    * counting.
+    */
+   void (*reference)( struct pipe_buffer *buf );
+
+   /**
+    * Release a reference to this buffer and destroy it.
+    */
+   void (*release)( struct pipe_buffer *buf );
+
+   /** 
+    * Map the entire data store of a buffer object into the client's address.
+    * flags is bitmask of PIPE_BUFFER_FLAG_READ/WRITE. 
+    */
+   void *(*map)( struct pipe_buffer *buf, 
+                 unsigned flags );
+   
+   void (*unmap)( struct pipe_buffer *buf );
+
+   /**
+    * Get the base buffer and the offset.
+    * 
+    * A buffer can be subdivided in smaller buffers. This method should return
+    * the underlaying buffer, and the relative offset.
+    * 
+    * Buffers without an underlaying base buffer should return themselves, with 
+    * a zero offset.
+    * 
+    * Note that this will increase the reference count of the base buffer.
+    */
+   void (*get_base_buffer)( struct pipe_buffer *buf,
+                            struct pipe_buffer **base_buf,
+                            unsigned *offset );
+};
+
+
+/** *dst = src with reference counting */
+void
+buffer_reference(struct pipe_buffer **dst,
+                 struct pipe_buffer *src);
+
+
+static inline void
+buffer_release(struct pipe_buffer *buf)
+{
+   assert(buf);
+   buf->vtbl->release(buf);
+}
+
+
+static inline void *
+buffer_map(struct pipe_buffer *buf, 
+           unsigned flags)
+{
+   assert(buf);
+   return buf->vtbl->map(buf, flags);
+}
+
+
+static inline void 
+buffer_unmap(struct pipe_buffer *buf)
+{
+   assert(buf);
+   buf->vtbl->unmap(buf);
+}
+
+
+static inline void
+buffer_get_base_buffer( struct pipe_buffer *buf,
+                        struct pipe_buffer **base_buf,
+                        unsigned *offset )
+{
+   buf->vtbl->get_base_buffer(buf, base_buf, offset);
+}
+
+
+/** Placeholder for empty buffers. */
+extern struct pipe_buffer null_buffer;
+
+
+/**
+ * Client buffers (also designated as user buffers) are just for convenience 
+ * of the state tracker, so that it can masquerade its own data as a buffer.
+ */
+struct pipe_buffer *
+client_buffer_create(void *data);
+
+
+/**
+ * Malloc-based buffer to store data that can't be used by the graphics 
+ * hardware.
+ */
+struct pipe_buffer *
+malloc_buffer_create(unsigned size);
+
+
+#endif /*PB_BUFFER_H_*/
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_client.c b/src/mesa/pipe/pipebuffer/pb_buffer_client.c
new file mode 100644 (file)
index 0000000..bb7f5a9
--- /dev/null
@@ -0,0 +1,123 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Implementation of client buffer (also designated as "user buffers"), which
+ * are just state-tracker owned data masqueraded as buffers.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+#include "pb_buffer.h"
+
+
+struct client_buffer 
+{
+   struct pipe_buffer base;
+   void *data;
+};
+
+
+extern const struct pipe_buffer_vtbl client_buffer_vtbl;
+
+
+static inline struct client_buffer *
+client_buffer(struct pipe_buffer *buf)
+{
+   assert(buf);
+   assert(buf->vtbl == &client_buffer_vtbl);
+   return (struct client_buffer *)buf;
+}
+
+
+static void
+client_buffer_reference(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+client_buffer_release(struct pipe_buffer *buf)
+{
+   assert(buf);
+   free(buf);
+}
+
+
+static void *
+client_buffer_map(struct pipe_buffer *buf, 
+                  unsigned flags)
+{
+   return client_buffer(buf)->data;
+}
+
+
+static void
+client_buffer_unmap(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+client_buffer_get_base_buffer(struct pipe_buffer *buf,
+                              struct pipe_buffer **base_buf,
+                              unsigned *offset)
+{
+   *base_buf = buf;
+   *offset = 0;
+}
+
+
+const struct pipe_buffer_vtbl 
+client_buffer_vtbl = {
+      client_buffer_reference,
+      client_buffer_release,
+      client_buffer_map,
+      client_buffer_unmap,
+      client_buffer_get_base_buffer
+};
+
+
+struct pipe_buffer *
+client_buffer_create(void *data) 
+{
+   struct client_buffer *buf;
+   
+   buf = (struct client_buffer *)malloc(sizeof(struct client_buffer));
+   if(!buf)
+      return NULL;
+   
+   buf->base.vtbl = &client_buffer_vtbl;
+   
+   buf->data = data;
+   
+   return &buf->base;
+}
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_fenced.c b/src/mesa/pipe/pipebuffer/pb_buffer_fenced.c
new file mode 100644 (file)
index 0000000..c5a06c5
--- /dev/null
@@ -0,0 +1,340 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Implementation of fenced buffers.
+ * 
+ * \author José Fonseca <jrfonseca-at-tungstengraphics-dot-com>
+ * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main/imports.h"
+#include "glapi/glthread.h"
+#include "linked_list.h"
+
+#include "p_winsys.h"
+
+#include "pb_buffer.h"
+#include "pb_buffer_fenced.h"
+
+
+/**
+ * Convenience macro (type safe).
+ */
+#define SUPER(__derived) (&(__derived)->base)
+
+
+struct fenced_buffer_list
+{
+   _glthread_Mutex mutex;
+   
+   struct pipe_winsys *winsys;
+   
+   size_t numDelayed;
+   size_t checkDelayed;
+   
+   struct list_head delayed;
+};
+
+
+/**
+ * Wrapper around a pipe buffer which adds fencing and reference counting.
+ */
+struct fenced_buffer
+{
+   struct pipe_buffer base;
+   
+   struct pipe_buffer *buffer;
+
+   unsigned refcount;
+   struct pipe_fence_handle *fence;
+
+   struct list_head head;
+   struct fenced_buffer_list *list;
+};
+
+
+static inline struct fenced_buffer *
+fenced_buffer(struct pipe_buffer *buf)
+{
+   assert(buf);
+   assert(buf->vtbl == &fenced_buffer_vtbl);
+   return (struct fenced_buffer *)buf;
+}
+
+
+static void
+_fenced_buffer_destroy(struct fenced_buffer *fenced_buf)
+{
+   buffer_release(fenced_buf->buffer);
+   free(fenced_buf);
+}
+
+
+static void
+_fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 
+                               int wait)
+{
+   struct pipe_winsys *winsys = fenced_list->winsys;
+   struct fenced_buffer *fenced_buf;   
+   struct list_head *list, *prev;
+   int signaled = -1;
+   int i;
+
+   list = fenced_list->delayed.next;
+
+   if (fenced_list->numDelayed > 3) {
+      for (i = 0; i < fenced_list->numDelayed; i += 3) {
+         list = list->next;
+      }
+   }
+
+   prev = list->prev;
+   for (; list != &fenced_list->delayed; list = prev, prev = list->prev) {
+
+      fenced_buf = LIST_ENTRY(struct fenced_buffer, list, head);
+
+      if (signaled != 0) {
+         if (wait) {
+            signaled = winsys->fence_finish(winsys, fenced_buf->fence, 0);
+         }
+         else {
+            signaled = winsys->fence_signalled(winsys, fenced_buf->fence, 0);
+         }
+      }
+
+      if (signaled != 0)
+        /* XXX: we are assuming that buffers are freed in the same order they 
+         * are fenced which may not always be true... 
+         */
+         break;
+
+      winsys->fence_reference(winsys, &fenced_buf->fence, NULL);
+      
+      LIST_DEL(list);
+      fenced_list->numDelayed--;
+      
+      _fenced_buffer_destroy(fenced_buf);
+   }
+}
+
+
+static void
+fenced_buffer_reference(struct pipe_buffer *buf) 
+{
+   struct fenced_buffer *fenced_buf = fenced_buffer(buf);   
+   struct fenced_buffer_list *fenced_list = fenced_buf->list;
+
+   _glthread_LOCK_MUTEX(fenced_list->mutex);
+   fenced_buf->refcount++;
+   _glthread_UNLOCK_MUTEX(fenced_list->mutex);
+}
+
+
+static void
+fenced_buffer_release(struct pipe_buffer *buf)
+{
+   struct fenced_buffer *fenced_buf = fenced_buffer(buf);   
+   struct fenced_buffer_list *fenced_list = fenced_buf->list;
+
+   _glthread_LOCK_MUTEX(fenced_list->mutex);
+
+   fenced_buf->refcount--;
+   if(!fenced_buf->refcount) {
+      if (fenced_buf->fence) {
+         LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed);
+         fenced_list->numDelayed++;
+      }
+      else {
+         _fenced_buffer_destroy(fenced_buf);
+      }
+   
+      if ((fenced_list->numDelayed % fenced_list->checkDelayed) == 0)
+         _fenced_buffer_list_check_free(fenced_list, 0);
+   }
+   
+   _glthread_UNLOCK_MUTEX(fenced_list->mutex);
+}
+
+
+static void *
+fenced_buffer_map(struct pipe_buffer *buf, 
+                  unsigned flags)
+{
+   struct fenced_buffer *fenced_buf = fenced_buffer(buf);   
+   return buffer_map(fenced_buf->buffer, flags);
+}
+
+
+static void
+fenced_buffer_unmap(struct pipe_buffer *buf)
+{
+   struct fenced_buffer *fenced_buf = fenced_buffer(buf);   
+   buffer_unmap(fenced_buf->buffer);
+}
+
+
+static void
+fenced_buffer_get_base_buffer(struct pipe_buffer *buf,
+                              struct pipe_buffer **base_buf,
+                              unsigned *offset)
+{
+   struct fenced_buffer *fenced_buf = fenced_buffer(buf);
+   buffer_get_base_buffer(fenced_buf->buffer, base_buf, offset);
+}
+
+
+const struct pipe_buffer_vtbl 
+fenced_buffer_vtbl = {
+      fenced_buffer_reference,
+      fenced_buffer_release,
+      fenced_buffer_map,
+      fenced_buffer_unmap,
+      fenced_buffer_get_base_buffer
+};
+
+
+struct pipe_buffer *
+fenced_buffer_create(struct fenced_buffer_list *fenced_list, 
+                     struct pipe_buffer *buffer)
+{
+   struct fenced_buffer *buf;
+   
+   buf = (struct fenced_buffer *)calloc(1, sizeof(struct fenced_buffer));
+   if(!buf)
+      return NULL;
+   
+   buf->base.vtbl = &fenced_buffer_vtbl;
+   buf->buffer = buffer;
+   buf->refcount = 1;
+   buf->list = fenced_list;
+   
+   return &buf->base;
+}
+
+
+void
+buffer_fence(struct pipe_buffer *buf,
+             struct pipe_fence_handle *fence)
+{
+   if(buf->vtbl == &fenced_buffer_vtbl) {
+      struct fenced_buffer *fenced_buf = fenced_buffer(buf);
+      struct fenced_buffer_list *fenced_list = fenced_buf->list;
+      struct pipe_winsys *winsys = fenced_list->winsys;
+   
+      _glthread_LOCK_MUTEX(fenced_list->mutex);
+      winsys->fence_reference(winsys, &fenced_buf->fence, fence);
+      _glthread_UNLOCK_MUTEX(fenced_list->mutex);
+   }
+   else
+      assert(0);
+}
+
+
+void
+buffer_unfence(struct pipe_buffer *buf)
+{
+   buffer_fence(buf, NULL);
+}
+
+
+int
+buffer_finish(struct pipe_buffer *buf, 
+             unsigned flag)
+{
+   if(buf->vtbl == &fenced_buffer_vtbl) {
+      struct fenced_buffer *fenced_buf = fenced_buffer(buf);
+      if(fenced_buf->fence) {
+         struct fenced_buffer_list *fenced_list = fenced_buf->list;
+         struct pipe_winsys *winsys = fenced_list->winsys;         
+         return winsys->fence_finish(winsys, fenced_buf->fence, flag);
+      }
+   }
+   
+   return 0;
+}
+
+
+struct fenced_buffer_list *
+fenced_buffer_list_create(struct pipe_winsys *winsys) 
+{
+   struct fenced_buffer_list *fenced_list;
+
+   fenced_list = (struct fenced_buffer_list *)calloc(1, sizeof(*fenced_list));
+   if (!fenced_list)
+      return NULL;
+
+   fenced_list->winsys = winsys;
+
+   LIST_INITHEAD(&fenced_list->delayed);
+
+   fenced_list->numDelayed = 0;
+   
+   /* TODO: don't hard code this */ 
+   fenced_list->checkDelayed = 5;
+
+   _glthread_INIT_MUTEX(fenced_list->mutex);
+
+   return fenced_list;
+}
+
+
+void
+fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 
+                              int wait)
+{
+   _glthread_LOCK_MUTEX(fenced_list->mutex);
+   _fenced_buffer_list_check_free(fenced_list, wait);
+   _glthread_UNLOCK_MUTEX(fenced_list->mutex);
+}
+
+
+void
+fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list)
+{
+   _glthread_LOCK_MUTEX(fenced_list->mutex);
+
+   /* Wait on outstanding fences */
+   while (fenced_list->numDelayed) {
+      _glthread_UNLOCK_MUTEX(fenced_list->mutex);
+      sched_yield();
+      _fenced_buffer_list_check_free(fenced_list, GL_TRUE);
+      _glthread_LOCK_MUTEX(fenced_list->mutex);
+   }
+
+   _glthread_UNLOCK_MUTEX(fenced_list->mutex);
+   
+   free(fenced_list);
+}
+
+
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_fenced.h b/src/mesa/pipe/pipebuffer/pb_buffer_fenced.h
new file mode 100644 (file)
index 0000000..d12428e
--- /dev/null
@@ -0,0 +1,138 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Buffer fencing.
+ * 
+ * "Fenced buffers" is actually a misnomer. They should be referred as 
+ * "fenceable buffers", i.e, buffers that can be fenced, but I couldn't find
+ * the word "fenceable" in the dictionary.
+ * 
+ * A "fenced buffer" is a decorator around a normal buffer, which adds two 
+ * special properties:
+ * - the ability for the destruction to be delayed by a fence;
+ * - reference counting.
+ * 
+ * Usually DMA buffers have a life-time that will extend the life-time of its 
+ * handle. The end-of-life is dictated by the fence signalling. 
+ * 
+ * Between the handle's destruction, and the fence signalling, the buffer is 
+ * stored in a fenced buffer list.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+#ifndef PB_BUFFER_FENCED_H_
+#define PB_BUFFER_FENCED_H_
+
+
+#include <assert.h>
+
+
+struct pipe_winsys;
+struct pipe_buffer;
+struct pipe_fence_handle;
+
+
+/**
+ * List of buffers which are awaiting fence signalling.
+ */
+struct fenced_buffer_list;
+
+
+/**
+ * The fenced buffer's virtual function table.
+ * 
+ * NOTE: Made public for debugging purposes.
+ */
+extern const struct pipe_buffer_vtbl fenced_buffer_vtbl;
+
+
+/**
+ * Create a fenced buffer list.
+ * 
+ * See also fenced_bufmgr_create for a more convenient way to use this.
+ */
+struct fenced_buffer_list *
+fenced_buffer_list_create(struct pipe_winsys *winsys);
+
+
+/**
+ * Walk the fenced buffer list to check and free signalled buffers.
+ */ 
+void
+fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, 
+                              int wait);
+
+void
+fenced_buffer_list_destroy(struct fenced_buffer_list *fenced_list);
+
+
+/**
+ * Wrap a buffer in a fenced buffer.
+ * 
+ * NOTE: this will not increase the buffer reference count.
+ */
+struct pipe_buffer *
+fenced_buffer_create(struct fenced_buffer_list *fenced, 
+                     struct pipe_buffer *buffer);
+
+
+/**
+ * Set a buffer's fence.
+ * 
+ * NOTE: Although it takes a generic pipe buffer argument, it will fail
+ * on everything but buffers returned by fenced_buffer_create.
+ */
+void
+buffer_fence(struct pipe_buffer *buf,
+             struct pipe_fence_handle *fence);
+
+
+/**
+ * Remove the buffer's fence.
+ * 
+ * NOTE: Although it takes a generic pipe buffer argument, it will fail
+ * on everything but buffers returned by fenced_buffer_create.
+ */
+void
+buffer_unfence(struct pipe_buffer *buf);
+
+
+/**
+ * Wait for the buffer fence to signal.
+ *
+ * See also pipe_winsys::fence_finish().
+ */ 
+int
+buffer_finish(struct pipe_buffer *buf, 
+              unsigned flag);
+
+
+
+#endif /*PB_BUFFER_FENCED_H_*/
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_handle.c b/src/mesa/pipe/pipebuffer/pb_buffer_handle.c
new file mode 100644 (file)
index 0000000..5a5eaee
--- /dev/null
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Drop-in implementation of the winsys driver functions for buffer handles.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pipe/p_winsys.h"
+#include "pipe/p_defines.h"
+
+#include "pb_buffer.h"
+#include "pb_buffer_handle.h"
+
+
+static struct pipe_buffer_handle *
+buffer_handle_create(struct pipe_winsys *winsys,
+                     unsigned alignment,
+                     unsigned flags,
+                     unsigned hint)
+{
+   struct pipe_buffer_handle *handle;
+  
+   handle = (struct pipe_buffer_handle *)malloc(sizeof(struct pipe_buffer_handle));
+   if(!handle)
+      return NULL;
+   
+   handle->refcount = 1;
+   handle->alignment = alignment;
+   handle->flags = flags;
+   handle->hint = hint;
+   
+   handle->buf = &null_buffer;
+   
+   return handle;
+}
+
+
+static struct pipe_buffer_handle *
+buffer_handle_create_user(struct pipe_winsys *winsys, 
+                          void *data, unsigned size)
+{
+   struct pipe_buffer_handle *handle;
+   struct pipe_buffer *buf;
+   
+   handle = buffer_handle_create(winsys, 1, 0, 0);
+   if(!handle)
+      return NULL;
+   
+   buf = client_buffer_create(data);
+   if(!buf) {
+      free(handle);
+      return NULL;
+   }
+   
+   buffer_handle_data(handle, buf);
+   
+   return handle;
+}
+
+
+static void *
+buffer_handle_map(struct pipe_winsys *winsys,
+                  struct pipe_buffer_handle *handle, 
+                  unsigned flags)
+{
+   return buffer_map(handle->buf, flags);
+}
+
+
+static void 
+buffer_handle_unmap(struct pipe_winsys *winsys,
+                    struct pipe_buffer_handle *handle)
+{
+   buffer_unmap(handle->buf);
+}
+
+
+static void
+buffer_handle_reference(struct pipe_winsys *winsys,
+                        struct pipe_buffer_handle **dst,
+                       struct pipe_buffer_handle *src)
+{
+   /* XXX: should this be thread safe? */
+   
+   if (src) {
+      src->refcount++;
+   }
+   
+   if (*dst) {
+      (*dst)->refcount--;
+      if ((*dst)->refcount == 0) {
+        buffer_release((*dst)->buf);
+        free(*dst);
+      }
+   }
+
+   *dst = src;
+}
+
+
+static int 
+buffer_handle_subdata(struct pipe_winsys *winsys, 
+                      struct pipe_buffer_handle *handle,
+                      unsigned long offset, 
+                      unsigned long size, 
+                      const void *data)
+{
+   void *map;
+   assert(handle);
+   assert(data);
+   map = buffer_handle_map(winsys, handle, PIPE_BUFFER_FLAG_WRITE);
+   if(map) {
+      memcpy((char *)map + offset, data, size);
+      buffer_handle_unmap(winsys, handle);
+      return 0;
+   }
+   return -1; 
+}
+
+
+static int  
+buffer_handle_get_subdata(struct pipe_winsys *winsys,
+                          struct pipe_buffer_handle *handle,
+                          unsigned long offset, 
+                          unsigned long size, 
+                          void *data)
+{
+   void *map;
+   assert(handle);
+   assert(data);
+   map = buffer_handle_map(winsys, handle, PIPE_BUFFER_FLAG_READ);
+   if(map) {
+      memcpy(data, (char *)map + offset, size);
+      buffer_handle_unmap(winsys, handle);
+      return 0;
+   }
+   return -1; 
+}
+
+
+void 
+buffer_handle_init_winsys(struct pipe_winsys *winsys)
+{
+   winsys->buffer_create = buffer_handle_create;
+   winsys->user_buffer_create = buffer_handle_create_user;
+   winsys->buffer_map = buffer_handle_map;
+   winsys->buffer_unmap = buffer_handle_unmap;
+   winsys->buffer_reference = buffer_handle_reference;
+   winsys->buffer_subdata = buffer_handle_subdata;
+   winsys->buffer_get_subdata = buffer_handle_get_subdata;
+}
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_handle.h b/src/mesa/pipe/pipebuffer/pb_buffer_handle.h
new file mode 100644 (file)
index 0000000..076eec2
--- /dev/null
@@ -0,0 +1,120 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Buffer handle interface.
+ *
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+#ifndef PB_BUFFER_HANDLE_H_
+#define PB_BUFFER_HANDLE_H_
+
+
+#include <assert.h>
+
+#include "pb_buffer.h"
+
+
+/**
+ * Buffer handle.
+ *
+ * The buffer handle and the buffer data storage are separate entities. This
+ * is modelled after ARB_vertex_buffer_object, which is the interface that
+ * Gallium requires. See p_winsys.h for more information.
+ */
+struct pipe_buffer_handle 
+{
+   /** Reference count */
+   unsigned refcount;
+
+   /** Allocation characteristics */
+   unsigned alignment;
+   unsigned flags;
+   unsigned hint;
+   
+   /** 
+    * The actual buffer.
+    * 
+    * It should never be NULL. Use null_buffer instead. 
+    */
+   struct pipe_buffer *buf;
+};
+
+
+/**
+ * Set buffer storage.
+ * 
+ * NOTE: this will not increase the buffer reference count.
+ */
+static inline void
+buffer_handle_data(struct pipe_buffer_handle *handle,
+                   struct pipe_buffer *buf)
+{
+   assert(handle);
+   assert(handle->buf);
+   buffer_release(handle->buf);
+   assert(buf);
+   handle->buf = buf;
+}
+
+
+static inline void
+buffer_handle_clear(struct pipe_buffer_handle *handle)
+{
+   buffer_handle_data(handle, &null_buffer);
+}
+
+
+static inline int
+buffer_handle_has_data(struct pipe_buffer_handle *handle) {
+   assert(handle);
+   assert(handle->buf);
+   return handle->buf != &null_buffer;
+}
+
+
+/**
+ * Fill in the pipe_winsys' buffer-related callbacks.
+ * 
+ * Specifically, the fullfilled functions are:
+ * - buffer_create
+ * - user_buffer_create
+ * - buffer_map
+ * - buffer_unmap
+ * - buffer_reference
+ * - buffer_subdata
+ * - buffer_get_subdata
+ * 
+ * NOTE: buffer_data is left untouched.
+ */
+void 
+buffer_handle_init_winsys(struct pipe_winsys *winsys);
+
+
+#endif /*PB_BUFFER_HANDLE_H_*/
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_malloc.c b/src/mesa/pipe/pipebuffer/pb_buffer_malloc.c
new file mode 100644 (file)
index 0000000..65ad51e
--- /dev/null
@@ -0,0 +1,132 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Implementation of malloc-based buffers to store data that can't be processed
+ * by the hardware. 
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pb_buffer.h"
+
+
+struct malloc_buffer 
+{
+   struct pipe_buffer base;
+   void *data;
+};
+
+
+extern const struct pipe_buffer_vtbl malloc_buffer_vtbl;
+
+static inline struct malloc_buffer *
+malloc_buffer(struct pipe_buffer *buf)
+{
+   assert(buf);
+   assert(buf->vtbl == &malloc_buffer_vtbl);
+   return (struct malloc_buffer *)buf;
+}
+
+
+static void
+malloc_buffer_reference(struct pipe_buffer *buf)
+{
+   /* no-op */
+}
+
+
+static void
+malloc_buffer_release(struct pipe_buffer *buf)
+{
+   free(malloc_buffer(buf)->data);
+   free(buf);
+}
+
+
+static void *
+malloc_buffer_map(struct pipe_buffer *buf, 
+                  unsigned flags)
+{
+   return malloc_buffer(buf)->data;
+}
+
+
+static void
+malloc_buffer_unmap(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+malloc_buffer_get_base_buffer(struct pipe_buffer *buf,
+                              struct pipe_buffer **base_buf,
+                              unsigned *offset)
+{
+   *base_buf = buf;
+   *offset = 0;
+}
+
+
+const struct pipe_buffer_vtbl 
+malloc_buffer_vtbl = {
+      malloc_buffer_reference,
+      malloc_buffer_release,
+      malloc_buffer_map,
+      malloc_buffer_unmap,
+      malloc_buffer_get_base_buffer
+};
+
+
+struct pipe_buffer *
+malloc_buffer_create(unsigned size) 
+{
+   struct malloc_buffer *buf;
+   
+   /* TODO: accept an alignment parameter */
+   /* TODO: do a single allocation */
+   
+   buf = (struct malloc_buffer *)malloc(sizeof(struct malloc_buffer));
+   if(!buf)
+      return NULL;
+   
+   buf->base.vtbl = &malloc_buffer_vtbl;
+   
+   buf->data = malloc(size);
+   if(!buf->data) {
+      free(buf);
+      return NULL;
+   }
+
+   return &buf->base;
+}
diff --git a/src/mesa/pipe/pipebuffer/pb_buffer_null.c b/src/mesa/pipe/pipebuffer/pb_buffer_null.c
new file mode 100644 (file)
index 0000000..a356c6b
--- /dev/null
@@ -0,0 +1,98 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Null buffer implementation.
+ * 
+ * We have a special null buffer object so that we can safely call buffer 
+ * operations without having to check whether the buffer pointer is null or not.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+#include "pipe/p_winsys.h"
+#include "pipe/p_defines.h"
+
+#include "pb_buffer.h"
+
+
+static void
+null_buffer_reference(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+null_buffer_release(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void *
+null_buffer_map(struct pipe_buffer *buf, 
+                unsigned flags)
+{
+   assert(0);
+   return NULL;
+}
+
+
+static void
+null_buffer_unmap(struct pipe_buffer *buf)
+{
+   assert(0);
+}
+
+
+static void
+null_buffer_get_base_buffer(struct pipe_buffer *buf,
+                            struct pipe_buffer **base_buf,
+                            unsigned *offset)
+{
+   *base_buf = buf;
+   *offset = 0;
+}
+
+
+const struct pipe_buffer_vtbl 
+pipe_buffer_vtbl = {
+      null_buffer_reference,
+      null_buffer_release,
+      null_buffer_map,
+      null_buffer_unmap,
+      null_buffer_get_base_buffer
+};
+
+
+struct pipe_buffer
+null_buffer = {
+      &pipe_buffer_vtbl
+};
diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr.h b/src/mesa/pipe/pipebuffer/pb_bufmgr.h
new file mode 100644 (file)
index 0000000..0e6c3a8
--- /dev/null
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Buffer management.
+ * 
+ * A buffer manager does only one basic thing: it creates buffers. Actually,
+ * "buffer factory" would probably a more accurate description.
+ * 
+ * You can chain buffer managers so that you can have a finer grained memory
+ * management and pooling.
+ * 
+ * For example, for a simple batch buffer manager you would chain:
+ * - the native buffer manager, which provides DMA memory from the graphics
+ * memory space;
+ * - the pool buffer manager, which keep around a pool of equally sized buffers
+ * to avoid latency associated with the native buffer manager; 
+ * - the fenced buffer manager, which will delay buffer destruction until the 
+ * the moment the card finishing processing it. 
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+#ifndef PB_BUFMGR_H_
+#define PB_BUFMGR_H_
+
+
+#include <stddef.h>
+
+
+struct pipe_buffer;
+struct pipe_winsys;
+
+
+/** 
+ * Abstract base class for all buffer managers.
+ */
+struct buffer_manager
+{
+   /* XXX: we will likely need more allocation flags */
+   struct pipe_buffer *
+   (*create_buffer)( struct buffer_manager *mgr, 
+                    size_t size);
+
+   void
+   (*destroy)( struct buffer_manager *mgr );
+};
+
+
+/** 
+ * Static buffer pool manager.
+ * 
+ * Manages the allocation of equally sized buffers. It does so by allocating
+ * a single big buffer and divide it equally sized buffers. 
+ * 
+ * It is meant to manage the allocation of batch buffer pools.
+ */
+struct buffer_manager *
+pool_bufmgr_create(struct buffer_manager *provider, 
+                   size_t n, size_t size);
+
+
+/** 
+ * Wraper around the old memory manager.
+ * 
+ * It managers buffers of different sizes. It does so by allocating a buffer
+ * with the size of the heap, and then using the old mm memory manager to manage
+ * that heap. 
+ */
+struct buffer_manager *
+mm_bufmgr_create(struct buffer_manager *provider, 
+                 size_t size, size_t align2);
+
+
+/** 
+ * Fenced buffer manager.
+ *
+ * This manager is just meant for convenience. It wraps the buffers returned
+ * by another manager in fenced buffers, so that  
+ * 
+ * NOTE: the buffer manager that provides the buffers will be destroyed
+ * at the same time.
+ */
+struct buffer_manager *
+fenced_bufmgr_create(struct buffer_manager *provider,
+                     struct pipe_winsys *winsys);
+
+
+#endif /*PB_BUFMGR_H_*/
diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c b/src/mesa/pipe/pipebuffer/pb_bufmgr_fenced.c
new file mode 100644 (file)
index 0000000..defd8e4
--- /dev/null
@@ -0,0 +1,128 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * 
+ **************************************************************************/
+
+/**
+ * \file
+ * A buffer manager that wraps buffers in fenced buffers.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.dot.com>
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pb_buffer.h"
+#include "pb_buffer_fenced.h"
+#include "pb_bufmgr.h"
+
+
+struct fenced_buffer_manager
+{
+   struct buffer_manager base;
+
+   struct buffer_manager *provider;
+   
+   struct fenced_buffer_list *fenced_list;
+};
+
+
+static inline struct fenced_buffer_manager *
+fenced_buffer_manager(struct buffer_manager *mgr)
+{
+   assert(mgr);
+   return (struct fenced_buffer_manager *)mgr;
+}
+
+
+static struct pipe_buffer *
+fenced_bufmgr_create_buffer(struct buffer_manager *mgr, size_t size)
+{
+   struct fenced_buffer_manager *fenced_mgr = fenced_buffer_manager(mgr);
+   struct pipe_buffer *buf;
+   struct pipe_buffer *fenced_buf;
+
+   /* check for free buffers before allocating new ones */
+   fenced_buffer_list_check_free(fenced_mgr->fenced_list, 0);
+   
+   buf = fenced_mgr->provider->create_buffer(fenced_mgr->provider, size);
+   if(!buf) {
+      /* try harder to get a buffer */
+      fenced_buffer_list_check_free(fenced_mgr->fenced_list, 1);
+      
+      buf = fenced_mgr->provider->create_buffer(fenced_mgr->provider, size);
+      if(!buf) {
+         /* give up */
+         return NULL;
+      }
+   }
+   
+   fenced_buf = fenced_buffer_create(fenced_mgr->fenced_list, buf);
+   if(!fenced_buf) {
+      buffer_release(buf);
+   }
+   
+   return fenced_buf;
+}
+
+
+static void
+fenced_bufmgr_destroy(struct buffer_manager *mgr)
+{
+   struct fenced_buffer_manager *fenced_mgr = fenced_buffer_manager(mgr);
+
+   fenced_buffer_list_destroy(fenced_mgr->fenced_list);
+
+   fenced_mgr->provider->destroy(fenced_mgr->provider);
+   
+   free(fenced_mgr);
+}
+
+
+struct buffer_manager *
+fenced_bufmgr_create(struct buffer_manager *provider, 
+                     struct pipe_winsys *winsys) 
+{
+   struct fenced_buffer_manager *fenced_mgr;
+
+   fenced_mgr = (struct fenced_buffer_manager *)calloc(1, sizeof(*fenced_mgr));
+   if (!fenced_mgr)
+      return NULL;
+
+   fenced_mgr->base.destroy = fenced_bufmgr_destroy;
+   fenced_mgr->base.create_buffer = fenced_bufmgr_create_buffer;
+
+   fenced_mgr->provider = provider;
+   fenced_mgr->fenced_list = fenced_buffer_list_create(winsys);
+   if(!fenced_mgr->fenced_list) {
+      free(fenced_mgr);
+      return NULL;
+   }
+      
+   return &fenced_mgr->base;
+}
diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c b/src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c
new file mode 100644 (file)
index 0000000..8e6dcf1
--- /dev/null
@@ -0,0 +1,265 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * \file
+ * Buffer manager using the old texture memory manager.
+ * 
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main/imports.h"
+#include "glapi/glthread.h"
+#include "main/mm.h"
+#include "linked_list.h"
+
+#include "p_defines.h"
+#include "pb_buffer.h"
+#include "pb_bufmgr.h"
+
+
+/**
+ * Convenience macro (type safe).
+ */
+#define SUPER(__derived) (&(__derived)->base)
+
+
+struct mm_buffer_manager
+{
+   struct buffer_manager base;
+   
+   _glthread_Mutex mutex;
+   
+   size_t size;
+   struct mem_block *heap;
+   
+   size_t align2;
+   
+   struct pipe_buffer *buffer;
+   void *map;
+};
+
+
+static inline struct mm_buffer_manager *
+mm_buffer_manager(struct buffer_manager *mgr)
+{
+   assert(mgr);
+   return (struct mm_buffer_manager *)mgr;
+}
+
+
+struct mm_buffer
+{
+   struct pipe_buffer base;
+   
+   struct mm_buffer_manager *mgr;
+   
+   struct mem_block *block;
+};
+
+
+static inline struct mm_buffer *
+mm_buffer(struct pipe_buffer *buf)
+{
+   assert(buf);
+   return (struct mm_buffer *)buf;
+}
+
+
+static void
+mm_buffer_reference(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+mm_buffer_release(struct pipe_buffer *buf)
+{
+   struct mm_buffer *mm_buf = mm_buffer(buf);
+   struct mm_buffer_manager *mm = mm_buf->mgr;
+   
+   _glthread_LOCK_MUTEX(mm->mutex);
+   mmFreeMem(mm_buf->block);
+   free(buf);
+   _glthread_UNLOCK_MUTEX(mm->mutex);
+}
+
+
+static void *
+mm_buffer_map(struct pipe_buffer *buf,
+              unsigned flags)
+{
+   struct mm_buffer *mm_buf = mm_buffer(buf);
+   struct mm_buffer_manager *mm = mm_buf->mgr;
+
+   return (unsigned char *) mm->map + mm_buf->block->ofs;
+}
+
+
+static void
+mm_buffer_unmap(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+mm_buffer_get_base_buffer(struct pipe_buffer *buf,
+                          struct pipe_buffer **base_buf,
+                          unsigned *offset)
+{
+   struct mm_buffer *mm_buf = mm_buffer(buf);
+   struct mm_buffer_manager *mm = mm_buf->mgr;
+   buffer_get_base_buffer(mm->buffer, base_buf, offset);
+   *offset += mm_buf->block->ofs;
+}
+
+
+static const struct pipe_buffer_vtbl 
+mm_buffer_vtbl = {
+      mm_buffer_reference,
+      mm_buffer_release,
+      mm_buffer_map,
+      mm_buffer_unmap,
+      mm_buffer_get_base_buffer
+};
+
+
+static struct pipe_buffer *
+mm_bufmgr_create_buffer(struct buffer_manager *mgr, 
+                        size_t size)
+{
+   struct mm_buffer_manager *mm = mm_buffer_manager(mgr);
+   struct mm_buffer *mm_buf;
+
+   _glthread_LOCK_MUTEX(mm->mutex);
+
+   mm_buf = (struct mm_buffer *)malloc(sizeof(*mm_buf));
+   if (!mm_buf) {
+      _glthread_UNLOCK_MUTEX(mm->mutex);
+      return NULL;
+   }
+
+   mm_buf->base.vtbl = &mm_buffer_vtbl;
+   
+   mm_buf->mgr = mm;
+   
+   mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
+   if(!mm_buf->block) {
+      fprintf(stderr, "warning: heap full\n");
+#if 0
+      mmDumpMemInfo(mm->heap);
+#endif
+      
+      mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
+      if(!mm_buf->block) {
+        assert(0);
+         free(mm_buf);
+         _glthread_UNLOCK_MUTEX(mm->mutex);
+         return NULL;
+      }
+   }
+   
+   /* Some sanity checks */
+   assert(0 <= mm_buf->block->ofs && mm_buf->block->ofs < mm->size);
+   assert(size <= mm_buf->block->size && mm_buf->block->ofs + mm_buf->block->size <= mm->size);
+   
+   _glthread_UNLOCK_MUTEX(mm->mutex);
+   return SUPER(mm_buf);
+}
+
+
+static void
+mm_bufmgr_destroy(struct buffer_manager *mgr)
+{
+   struct mm_buffer_manager *mm = mm_buffer_manager(mgr);
+   
+   _glthread_LOCK_MUTEX(mm->mutex);
+
+   mmDestroy(mm->heap);
+   
+   buffer_unmap(mm->buffer);
+   buffer_release(mm->buffer);
+   
+   _glthread_UNLOCK_MUTEX(mm->mutex);
+   
+   free(mgr);
+}
+
+
+struct buffer_manager *
+mm_bufmgr_create(struct buffer_manager *provider, 
+                 size_t size, size_t align2) 
+{
+   struct mm_buffer_manager *mm;
+
+   mm = (struct mm_buffer_manager *)calloc(1, sizeof(*mm));
+   if (!mm)
+      return NULL;
+
+   assert(provider);
+   assert(provider->create_buffer);
+   mm->base.create_buffer = mm_bufmgr_create_buffer;
+   mm->base.destroy = mm_bufmgr_destroy;
+
+   mm->size = size;
+   mm->align2 = align2; /* 64-byte alignment */
+
+   _glthread_INIT_MUTEX(mm->mutex);
+
+   mm->buffer = provider->create_buffer(provider, size); 
+   if (!mm->buffer)
+      goto failure;
+
+   mm->map = buffer_map(mm->buffer, 
+                        PIPE_BUFFER_FLAG_READ | PIPE_BUFFER_FLAG_WRITE );
+   if(!mm->map)
+      goto failure;
+
+   mm->heap = mmInit(0, size); 
+   if (!mm->heap)
+      goto failure;
+
+   return SUPER(mm);
+   
+failure:
+if(mm->heap)
+   mmDestroy(mm->heap);
+   if(mm->map)
+      buffer_unmap(mm->buffer);
+   if(mm->buffer)
+      buffer_release(mm->buffer);
+   if(mm)
+      free(mm);
+   return NULL;
+}
diff --git a/src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c b/src/mesa/pipe/pipebuffer/pb_bufmgr_pool.c
new file mode 100644 (file)
index 0000000..ee6fa62
--- /dev/null
@@ -0,0 +1,279 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * 
+ **************************************************************************/
+
+/**
+ * \file
+ * Batch buffer pool management.
+ * 
+ * \author José Fonseca <jrfonseca-at-tungstengraphics-dot-com>
+ * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "main/imports.h"
+#include "glapi/glthread.h"
+#include "linked_list.h"
+
+#include "p_defines.h"
+
+#include "pb_buffer.h"
+#include "pb_bufmgr.h"
+
+
+/**
+ * Convenience macro (type safe).
+ */
+#define SUPER(__derived) (&(__derived)->base)
+
+
+struct pool_buffer_manager
+{
+   struct buffer_manager base;
+   
+   _glthread_Mutex mutex;
+   
+   size_t bufSize;
+   
+   size_t numFree;
+   size_t numTot;
+   
+   struct list_head free;
+   
+   struct pipe_buffer *buffer;
+   void *map;
+   
+   struct pool_buffer *bufs;
+};
+
+
+static inline struct pool_buffer_manager *
+pool_buffer_manager(struct buffer_manager *mgr)
+{
+   assert(mgr);
+   return (struct pool_buffer_manager *)mgr;
+}
+
+
+struct pool_buffer
+{
+   struct pipe_buffer base;
+   
+   struct pool_buffer_manager *mgr;
+   
+   struct list_head head;
+   
+   size_t start;
+};
+
+
+static inline struct pool_buffer *
+pool_buffer(struct pipe_buffer *buf)
+{
+   assert(buf);
+   return (struct pool_buffer *)buf;
+}
+
+
+static void
+pool_buffer_reference(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+pool_buffer_release(struct pipe_buffer *buf)
+{
+   struct pool_buffer *pool_buf = pool_buffer(buf);
+   struct pool_buffer_manager *pool = pool_buf->mgr;
+   
+   _glthread_LOCK_MUTEX(pool->mutex);
+   LIST_ADD(&pool_buf->head, &pool->free);
+   pool->numFree++;
+   _glthread_UNLOCK_MUTEX(pool->mutex);
+}
+
+
+static void *
+pool_buffer_map(struct pipe_buffer *buf, unsigned flags)
+{
+   struct pool_buffer *pool_buf = pool_buffer(buf);
+   struct pool_buffer_manager *pool = pool_buf->mgr;
+   void *map;
+
+   _glthread_LOCK_MUTEX(pool->mutex);
+   map = (unsigned char *) pool->map + pool_buf->start;
+   _glthread_UNLOCK_MUTEX(pool->mutex);
+   return map;
+}
+
+
+static void
+pool_buffer_unmap(struct pipe_buffer *buf)
+{
+   /* No-op */
+}
+
+
+static void
+pool_buffer_get_base_buffer(struct pipe_buffer *buf,
+                            struct pipe_buffer **base_buf,
+                            unsigned *offset)
+{
+   struct pool_buffer *pool_buf = pool_buffer(buf);
+   struct pool_buffer_manager *pool = pool_buf->mgr;
+   buffer_get_base_buffer(pool->buffer, base_buf, offset);
+   *offset += pool_buf->start;
+}
+
+
+static const struct pipe_buffer_vtbl 
+pool_buffer_vtbl = {
+      pool_buffer_reference,
+      pool_buffer_release,
+      pool_buffer_map,
+      pool_buffer_unmap,
+      pool_buffer_get_base_buffer
+};
+
+
+static struct pipe_buffer *
+pool_bufmgr_create_buffer(struct buffer_manager *mgr, size_t size)
+{
+   struct pool_buffer_manager *pool = pool_buffer_manager(mgr);
+   struct pool_buffer *pool_buf;
+   struct list_head *item;
+
+   assert(size == pool->bufSize);
+   
+   _glthread_LOCK_MUTEX(pool->mutex);
+
+   if (pool->numFree == 0) {
+      _glthread_UNLOCK_MUTEX(pool->mutex);
+      fprintf(stderr, "warning: out of fixed size buffer objects\n");
+      return NULL;
+   }
+
+   item = pool->free.next;
+
+   if (item == &pool->free) {
+      _glthread_UNLOCK_MUTEX(pool->mutex);
+      fprintf(stderr, "error: fixed size buffer pool corruption\n");
+      return NULL;
+   }
+
+   LIST_DEL(item);
+   --pool->numFree;
+
+   _glthread_UNLOCK_MUTEX(pool->mutex);
+   pool_buf = LIST_ENTRY(struct pool_buffer, item, head);
+   return SUPER(pool_buf);
+}
+
+
+static void
+pool_bufmgr_destroy(struct buffer_manager *mgr)
+{
+   struct pool_buffer_manager *pool = pool_buffer_manager(mgr);
+   _glthread_LOCK_MUTEX(pool->mutex);
+
+   free(pool->bufs);
+   
+   buffer_unmap(pool->buffer);
+   buffer_release(pool->buffer);
+   
+   _glthread_UNLOCK_MUTEX(pool->mutex);
+   
+   free(mgr);
+}
+
+
+struct buffer_manager *
+pool_bufmgr_create(struct buffer_manager *provider, 
+                   size_t numBufs, 
+                   size_t bufSize) 
+{
+   struct pool_buffer_manager *pool;
+   struct pool_buffer *pool_buf;
+   int i;
+
+   pool = (struct pool_buffer_manager *)calloc(1, sizeof(*pool));
+   if (!pool)
+      return NULL;
+
+   pool->base.destroy = pool_bufmgr_destroy;
+   pool->base.create_buffer = pool_bufmgr_create_buffer;
+
+   LIST_INITHEAD(&pool->free);
+
+   pool->numTot = numBufs;
+   pool->numFree = numBufs;
+   pool->bufSize = bufSize;
+   
+   _glthread_INIT_MUTEX(pool->mutex);
+
+   pool->buffer = provider->create_buffer(provider, numBufs*bufSize); 
+   if (!pool->buffer)
+      goto failure;
+
+   pool->map = buffer_map(pool->buffer,
+                          PIPE_BUFFER_FLAG_READ |
+                          PIPE_BUFFER_FLAG_WRITE );
+   if(!pool->map)
+      goto failure;
+
+   pool->bufs = (struct pool_buffer *) malloc(numBufs * sizeof(*pool->bufs));
+   if (!pool->bufs)
+      goto failure;
+
+   pool_buf = pool->bufs;
+   for (i = 0; i < numBufs; ++i) {
+      pool_buf->base.vtbl = &pool_buffer_vtbl;
+      pool_buf->mgr = pool;
+      pool_buf->start = i * bufSize;
+      LIST_ADDTAIL(&pool_buf->head, &pool->free);
+      pool_buf++;
+   }
+
+   return SUPER(pool);
+   
+failure:
+   if(pool->bufs)
+      free(pool->bufs);
+   if(pool->map)
+      buffer_unmap(pool->buffer);
+   if(pool->buffer)
+      buffer_release(pool->buffer);
+   if(pool)
+      free(pool);
+   return NULL;
+}