Use GrMemoryPool to manage GrCustomStage allocations.
Improve memory reclamation of GrMemoryPool for new/delete/new/delete pattern.

http://codereview.appspot.com/6438046/



git-svn-id: http://skia.googlecode.com/svn/trunk@4744 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrCustomStage.h b/include/gpu/GrCustomStage.h
index 9f5efd3..9060766 100644
--- a/include/gpu/GrCustomStage.h
+++ b/include/gpu/GrCustomStage.h
@@ -81,6 +81,9 @@
     virtual unsigned int numTextures() const;
     virtual GrTexture* texture(unsigned int index) const;
 
+    void* operator new(size_t size);
+    void operator delete(void* target);
+
 private:
     typedef GrRefCnt INHERITED;
 };
diff --git a/src/gpu/GrCustomStage.cpp b/src/gpu/GrCustomStage.cpp
index 66b78a6..43de5ae 100644
--- a/src/gpu/GrCustomStage.cpp
+++ b/src/gpu/GrCustomStage.cpp
@@ -7,9 +7,27 @@
 
 #include "GrContext.h"
 #include "GrCustomStage.h"
+#include "GrMemoryPool.h"
+#include "SkTLS.h"
 
 SK_DEFINE_INST_COUNT(GrCustomStage)
 
+class GrCustomStage_Globals {
+public:
+    static GrMemoryPool* GetTLS() {
+        return (GrMemoryPool*)SkTLS::Get(CreateTLS, DeleteTLS);
+    }
+
+private:
+    static void* CreateTLS() {
+        return SkNEW_ARGS(GrMemoryPool, (4096, 4096));
+    }
+
+    static void DeleteTLS(void* pool) {
+        SkDELETE(reinterpret_cast<GrMemoryPool*>(pool));
+    }
+};
+
 int32_t GrProgramStageFactory::fCurrStageClassID =
                                     GrProgramStageFactory::kIllegalStageClassID;
 
@@ -45,3 +63,11 @@
     return NULL;
 }
 
+void * GrCustomStage::operator new(size_t size) {
+    return GrCustomStage_Globals::GetTLS()->allocate(size);
+}
+
+void GrCustomStage::operator delete(void* target) {
+    GrCustomStage_Globals::GetTLS()->release(target);
+}
+
diff --git a/src/gpu/GrMemoryPool.cpp b/src/gpu/GrMemoryPool.cpp
index 597f88c..01f303f 100644
--- a/src/gpu/GrMemoryPool.cpp
+++ b/src/gpu/GrMemoryPool.cpp
@@ -57,6 +57,7 @@
     // so that we can decrement the live count on delete in constant time.
     *reinterpret_cast<BlockHeader**>(ptr) = fTail;
     ptr += kPerAllocPad;
+    fTail->fPrevPtr = fTail->fCurrPtr;
     fTail->fCurrPtr += size;
     fTail->fFreeSize -= size;
     fTail->fLiveCount += 1;
@@ -91,6 +92,11 @@
         }
     } else {
         --block->fLiveCount;
+        // Trivial reclaim: if we're releasing the most recent allocation, reuse it
+        if (block->fPrevPtr == ptr) {
+            block->fFreeSize += (block->fCurrPtr - block->fPrevPtr);
+            block->fCurrPtr = block->fPrevPtr;
+        }
     }
     GR_DEBUGCODE(--fAllocationCnt);
     VALIDATE;
@@ -104,6 +110,7 @@
     block->fLiveCount = 0;
     block->fFreeSize = size;
     block->fCurrPtr = reinterpret_cast<intptr_t>(block) + kHeaderSize;
+    block->fPrevPtr = NULL;
     return block;
 }
 
diff --git a/src/gpu/GrMemoryPool.h b/src/gpu/GrMemoryPool.h
index 08c9ee2..d327df4 100644
--- a/src/gpu/GrMemoryPool.h
+++ b/src/gpu/GrMemoryPool.h
@@ -53,12 +53,13 @@
     void validate();
 
     struct BlockHeader {
-        BlockHeader* fNext;      // doubly-linked list of blocks.
+        BlockHeader* fNext;      ///< doubly-linked list of blocks.
         BlockHeader* fPrev;
-        int          fLiveCount; // number of outstanding allocations in the
-                                 // block.
-        intptr_t     fCurrPtr;   // ptr to the start of blocks free space.
-        size_t       fFreeSize;  // amount of free space left in the block.
+        int          fLiveCount; ///< number of outstanding allocations in the
+                                 ///< block.
+        intptr_t     fCurrPtr;   ///< ptr to the start of blocks free space.
+        intptr_t     fPrevPtr;   ///< ptr to the last allocation made
+        size_t       fFreeSize;  ///< amount of free space left in the block.
     };
 
     enum {