gallium: Make mm buffer manager more portable.
authorJosé Fonseca <jrfonseca@tungstengraphics.com>
Fri, 25 Jan 2008 09:38:25 +0000 (18:38 +0900)
committerJosé Fonseca <jrfonseca@tungstengraphics.com>
Sat, 26 Jan 2008 02:11:08 +0000 (11:11 +0900)
src/mesa/pipe/pipebuffer/pb_bufmgr_mm.c

index f456b571d989b4541ac79b394ab0d4da0c075584..038406e953a48df08f129605c92f92a0e722f80f 100644 (file)
@@ -1,6 +1,7 @@
 /**************************************************************************
  *
  * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 1999 Wittawat Yamwong
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 
 
 #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 "p_thread.h"
+#include "p_util.h"
 #include "pb_buffer.h"
 #include "pb_bufmgr.h"
 
 #define SUPER(__derived) (&(__derived)->base)
 
 
+struct mem_block 
+{
+   struct mem_block *next, *prev;
+   struct mem_block *next_free, *prev_free;
+   struct mem_block *heap;
+   int ofs, size;
+   unsigned int free:1;
+   unsigned int reserved:1;
+};
+
+
+#ifdef DEBUG
+/**
+ * For debugging purposes.
+ */
+static void
+mmDumpMemInfo(const struct mem_block *heap)
+{
+   fprintf(stderr, "Memory heap %p:\n", (void *)heap);
+   if (heap == 0) {
+      fprintf(stderr, "  heap == 0\n");
+   } else {
+      const struct mem_block *p;
+
+      for(p = heap->next; p != heap; p = p->next) {
+        fprintf(stderr, "  Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
+                p->free ? 'F':'.',
+                p->reserved ? 'R':'.');
+      }
+
+      fprintf(stderr, "\nFree list:\n");
+
+      for(p = heap->next_free; p != heap; p = p->next_free) {
+        fprintf(stderr, " FREE Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
+                p->free ? 'F':'.',
+                p->reserved ? 'R':'.');
+      }
+
+   }
+   fprintf(stderr, "End of memory blocks\n");
+}
+#endif
+
+
+/** 
+ * input: total size in bytes
+ * return: a heap pointer if OK, NULL if error
+ */
+static struct mem_block *
+mmInit(int ofs, int size)
+{
+   struct mem_block *heap, *block;
+  
+   if (size <= 0) 
+      return NULL;
+
+   heap = CALLOC_STRUCT(mem_block);
+   if (!heap) 
+      return NULL;
+   
+   block = CALLOC_STRUCT(mem_block);
+   if (!block) {
+      FREE(heap);
+      return NULL;
+   }
+
+   heap->next = block;
+   heap->prev = block;
+   heap->next_free = block;
+   heap->prev_free = block;
+
+   block->heap = heap;
+   block->next = heap;
+   block->prev = heap;
+   block->next_free = heap;
+   block->prev_free = heap;
+
+   block->ofs = ofs;
+   block->size = size;
+   block->free = 1;
+
+   return heap;
+}
+
+
+static struct mem_block *
+SliceBlock(struct mem_block *p, 
+           int startofs, int size, 
+           int reserved, int alignment)
+{
+   struct mem_block *newblock;
+
+   /* break left  [p, newblock, p->next], then p = newblock */
+   if (startofs > p->ofs) {
+      newblock = CALLOC_STRUCT(mem_block);
+      if (!newblock)
+        return NULL;
+      newblock->ofs = startofs;
+      newblock->size = p->size - (startofs - p->ofs);
+      newblock->free = 1;
+      newblock->heap = p->heap;
+
+      newblock->next = p->next;
+      newblock->prev = p;
+      p->next->prev = newblock;
+      p->next = newblock;
+
+      newblock->next_free = p->next_free;
+      newblock->prev_free = p;
+      p->next_free->prev_free = newblock;
+      p->next_free = newblock;
+
+      p->size -= newblock->size;
+      p = newblock;
+   }
+
+   /* break right, also [p, newblock, p->next] */
+   if (size < p->size) {
+      newblock = CALLOC_STRUCT(mem_block);
+      if (!newblock)
+        return NULL;
+      newblock->ofs = startofs + size;
+      newblock->size = p->size - size;
+      newblock->free = 1;
+      newblock->heap = p->heap;
+
+      newblock->next = p->next;
+      newblock->prev = p;
+      p->next->prev = newblock;
+      p->next = newblock;
+
+      newblock->next_free = p->next_free;
+      newblock->prev_free = p;
+      p->next_free->prev_free = newblock;
+      p->next_free = newblock;
+        
+      p->size = size;
+   }
+
+   /* p = middle block */
+   p->free = 0;
+
+   /* Remove p from the free list: 
+    */
+   p->next_free->prev_free = p->prev_free;
+   p->prev_free->next_free = p->next_free;
+
+   p->next_free = 0;
+   p->prev_free = 0;
+
+   p->reserved = reserved;
+   return p;
+}
+
+
+/**
+ * Allocate 'size' bytes with 2^align2 bytes alignment,
+ * restrict the search to free memory after 'startSearch'
+ * depth and back buffers should be in different 4mb banks
+ * to get better page hits if possible
+ * input:      size = size of block
+ *             align2 = 2^align2 bytes alignment
+ *             startSearch = linear offset from start of heap to begin search
+ * return: pointer to the allocated block, 0 if error
+ */
+static struct mem_block *
+mmAllocMem(struct mem_block *heap, int size, int align2, int startSearch)
+{
+   struct mem_block *p;
+   const int mask = (1 << align2)-1;
+   int startofs = 0;
+   int endofs;
+
+   if (!heap || align2 < 0 || size <= 0)
+      return NULL;
+
+   for (p = heap->next_free; p != heap; p = p->next_free) {
+      assert(p->free);
+
+      startofs = (p->ofs + mask) & ~mask;
+      if ( startofs < startSearch ) {
+        startofs = startSearch;
+      }
+      endofs = startofs+size;
+      if (endofs <= (p->ofs+p->size))
+        break;
+   }
+
+   if (p == heap) 
+      return NULL;
+
+   assert(p->free);
+   p = SliceBlock(p,startofs,size,0,mask+1);
+
+   return p;
+}
+
+
+#if 0
+/**
+ * Free block starts at offset
+ * input: pointer to a heap, start offset
+ * return: pointer to a block
+ */
+static struct mem_block *
+mmFindBlock(struct mem_block *heap, int start)
+{
+   struct mem_block *p;
+
+   for (p = heap->next; p != heap; p = p->next) {
+      if (p->ofs == start) 
+        return p;
+   }
+
+   return NULL;
+}
+#endif
+
+
+static INLINE int
+Join2Blocks(struct mem_block *p)
+{
+   /* XXX there should be some assertions here */
+
+   /* NOTE: heap->free == 0 */
+
+   if (p->free && p->next->free) {
+      struct mem_block *q = p->next;
+
+      assert(p->ofs + p->size == q->ofs);
+      p->size += q->size;
+
+      p->next = q->next;
+      q->next->prev = p;
+
+      q->next_free->prev_free = q->prev_free; 
+      q->prev_free->next_free = q->next_free;
+     
+      FREE(q);
+      return 1;
+   }
+   return 0;
+}
+
+
+/**
+ * Free block starts at offset
+ * input: pointer to a block
+ * return: 0 if OK, -1 if error
+ */
+static int
+mmFreeMem(struct mem_block *b)
+{
+   if (!b)
+      return 0;
+
+   if (b->free) {
+      fprintf(stderr, "block already free\n");
+      return -1;
+   }
+   if (b->reserved) {
+      fprintf(stderr, "block is reserved\n");
+      return -1;
+   }
+
+   b->free = 1;
+   b->next_free = b->heap->next_free;
+   b->prev_free = b->heap;
+   b->next_free->prev_free = b;
+   b->prev_free->next_free = b;
+
+   Join2Blocks(b);
+   if (b->prev != b->heap)
+      Join2Blocks(b->prev);
+
+   return 0;
+}
+
+
+/**
+ * destroy MM
+ */
+static void
+mmDestroy(struct mem_block *heap)
+{
+   struct mem_block *p;
+
+   if (!heap)
+      return;
+
+   for (p = heap->next; p != heap; ) {
+      struct mem_block *next = p->next;
+      FREE(p);
+      p = next;
+   }
+
+   FREE(heap);
+}
+
+
 struct mm_pb_manager
 {
    struct pb_manager base;
@@ -103,7 +401,7 @@ mm_buffer_destroy(struct pb_buffer *buf)
    
    _glthread_LOCK_MUTEX(mm->mutex);
    mmFreeMem(mm_buf->block);
-   free(buf);
+   FREE(buf);
    _glthread_UNLOCK_MUTEX(mm->mutex);
 }
 
@@ -156,7 +454,7 @@ mm_bufmgr_create_buffer(struct pb_manager *mgr,
 
    _glthread_LOCK_MUTEX(mm->mutex);
 
-   mm_buf = (struct mm_buffer *)malloc(sizeof(*mm_buf));
+   mm_buf = CALLOC_STRUCT(mm_buffer);
    if (!mm_buf) {
       _glthread_UNLOCK_MUTEX(mm->mutex);
       return NULL;
@@ -176,7 +474,7 @@ mm_bufmgr_create_buffer(struct pb_manager *mgr,
       mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
       if(!mm_buf->block) {
         assert(0);
-         free(mm_buf);
+         FREE(mm_buf);
          _glthread_UNLOCK_MUTEX(mm->mutex);
          return NULL;
       }
@@ -205,7 +503,7 @@ mm_bufmgr_destroy(struct pb_manager *mgr)
    
    _glthread_UNLOCK_MUTEX(mm->mutex);
    
-   free(mgr);
+   FREE(mgr);
 }
 
 
@@ -218,7 +516,7 @@ mm_bufmgr_create_from_buffer(struct pb_buffer *buffer,
    if(!buffer)
       return NULL;
    
-   mm = (struct mm_pb_manager *)calloc(1, sizeof(*mm));
+   mm = CALLOC_STRUCT(mm_pb_manager);
    if (!mm)
       return NULL;
 
@@ -250,7 +548,7 @@ if(mm->heap)
    if(mm->map)
       pb_unmap(mm->buffer);
    if(mm)
-      free(mm);
+      FREE(mm);
    return NULL;
 }