Add GrResource base class for ibs, texs, vbs, etc.
Add lostContext() to GrContext.

Review URL: http://codereview.appspot.com/4328044/



git-svn-id: http://skia.googlecode.com/svn/trunk@1026 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrAtlas.h b/gpu/include/GrAtlas.h
index a933842..406b45c 100644
--- a/gpu/include/GrAtlas.h
+++ b/gpu/include/GrAtlas.h
@@ -80,8 +80,6 @@
     // to be called by ~GrAtlas()
     void freePlot(int x, int y);
 
-    void abandonAll();
-
 private:
     GrGpu*      fGpu;
     GrTexture*  fTexture[kCount_GrMaskFormats];
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index 106ac8a..cccc14f 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -52,14 +52,27 @@
      */
     void resetContext();
 
-    ///////////////////////////////////////////////////////////////////////////
-    // Textures
+    /**
+     * Abandons all gpu resources, assumes 3D API state is unknown. Call this
+     * if you have lost the associated GPU context, and thus internal texture,
+     * buffer, etc. references/IDs are now invalid. Should be called even when
+     * GrContext is no longer going to be used for two reasons:
+     *  1) ~GrContext will not try to free the objects in the 3D API.
+     *  2) If you've created GrResources that outlive the GrContext they will
+     *     be marked as invalid (GrResource::isValid()) and won't attempt to
+     *     free their underlying resource in the 3D API.
+     * Content drawn since the last GrContext::flush() may be lost.
+     */
+    void contextLost();
 
     /**
-     *  Abandons all textures. Call this if you have lost the associated GPU
-     *  context, and thus internal texture references/IDs are now invalid.
+     * Frees gpu created by the context. Can be called to reduce GPU memory
+     * pressure.
      */
-    void abandonAllTextures();
+    void freeGpuResources();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Textures
 
     /**
      *  Search for an entry with the same Key. If found, "lock" it and return it.
@@ -409,7 +422,7 @@
      * @param flagsBitfield     flags that control the flushing behavior. See
      *                          FlushBits.
      */
-    void flush(int flagsBitfield);
+    void flush(int flagsBitfield = 0);
     /**
      *  Return true on success, i.e. if we could copy the specified range of
      *  pixels from the current render-target into the buffer, converting into
@@ -489,6 +502,8 @@
 
     GrContext(GrGpu* gpu);
 
+    void setupDrawBuffer();
+
     void flushDrawBuffer();
 
     static void SetPaint(const GrPaint& paint, GrDrawTarget* target);
diff --git a/gpu/include/GrGLIndexBuffer.h b/gpu/include/GrGLIndexBuffer.h
index 0ecbe6d..92aadcf 100644
--- a/gpu/include/GrGLIndexBuffer.h
+++ b/gpu/include/GrGLIndexBuffer.h
@@ -24,33 +24,38 @@
 class GrGpuGL;
 
 class GrGLIndexBuffer : public GrIndexBuffer {
-protected:
-    GrGLIndexBuffer(GrGLuint id,
-                    GrGpuGL* gl,
-                    size_t sizeInBytes,
-                    bool dynamic);
+
 public:
-    virtual ~GrGLIndexBuffer();
+
+    virtual ~GrGLIndexBuffer() { this->release(); }
 
     GrGLuint bufferID() const;
 
     // overrides of GrIndexBuffer
-    virtual void abandon();
     virtual void* lock();
     virtual void* lockPtr() const;
     virtual void unlock();
     virtual bool isLocked() const;
     virtual bool updateData(const void* src, size_t srcSizeInBytes);
-    virtual bool updateSubData(const void* src,  
-                               size_t srcSizeInBytes, 
+    virtual bool updateSubData(const void* src,
+                               size_t srcSizeInBytes,
                                size_t offset);
+protected:
+    GrGLIndexBuffer(GrGpuGL* gpu,
+                    GrGLuint id,
+                    size_t sizeInBytes,
+                    bool dynamic);
+
+    // overrides of GrResource
+    virtual void onAbandon();
+    virtual void onRelease();
+
 private:
     void bind() const;
-    
-    GrGpuGL*     fGL;
+
     GrGLuint     fBufferID;
     void*        fLockPtr;
-    
+
     friend class GrGpuGL;
 
     typedef GrIndexBuffer INHERITED;
diff --git a/gpu/include/GrGLTexture.h b/gpu/include/GrGLTexture.h
index 1747b6d..0624f40 100644
--- a/gpu/include/GrGLTexture.h
+++ b/gpu/include/GrGLTexture.h
@@ -29,6 +29,7 @@
  * A ref counted tex id that deletes the texture in its destructor.
  */
 class GrGLTexID : public GrRefCnt {
+
 public:
     GrGLTexID(GrGLuint texID) : fTexID(texID) {}
 
@@ -46,20 +47,18 @@
 };
 
 class GrGLRenderTarget : public GrRenderTarget {
+
 public:
-    virtual ~GrGLRenderTarget();
-    
+    virtual ~GrGLRenderTarget() { this->release(); }
+
     bool resolveable() const { return fRTFBOID != fTexFBOID; }
     bool needsResolve() const { return fNeedsResolve; }
     void setDirty(bool dirty) { fNeedsResolve = resolveable() && dirty; }
-    
+
     GrGLuint renderFBOID() const { return fRTFBOID; }
     GrGLuint textureFBOID() const { return fTexFBOID; }
 
-    void   abandon();
-
 protected:
-
     struct GLRenderTargetIDs {
         GrGLuint      fRTFBOID;
         GrGLuint      fTexFBOID;
@@ -67,34 +66,38 @@
         GrGLuint      fMSColorRenderbufferID;
         bool        fOwnIDs;
     };
-    
-    GrGLRenderTarget(const GLRenderTargetIDs& ids,
+
+    GrGLRenderTarget(GrGpuGL* gpu,
+                     const GLRenderTargetIDs& ids,
                      GrGLTexID* texID,
                      GrGLuint stencilBits,
                      const GrGLIRect& fViewport,
-                     GrGLTexture* texture,
-                     GrGpuGL* gl);
-    
+                     GrGLTexture* texture);
+
     void setViewport(const GrGLIRect& rect) { fViewport = rect; }
     const GrGLIRect& getViewport() const { return fViewport; }
+
+    // overloads of GrResource
+    virtual void onAbandon();
+    virtual void onRelease();
+
 private:
-    GrGpuGL*    fGL;
     GrGLuint      fRTFBOID;
     GrGLuint      fTexFBOID;
     GrGLuint      fStencilRenderbufferID;
     GrGLuint      fMSColorRenderbufferID;
-   
+
     // Should this object delete IDs when it is destroyed or does someone
     // else own them.
     bool        fOwnIDs;
-    
+
     // If there separate Texture and RenderTarget FBO IDs then the rendertarget
     // must be resolved to the texture FBO before it is used as a texture.
     bool fNeedsResolve;
-    
-    // when we switch to this rendertarget we want to set the viewport to 
+
+    // when we switch to this rendertarget we want to set the viewport to
     // only render to to content area (as opposed to the whole allocation) and
-    // we want the rendering to be at top left (GL has origin in bottom left) 
+    // we want the rendering to be at top left (GL has origin in bottom left)
     GrGLIRect fViewport;
 
     // non-NULL if this RT was created by Gr with an associated GrGLTexture.
@@ -102,48 +105,27 @@
 
     friend class GrGpuGL;
     friend class GrGLTexture;
-    
+
     typedef GrRenderTarget INHERITED;
 };
 
 class GrGLTexture : public GrTexture {
+
 public:
     enum Orientation {
         kBottomUp_Orientation,
         kTopDown_Orientation,
     };
-    
+
     struct TexParams {
         GrGLenum fFilter;
         GrGLenum fWrapS;
         GrGLenum fWrapT;
     };
 
-protected:
-    struct GLTextureDesc {
-        uint32_t    fContentWidth;
-        uint32_t    fContentHeight;
-        uint32_t    fAllocWidth;
-        uint32_t    fAllocHeight;
-        PixelConfig fFormat;
-        GrGLuint    fTextureID;
-        GrGLenum    fUploadFormat;
-        GrGLenum    fUploadByteCount;
-        GrGLenum    fUploadType;
-        GrGLuint    fStencilBits;
-        Orientation fOrientation;
-    };
-    typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
-    GrGLTexture(const GLTextureDesc& textureDesc,
-                const GLRenderTargetIDs& rtIDs,
-                const TexParams& initialTexParams,
-                GrGpuGL* gl);
+    virtual ~GrGLTexture() { this->release(); }
 
-public:
-    virtual ~GrGLTexture();
-    
     // overloads of GrTexture
-    virtual void abandon();
     virtual GrRenderTarget* asRenderTarget();
     virtual void releaseRenderTarget();
     virtual void uploadTextureData(uint32_t x,
@@ -189,12 +171,37 @@
     // in the top-left corner of the image. OpenGL, however,
     // has the origin in the lower-left corner. For content that
     // is loaded by Ganesh we just push the content "upside down"
-    // (by GL's understanding of the world ) in glTex*Image and the 
-    // addressing just works out. However, content generated by GL 
-    // (FBO or externally imported texture) will be updside down 
+    // (by GL's understanding of the world ) in glTex*Image and the
+    // addressing just works out. However, content generated by GL
+    // (FBO or externally imported texture) will be updside down
     // and it is up to the GrGpuGL derivative to handle y-mirroing.
     Orientation orientation() const { return fOrientation; }
 
+protected:
+
+    struct GLTextureDesc {
+        uint32_t    fContentWidth;
+        uint32_t    fContentHeight;
+        uint32_t    fAllocWidth;
+        uint32_t    fAllocHeight;
+        PixelConfig fFormat;
+        GrGLuint    fTextureID;
+        GrGLenum    fUploadFormat;
+        GrGLenum    fUploadByteCount;
+        GrGLenum    fUploadType;
+        GrGLuint    fStencilBits;
+        Orientation fOrientation;
+    };
+    typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
+    GrGLTexture(GrGpuGL* gpu,
+                const GLTextureDesc& textureDesc,
+                const GLRenderTargetIDs& rtIDs,
+                const TexParams& initialTexParams);
+
+    // overloads of GrResource
+    virtual void onAbandon();
+    virtual void onRelease();
+
 private:
     TexParams           fTexParams;
     GrGLTexID*          fTexIDObj;
diff --git a/gpu/include/GrGLVertexBuffer.h b/gpu/include/GrGLVertexBuffer.h
index c4f62a0..183caba 100644
--- a/gpu/include/GrGLVertexBuffer.h
+++ b/gpu/include/GrGLVertexBuffer.h
@@ -24,31 +24,33 @@
 class GrGpuGL;
 
 class GrGLVertexBuffer : public GrVertexBuffer {
-protected:
-    GrGLVertexBuffer(GrGLuint id,
-                     GrGpuGL* gl,
-                     size_t sizeInBytes,
-                     bool dynamic);
 
 public:
-    virtual ~GrGLVertexBuffer();
-    
+    virtual ~GrGLVertexBuffer() { this->release(); }
     // overrides of GrVertexBuffer
-    virtual void abandon();
     virtual void* lock();
     virtual void* lockPtr() const;
     virtual void unlock();
     virtual bool isLocked() const;
     virtual bool updateData(const void* src, size_t srcSizeInBytes);
-    virtual bool updateSubData(const void* src,  
-                               size_t srcSizeInBytes, 
+    virtual bool updateSubData(const void* src,
+                               size_t srcSizeInBytes,
                                size_t offset);
     GrGLuint bufferID() const;
 
+protected:
+    GrGLVertexBuffer(GrGpuGL* gpu,
+                     GrGLuint id,
+                     size_t sizeInBytes,
+                     bool dynamic);
+
+    // overrides of GrResource
+    virtual void onAbandon();
+    virtual void onRelease();
+
 private:
     void bind() const;
-    
-    GrGpuGL*     fGL;
+
     GrGLuint     fBufferID;
     void*        fLockPtr;
 
diff --git a/gpu/include/GrGeometryBuffer.h b/gpu/include/GrGeometryBuffer.h
index 1447e73..98f58bd 100644
--- a/gpu/include/GrGeometryBuffer.h
+++ b/gpu/include/GrGeometryBuffer.h
@@ -1,12 +1,12 @@
 /*
  Copyright 2011 Google Inc.
- 
+
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
- 
+
  http://www.apache.org/licenses/LICENSE-2.0
- 
+
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,47 +17,40 @@
 #ifndef GrGeometryBuffer_DEFINED
 #define GrGeometryBuffer_DEFINED
 
-#include "GrRefCnt.h"
+#include "GrResource.h"
+
+class GrGpu;
 
 /**
  * Parent class for vertex and index buffers
  */
-class GrGeometryBuffer : public GrRefCnt {
+class GrGeometryBuffer : public GrResource {
 public:
-    virtual ~GrGeometryBuffer() {}
-    
     /**
      * Retrieves the size of the buffer
      *
      * @return the size of the buffer in bytes
      */
     size_t size() const { return fSizeInBytes; }
-    
+
     /**
      *Retrieves whether the buffer was created with the dynamic flag
      *
      * @return true if the buffer was created with the dynamic flag
      */
     bool dynamic() const { return fDynamic; }
-    
-    /**
-     * Indicates that GPU context in which this veretx buffer was created is 
-     * destroyed and that Ganesh should not attempt to free the buffer in the
-     * underlying API.
-     */
-    virtual void abandon() = 0;
-    
+
     /**
      * Locks the buffer to be written by the CPU.
-     * 
+     *
      * The previous content of the buffer is invalidated. It is an error
      * to draw from the buffer while it is locked. It is an error to call lock
      * on an already locked buffer.
-     * 
+     *
      * @return a pointer to the data or NULL if the lock fails.
      */
     virtual void* lock() = 0;
-    
+
     /**
      * Returns the same ptr that lock() returned at time of lock or NULL if the
      * is not locked.
@@ -65,52 +58,53 @@
      * @return ptr to locked buffer data or undefined if buffer is not locked.
      */
     virtual void* lockPtr() const = 0;
-    
-    /** 
-     * Unlocks the buffer. 
-     * 
+
+    /**
+     * Unlocks the buffer.
+     *
      * The pointer returned by the previous lock call will no longer be valid.
      */
     virtual void unlock() = 0;
-    
-    /** 
+
+    /**
      Queries whether the buffer has been locked.
-     
+
      @return true if the buffer is locked, false otherwise.
      */
     virtual bool isLocked() const = 0;
-    
+
     /**
-     * Updates the buffer data. 
-     *  
-     * The size of the buffer will be preserved. The src data will be 
+     * Updates the buffer data.
+     *
+     * The size of the buffer will be preserved. The src data will be
      * placed at the begining of the buffer and any remaining contents will
      * be undefined.
-     * 
+     *
      * @return returns true if the update succeeds, false otherwise.
      */
     virtual bool updateData(const void* src, size_t srcSizeInBytes) = 0;
-    
+
     /**
-     * Updates a portion of the buffer data. 
-     * 
+     * Updates a portion of the buffer data.
+     *
      * The contents of the buffer outside the update region are preserved.
-     * 
+     *
      * @return returns true if the update succeeds, false otherwise.
      */
-    virtual bool updateSubData(const void* src, 
-                               size_t srcSizeInBytes, 
+    virtual bool updateSubData(const void* src,
+                               size_t srcSizeInBytes,
                                size_t offset) = 0;
 protected:
-    GrGeometryBuffer(size_t sizeInBytes, bool dynamic) : 
-        fSizeInBytes(sizeInBytes),
-        fDynamic(dynamic) {}
+    GrGeometryBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
+        : INHERITED(gpu)
+        , fSizeInBytes(sizeInBytes)
+        , fDynamic(dynamic) {}
 
 private:
     size_t   fSizeInBytes;
     bool     fDynamic;
 
-    typedef GrRefCnt INHERITED;
+    typedef GrResource INHERITED;
 };
 
 #endif
diff --git a/gpu/include/GrGpu.h b/gpu/include/GrGpu.h
index 7e12456..c4f5e4b 100644
--- a/gpu/include/GrGpu.h
+++ b/gpu/include/GrGpu.h
@@ -25,6 +25,7 @@
 
 class GrVertexBufferAllocPool;
 class GrIndexBufferAllocPool;
+class GrResource;
 
 class GrGpu : public GrDrawTarget {
 
@@ -158,7 +159,7 @@
      * will be embedded in a power of two texture. The extra width and height
      * is filled as though srcData were rendered clamped into the texture.
      *
-     * If kRenderTarget_TextureFlag is specified the GrRenderTarget is 
+     * If kRenderTarget_TextureFlag is specified the GrRenderTarget is
      * accessible via GrTexture::asRenderTarget(). The texture will hold a ref
      * on the render target until its releaseRenderTarget() is called or it is
      * destroyed.
@@ -353,11 +354,34 @@
     bool readPixels(int left, int top, int width, int height,
                     GrTexture::PixelConfig, void* buffer);
 
-
     const Stats& getStats() const;
     void resetStats();
     void printStats() const;
 
+    /**
+     * Called to tell Gpu object that all GrResources have been lost and should
+     * be abandoned.
+     */
+    void abandonResources();
+
+    /**
+     * Called to tell Gpu object to release all GrResources.
+     */
+    void releaseResources();
+
+    /**
+     * Add resource to list of resources. Should only be called by GrResource.
+     * @param resource  the resource to add.
+     */
+    void insertResource(GrResource* resource);
+
+    /**
+     * Remove resource from list of resources. Should only be called by
+     * GrResource.
+     * @param resource  the resource to remove.
+     */
+    void removeResource(GrResource* resource);
+
 protected:
     enum PrivateStateBits {
         kFirstBit = (kLastPublicStateBit << 1),
@@ -535,6 +559,8 @@
     bool                        fVertexPoolInUse;
     bool                        fIndexPoolInUse;
 
+    GrResource*                 fResourceHead;
+
     // used to save and restore state when the GrGpu needs
     // to make its geometry pools available internally
     class AutoInternalDrawGeomRestore {
diff --git a/gpu/include/GrIndexBuffer.h b/gpu/include/GrIndexBuffer.h
index 09d1977..366640e 100644
--- a/gpu/include/GrIndexBuffer.h
+++ b/gpu/include/GrIndexBuffer.h
@@ -29,8 +29,8 @@
          */
         int maxQuads() const { return size() / (sizeof(uint16_t) * 6); }
 protected:
-    GrIndexBuffer(size_t sizeInBytes, bool dynamic) :
-        INHERITED(sizeInBytes, dynamic) {}
+    GrIndexBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
+        : INHERITED(gpu, sizeInBytes, dynamic) {}
 private:
     typedef GrGeometryBuffer INHERITED;
 };
diff --git a/gpu/include/GrRefCnt.h b/gpu/include/GrRefCnt.h
index c462b2c..9c9fed1 100644
--- a/gpu/include/GrRefCnt.h
+++ b/gpu/include/GrRefCnt.h
@@ -104,6 +104,14 @@
     dst = src;
 }
 
+template<typename T>
+static inline void GrSafeSetNull(T*& obj) {
+    if (NULL != obj) {
+        obj->unref();
+        obj = NULL;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class GrAutoRef : GrNoncopyable {
diff --git a/gpu/include/GrResource.h b/gpu/include/GrResource.h
new file mode 100644
index 0000000..8cc4d57
--- /dev/null
+++ b/gpu/include/GrResource.h
@@ -0,0 +1,77 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#ifndef GrResource_DEFINED
+#define GrResource_DEFINED
+
+#include "GrRefCnt.h"
+
+class GrGpu;
+
+class GrResource : public GrRefCnt {
+public:
+    explicit GrResource(GrGpu* gpu);
+
+    virtual ~GrResource() {
+        // subclass should have released this.
+        GrAssert(!isValid());
+    }
+
+    /**
+     * Frees the resource in the underlying 3D API. It must be safe to call this
+     * when the resource has been previously abandoned.
+     */
+    void release();
+
+    /**
+     * Removes references to objects in the underlying 3D API without freeing
+     * them. Used when the API context has been torn down before the GrContext.
+     */
+    void abandon();
+
+    /**
+     * Tests whether a resource has been abandoned or released. All resources
+     * will be in this state after their creating GrContext is destroyed or has
+     * contextLost called. It's up to the client to test isValid() before
+     * attempting to use a resource if it holds refs on resources across
+     * ~GrContext, freeResources with the force flag, or contextLost.
+     *
+     * @return true if the resource has been released or abandoned,
+     *         false otherwise.
+     */
+    bool isValid() const { return NULL != fGpu; }
+
+protected:
+
+    virtual void onRelease() = 0;
+    virtual void onAbandon() = 0;
+
+    GrGpu* getGpu() const { return fGpu; }
+
+private:
+    GrResource(); // unimpl
+
+    GrGpu* fGpu; // not reffed. This can outlive the GrGpu.
+
+    friend class GrGpu; // GrGpu manages list of resources.
+
+    GrResource* fNext;      // dl-list of resources per-GrGpu
+    GrResource* fPrevious;
+
+    typedef GrRefCnt INHERITED;
+};
+
+#endif
diff --git a/gpu/include/GrTextStrike.h b/gpu/include/GrTextStrike.h
index 610222c..2bdcc90 100644
--- a/gpu/include/GrTextStrike.h
+++ b/gpu/include/GrTextStrike.h
@@ -85,7 +85,6 @@
     inline GrTextStrike* getStrike(GrFontScaler*);
 
     void freeAll();
-    void abandonAll();
 
     void purgeExceptFor(GrTextStrike*);
 
diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h
index 0a65ff7..d1853e3 100644
--- a/gpu/include/GrTexture.h
+++ b/gpu/include/GrTexture.h
@@ -20,6 +20,7 @@
 
 #include "GrRefCnt.h"
 #include "GrClip.h"
+#include "GrResource.h"
 
 class GrTexture;
 
@@ -30,7 +31,7 @@
  * Additionally, GrContext provides methods for creating GrRenderTargets
  * that wrap externally created render targets.
  */
-class GrRenderTarget : public GrRefCnt {
+class GrRenderTarget : public GrResource {
 public:
     /**
      * @return the width of the rendertarget
@@ -52,14 +53,17 @@
     GrTexture* asTexture() {return fTexture;}
 
 protected:
-    GrRenderTarget(GrTexture* texture,
+    GrRenderTarget(GrGpu* gpu,
+                   GrTexture* texture,
                    int width,
                    int height,
                    int stencilBits)
-        : fTexture(texture),
-          fWidth(width),
-          fHeight(height),
-          fStencilBits(stencilBits) {}
+        : INHERITED(gpu)
+        , fTexture(texture)
+        , fWidth(width)
+        , fHeight(height)
+        , fStencilBits(stencilBits)
+    {}
 
 
     GrTexture* fTexture;
@@ -73,10 +77,10 @@
     friend class GrGpu;
     GrClip     fLastStencilClip;
 
-    typedef GrRefCnt INHERITED;
+    typedef GrResource INHERITED;
 };
 
-class GrTexture : public GrRefCnt {
+class GrTexture : public GrResource {
 public:
     enum PixelConfig {
         kUnknown_PixelConfig,
@@ -92,16 +96,19 @@
     static bool PixelConfigIsAlphaOnly(PixelConfig);
 
 protected:
-    GrTexture(int width,
+    GrTexture(GrGpu* gpu,
+              int width,
               int height,
-              PixelConfig config) :
-                fWidth(width),
-                fHeight(height),
-                fConfig(config) {
-                    // only make sense if alloc size is pow2
-                    fShiftFixedX = 31 - Gr_clz(fWidth);
-                    fShiftFixedY = 31 - Gr_clz(fHeight);
-                }
+              PixelConfig config)
+    : INHERITED(gpu)
+    , fWidth(width)
+    , fHeight(height)
+    , fConfig(config) {
+        // only make sense if alloc size is pow2
+        fShiftFixedX = 31 - Gr_clz(fWidth);
+        fShiftFixedY = 31 - Gr_clz(fHeight);
+    }
+
 public:
     virtual ~GrTexture();
 
@@ -111,6 +118,7 @@
      * @return the width in texels
      */
     int width() const { return fWidth; }
+
     /**
      * Retrieves the height of the texture.
      *
@@ -154,12 +162,6 @@
                                    uint32_t width,
                                    uint32_t height,
                                    const void* srcData) = 0;
-    /**
-     * Indicates that GPU context in which this texture was created is destroyed
-     * and that Ganesh should not attempt to free the texture with the
-     * underlying API.
-     */
-    virtual void abandon() = 0;
 
     /**
      * Retrieves the render target underlying this texture that can be passed to
@@ -172,7 +174,7 @@
 
     /**
      * Removes the reference on the associated GrRenderTarget held by this
-     * texture. Afterwards asRenderTarget() will return NULL. The 
+     * texture. Afterwards asRenderTarget() will return NULL. The
      * GrRenderTarget survives the release if another ref is held on it.
      */
     virtual void releaseRenderTarget() = 0;
@@ -200,7 +202,7 @@
     int      fShiftFixedY;
     PixelConfig fConfig;
 
-    typedef GrRefCnt INHERITED;
+    typedef GrResource INHERITED;
 };
 
 #endif
diff --git a/gpu/include/GrTextureCache.h b/gpu/include/GrTextureCache.h
index 68e1daa..466dafa 100644
--- a/gpu/include/GrTextureCache.h
+++ b/gpu/include/GrTextureCache.h
@@ -191,7 +191,7 @@
 class GrTextureCache {
 public:
     GrTextureCache(int maxCount, size_t maxBytes);
-    ~GrTextureCache();  // uses kFreeTexture_DeleteMode
+    ~GrTextureCache();
 
     /**
      *  Return the current texture cache limits.
@@ -250,11 +250,7 @@
      */
     void unlock(GrTextureEntry*);
 
-    enum DeleteMode {
-        kFreeTexture_DeleteMode,
-        kAbandonTexture_DeleteMode
-    };
-    void deleteAll(DeleteMode);
+    void removeAll();
 
 #if GR_DEBUG
     void validate() const;
diff --git a/gpu/include/GrVertexBuffer.h b/gpu/include/GrVertexBuffer.h
index 3792c15..34abe2c 100644
--- a/gpu/include/GrVertexBuffer.h
+++ b/gpu/include/GrVertexBuffer.h
@@ -22,8 +22,8 @@
 
 class GrVertexBuffer : public GrGeometryBuffer {
 protected:
-    GrVertexBuffer(size_t sizeInBytes, bool dynamic) : 
-        INHERITED(sizeInBytes, dynamic) {}
+    GrVertexBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
+        : INHERITED(gpu, sizeInBytes, dynamic) {}
 private:
     typedef GrGeometryBuffer INHERITED;
 };
diff --git a/gpu/src/GrAtlas.cpp b/gpu/src/GrAtlas.cpp
index ab99d9a..a37df9c 100644
--- a/gpu/src/GrAtlas.cpp
+++ b/gpu/src/GrAtlas.cpp
@@ -203,16 +203,4 @@
     fPlotMgr->freePlot(x, y);
 }
 
-void GrAtlasMgr::abandonAll() {
-#if 0
-    GrAtlas** curr = fList.begin();
-    GrAtlas** stop = fList.end();
-    for (; curr < stop; curr++) {
-        (*curr)->texture()->abandon();
-        delete *curr;
-    }
-    fList.reset();
-#endif
-}
-
 
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index f6009f5..d093d7c 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -57,6 +57,7 @@
 }
 
 GrContext::~GrContext() {
+    this->flush();
     fGpu->unref();
     delete fTextureCache;
     delete fFontCache;
@@ -66,9 +67,31 @@
     GrSafeUnref(fCustomPathRenderer);
 }
 
-void GrContext::abandonAllTextures() {
-    fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);
-    fFontCache->abandonAll();
+void GrContext::contextLost() {
+    delete fDrawBuffer;
+    fDrawBuffer = NULL;
+    delete fDrawBufferVBAllocPool;
+    fDrawBufferVBAllocPool = NULL;
+    delete fDrawBufferIBAllocPool;
+    fDrawBufferIBAllocPool = NULL;
+
+    fTextureCache->removeAll();
+    fFontCache->freeAll();
+    fGpu->markContextDirty();
+
+    fGpu->abandonResources();
+
+    this->setupDrawBuffer();
+}
+
+void GrContext::resetContext() {
+    fGpu->markContextDirty();
+}
+
+void GrContext::freeGpuResources() {
+    this->flush();
+    fTextureCache->removeAll();
+    fFontCache->freeAll();
 }
 
 GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
@@ -688,12 +711,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrContext::resetContext() {
-    fGpu->markContextDirty();
-}
-
 void GrContext::setRenderTarget(GrRenderTarget* target) {
-    flush(false);
+    this->flush(false);
     fGpu->setRenderTarget(target);
 }
 
@@ -745,7 +764,7 @@
 
     fGpu = gpu;
     fGpu->ref();
-    
+
     fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
     fGpu->setClipPathRenderer(fCustomPathRenderer);
 
@@ -755,22 +774,31 @@
 
     fLastDrawCategory = kUnbuffered_DrawCategory;
 
+    fDrawBuffer = NULL;
+    fDrawBufferVBAllocPool = NULL;
+    fDrawBufferIBAllocPool = NULL;
+
+    this->setupDrawBuffer();
+}
+
+void GrContext::setupDrawBuffer() {
+
+    GrAssert(NULL == fDrawBuffer);
+    GrAssert(NULL == fDrawBufferVBAllocPool);
+    GrAssert(NULL == fDrawBufferIBAllocPool);
+
 #if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
     fDrawBufferVBAllocPool =
-        new GrVertexBufferAllocPool(gpu, false,
+        new GrVertexBufferAllocPool(fGpu, false,
                                     DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
                                     DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
     fDrawBufferIBAllocPool =
-        new GrIndexBufferAllocPool(gpu, false,
+        new GrIndexBufferAllocPool(fGpu, false,
                                    DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
                                    DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
 
     fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
                                           fDrawBufferIBAllocPool);
-#else
-    fDrawBuffer = NULL;
-    fDrawBufferVBAllocPool = NULL;
-    fDrawBufferIBAllocPool = NULL;
 #endif
 
 #if BATCH_RECT_TO_RECT
@@ -818,7 +846,7 @@
 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
                                            GrPathIter* path,
                                            GrPathFill fill) {
-    if (NULL != fCustomPathRenderer && 
+    if (NULL != fCustomPathRenderer &&
         fCustomPathRenderer->canDrawPath(target, path, fill)) {
         return fCustomPathRenderer;
     } else {
diff --git a/gpu/src/GrGLIndexBuffer.cpp b/gpu/src/GrGLIndexBuffer.cpp
index 9d73419..4fb1e99 100644
--- a/gpu/src/GrGLIndexBuffer.cpp
+++ b/gpu/src/GrGLIndexBuffer.cpp
@@ -18,42 +18,46 @@
 #include "GrGLIndexBuffer.h"
 #include "GrGpuGL.h"
 
-GrGLIndexBuffer::GrGLIndexBuffer(GrGLuint id, GrGpuGL* gl, size_t sizeInBytes,
-                                   bool dynamic) :
-                                INHERITED(sizeInBytes, dynamic),
-                                fGL(gl),
-                                fBufferID(id),
-                                fLockPtr(NULL) {
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+GrGLIndexBuffer::GrGLIndexBuffer(GrGpuGL* gpu,
+                                 GrGLuint id,
+                                 size_t sizeInBytes,
+                                 bool dynamic)
+    : INHERITED(gpu, sizeInBytes, dynamic)
+    , fBufferID(id)
+    , fLockPtr(NULL) {
+
 }
 
-GrGLIndexBuffer::~GrGLIndexBuffer() {
+void GrGLIndexBuffer::onRelease() {
     // make sure we've not been abandoned
     if (fBufferID) {
-        fGL->notifyIndexBufferDelete(this);
+        GPUGL->notifyIndexBufferDelete(this);
         GR_GL(DeleteBuffers(1, &fBufferID));
+        fBufferID = 0;
     }
 }
 
+void GrGLIndexBuffer::onAbandon() {
+    fBufferID = 0;
+    fLockPtr = NULL;
+}
+
 void GrGLIndexBuffer::bind() const {
     GR_GL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, fBufferID));
-    fGL->notifyIndexBufferBind(this);
+    GPUGL->notifyIndexBufferBind(this);
 }
 
 GrGLuint GrGLIndexBuffer::bufferID() const {
     return fBufferID;
 }
 
-void GrGLIndexBuffer::abandon() {
-    fBufferID = 0;
-    fGL = NULL;
-    fLockPtr = NULL;
-}
-
 void* GrGLIndexBuffer::lock() {
     GrAssert(fBufferID);
     GrAssert(!isLocked());
-    if (fGL->supportsBufferLocking()) {
-        bind();
+    if (GPUGL->supportsBufferLocking()) {
+        this->bind();
         // Let driver know it can discard the old data
         GR_GL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, size(), NULL,
                          dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
@@ -71,18 +75,17 @@
 void GrGLIndexBuffer::unlock() {
     GrAssert(fBufferID);
     GrAssert(isLocked());
-    GrAssert(fGL->supportsBufferLocking());
+    GrAssert(GPUGL->supportsBufferLocking());
 
-    bind();
+    this->bind();
     GR_GL(UnmapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER));
     fLockPtr = NULL;
 }
 
 bool GrGLIndexBuffer::isLocked() const {
-    GrAssert(fBufferID);
 #if GR_DEBUG
-    if (fGL->supportsBufferLocking()) {
-        bind();
+    if (this->isValid() && GPUGL->supportsBufferLocking()) {
+        this->bind();
         GrGLint mapped;
         GR_GL(GetBufferParameteriv(GR_GL_ELEMENT_ARRAY_BUFFER,
                                    GR_GL_BUFFER_MAPPED, &mapped));
@@ -98,7 +101,7 @@
     if (srcSizeInBytes > size()) {
         return false;
     }
-    bind();
+    this->bind();
     GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
     if (size() == srcSizeInBytes) {
         GR_GL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, srcSizeInBytes, src, usage));
@@ -117,7 +120,7 @@
     if (srcSizeInBytes + offset > size()) {
         return false;
     }
-    bind();
+    this->bind();
     GR_GL(BufferSubData(GR_GL_ELEMENT_ARRAY_BUFFER, offset, srcSizeInBytes, src));
     return true;
 }
diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp
index ae36e4c..bd157d2 100644
--- a/gpu/src/GrGLTexture.cpp
+++ b/gpu/src/GrGLTexture.cpp
@@ -18,16 +18,15 @@
 #include "GrGLTexture.h"
 #include "GrGpuGL.h"
 
-GrGLRenderTarget::GrGLRenderTarget(const GLRenderTargetIDs& ids,
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
+                                   const GLRenderTargetIDs& ids,
                                    GrGLTexID* texID,
                                    GrGLuint stencilBits,
                                    const GrGLIRect& viewport,
-                                   GrGLTexture* texture,
-                                   GrGpuGL* gl) : INHERITED(texture,
-                                                            viewport.fWidth,
-                                                            viewport.fHeight,
-                                                            stencilBits) {
-    fGL                     = gl;
+                                   GrGLTexture* texture)
+    : INHERITED(gpu, texture, viewport.fWidth, viewport.fHeight, stencilBits) {
     fRTFBOID                = ids.fRTFBOID;
     fTexFBOID               = ids.fTexFBOID;
     fStencilRenderbufferID  = ids.fStencilRenderbufferID;
@@ -39,10 +38,10 @@
     GrSafeRef(fTexIDObj);
 }
 
-GrGLRenderTarget::~GrGLRenderTarget() {
-    fGL->notifyRenderTargetDelete(this);
+void GrGLRenderTarget::onRelease() {
     if (fOwnIDs) {
         if (fTexFBOID) {
+            GPUGL->notifyRenderTargetDelete(this);
             GR_GL(DeleteFramebuffers(1, &fTexFBOID));
         }
         if (fRTFBOID && fRTFBOID != fTexFBOID) {
@@ -55,16 +54,22 @@
             GR_GL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
         }
     }
+    fRTFBOID                = 0;
+    fTexFBOID               = 0;
+    fStencilRenderbufferID  = 0;
+    fMSColorRenderbufferID  = 0;
     GrSafeUnref(fTexIDObj);
+    fTexIDObj = NULL;
 }
 
-void GrGLRenderTarget::abandon() {
+void GrGLRenderTarget::onAbandon() {
     fRTFBOID                = 0;
     fTexFBOID               = 0;
     fStencilRenderbufferID  = 0;
     fMSColorRenderbufferID  = 0;
     if (NULL != fTexIDObj) {
         fTexIDObj->abandon();
+        fTexIDObj = NULL;
     }
 }
 
@@ -92,13 +97,14 @@
 };
 
 
-GrGLTexture::GrGLTexture(const GLTextureDesc& textureDesc,
+GrGLTexture::GrGLTexture(GrGpuGL* gpu,
+                         const GLTextureDesc& textureDesc,
                          const GLRenderTargetIDs& rtIDs,
-                         const TexParams& initialTexParams,
-                         GrGpuGL* gl)
-        : INHERITED(textureDesc.fContentWidth, 
-                    textureDesc.fContentHeight, 
-                    textureDesc.fFormat) {
+                         const TexParams& initialTexParams)
+    : INHERITED(gpu,
+                textureDesc.fContentWidth,
+                textureDesc.fContentHeight,
+                textureDesc.fFormat) {
 
     fTexParams          = initialTexParams;
     fTexIDObj           = new GrGLTexID(textureDesc.fTextureID);
@@ -113,7 +119,6 @@
     fScaleY             = GrIntToScalar(textureDesc.fContentHeight) /
                             textureDesc.fAllocHeight;
     fRenderTarget       = NULL;
-    fGpuGL              = gl;
 
     GrAssert(0 != textureDesc.fTextureID);
 
@@ -125,27 +130,32 @@
         vp.fHeight = textureDesc.fContentHeight;
         vp.fBottom = textureDesc.fAllocHeight - textureDesc.fContentHeight;
 
-        fRenderTarget = new GrGLRenderTarget(rtIDs, fTexIDObj,
+        fRenderTarget = new GrGLRenderTarget(gpu, rtIDs, fTexIDObj,
                                              textureDesc.fStencilBits,
-                                             vp, this, gl);
+                                             vp, this);
     }
 }
 
-GrGLTexture::~GrGLTexture() {
-    fGpuGL->notifyTextureDelete(this);
-    fTexIDObj->unref();
-    GrSafeUnref(fRenderTarget);
+void GrGLTexture::onRelease() {
+    if (NULL != fTexIDObj) {
+        GPUGL->notifyTextureDelete(this);
+        fTexIDObj->unref();
+        fTexIDObj = NULL;
+        GrSafeUnref(fRenderTarget);
+    }
 }
 
-void GrGLTexture::abandon() {
-    fTexIDObj->abandon();
+void GrGLTexture::onAbandon() {
+    if (NULL != fTexIDObj) {
+        fTexIDObj->abandon();
+    }
     if (NULL != fRenderTarget) {
         fRenderTarget->abandon();
     }
 }
 
 GrRenderTarget* GrGLTexture::asRenderTarget() {
-    return (GrRenderTarget*)fRenderTarget;
+    return fRenderTarget;
 }
 
 void GrGLTexture::releaseRenderTarget() {
@@ -158,8 +168,8 @@
                                     uint32_t width,
                                     uint32_t height,
                                     const void* srcData) {
-    
-    fGpuGL->setSpareTextureUnit();
+
+    GPUGL->setSpareTextureUnit();
 
     // glCompressedTexSubImage2D doesn't support any formats
     // (at least without extensions)
@@ -170,7 +180,7 @@
     GrAssert(kTopDown_Orientation == fOrientation);
     GR_GL(BindTexture(GR_GL_TEXTURE_2D, fTexIDObj->id()));
     GR_GL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, fUploadByteCount));
-    GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, x, y, width, height, 
+    GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, x, y, width, height,
                         fUploadFormat, fUploadType, srcData));
 
 }
diff --git a/gpu/src/GrGLVertexBuffer.cpp b/gpu/src/GrGLVertexBuffer.cpp
index f96f90e..3fa1425 100644
--- a/gpu/src/GrGLVertexBuffer.cpp
+++ b/gpu/src/GrGLVertexBuffer.cpp
@@ -18,42 +18,45 @@
 #include "GrGLVertexBuffer.h"
 #include "GrGpuGL.h"
 
-GrGLVertexBuffer::GrGLVertexBuffer(GrGLuint id, GrGpuGL* gl, size_t sizeInBytes,
-                                   bool dynamic) :
-                                   INHERITED(sizeInBytes, dynamic),
-                                   fGL(gl),
-                                   fBufferID(id),
-                                   fLockPtr(NULL) {
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+GrGLVertexBuffer::GrGLVertexBuffer(GrGpuGL* gpu,
+                                   GrGLuint id,
+                                   size_t sizeInBytes,
+                                   bool dynamic)
+    : INHERITED(gpu, sizeInBytes, dynamic)
+    , fBufferID(id)
+    , fLockPtr(NULL) {
 }
 
-GrGLVertexBuffer::~GrGLVertexBuffer() {
+void GrGLVertexBuffer::onRelease() {
     // make sure we've not been abandoned
     if (fBufferID) {
-        fGL->notifyVertexBufferDelete(this);
+        GPUGL->notifyVertexBufferDelete(this);
         GR_GL(DeleteBuffers(1, &fBufferID));
+        fBufferID = 0;
     }
 }
 
+void GrGLVertexBuffer::onAbandon() {
+    fBufferID = 0;
+    fLockPtr = NULL;
+}
+
 void GrGLVertexBuffer::bind() const {
     GR_GL(BindBuffer(GR_GL_ARRAY_BUFFER, fBufferID));
-    fGL->notifyVertexBufferBind(this);
+    GPUGL->notifyVertexBufferBind(this);
 }
 
 GrGLuint GrGLVertexBuffer::bufferID() const {
     return fBufferID;
 }
 
-void GrGLVertexBuffer::abandon() {
-    fBufferID = 0;
-    fGL = NULL;
-    fLockPtr = NULL;
-}
-
 void* GrGLVertexBuffer::lock() {
     GrAssert(fBufferID);
     GrAssert(!isLocked());
-    if (fGL->supportsBufferLocking()) {
-        bind();
+    if (GPUGL->supportsBufferLocking()) {
+        this->bind();
         // Let driver know it can discard the old data
         GR_GL(BufferData(GR_GL_ARRAY_BUFFER, size(), NULL,
                          dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
@@ -68,21 +71,22 @@
 }
 
 void GrGLVertexBuffer::unlock() {
+
     GrAssert(fBufferID);
     GrAssert(isLocked());
-    GrAssert(fGL->supportsBufferLocking());
+    GrAssert(GPUGL->supportsBufferLocking());
 
-    bind();
+    this->bind();
     GR_GL(UnmapBuffer(GR_GL_ARRAY_BUFFER));
     fLockPtr = NULL;
 }
 
 bool GrGLVertexBuffer::isLocked() const {
-    GrAssert(fBufferID);
+    GrAssert(!this->isValid() || fBufferID);
 #if GR_DEBUG
-    if (fGL->supportsBufferLocking()) {
+    if (this->isValid() && GPUGL->supportsBufferLocking()) {
         GrGLint mapped;
-        bind();
+        this->bind();
         GR_GL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER, GR_GL_BUFFER_MAPPED, &mapped));
         GrAssert(!!mapped == !!fLockPtr);
     }
@@ -96,7 +100,7 @@
     if (srcSizeInBytes > size()) {
         return false;
     }
-    bind();
+    this->bind();
     GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
     if (size() == srcSizeInBytes) {
         GR_GL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
@@ -115,7 +119,7 @@
     if (srcSizeInBytes + offset > size()) {
         return false;
     }
-    bind();
+    this->bind();
     GR_GL(BufferSubData(GR_GL_ARRAY_BUFFER, offset, srcSizeInBytes, src));
     return true;
 }
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index 378b881..31e4d99 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -69,20 +69,22 @@
 
 extern void gr_run_unittests();
 
-GrGpu::GrGpu() : f8bitPaletteSupport(false),
-                 fCurrPoolVertexBuffer(NULL),
-                 fCurrPoolStartVertex(0),
-                 fCurrPoolIndexBuffer(NULL),
-                 fCurrPoolStartIndex(0),
-                 fVertexPool(NULL),
-                 fIndexPool(NULL),
-                 fQuadIndexBuffer(NULL),
-                 fUnitSquareVertexBuffer(NULL),
-                 fDefaultPathRenderer(NULL),
-                 fClientPathRenderer(NULL),
-                 fContextIsDirty(true),
-                 fVertexPoolInUse(false),
-                 fIndexPoolInUse(false) {
+GrGpu::GrGpu()
+    : f8bitPaletteSupport(false)
+    , fCurrPoolVertexBuffer(NULL)
+    , fCurrPoolStartVertex(0)
+    , fCurrPoolIndexBuffer(NULL)
+    , fCurrPoolStartIndex(0)
+    , fVertexPool(NULL)
+    , fIndexPool(NULL)
+    , fQuadIndexBuffer(NULL)
+    , fUnitSquareVertexBuffer(NULL)
+    , fDefaultPathRenderer(NULL)
+    , fClientPathRenderer(NULL)
+    , fContextIsDirty(true)
+    , fVertexPoolInUse(false)
+    , fIndexPoolInUse(false)
+    , fResourceHead(NULL) {
 #if GR_DEBUG
     //gr_run_unittests();
 #endif
@@ -90,17 +92,76 @@
 }
 
 GrGpu::~GrGpu() {
-    GrSafeUnref(fQuadIndexBuffer);
-    GrSafeUnref(fUnitSquareVertexBuffer);
-    delete fVertexPool;
-    delete fIndexPool;
-    GrSafeUnref(fClientPathRenderer);
-    GrSafeUnref(fDefaultPathRenderer);
+    releaseResources();
 }
 
-void GrGpu::resetContext() {
+void GrGpu::abandonResources() {
+
+    while (NULL != fResourceHead) {
+        fResourceHead->abandon();
+    }
+
+    GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
+    GrAssert(NULL == fUnitSquareVertexBuffer ||
+             !fUnitSquareVertexBuffer->isValid());
+    GrSafeSetNull(fQuadIndexBuffer);
+    GrSafeSetNull(fUnitSquareVertexBuffer);
+    delete fVertexPool;
+    fVertexPool = NULL;
+    delete fIndexPool;
+    fIndexPool = NULL;
 }
 
+void GrGpu::releaseResources() {
+
+    while (NULL != fResourceHead) {
+        fResourceHead->release();
+    }
+
+    GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
+    GrAssert(NULL == fUnitSquareVertexBuffer ||
+             !fUnitSquareVertexBuffer->isValid());
+    GrSafeSetNull(fQuadIndexBuffer);
+    GrSafeSetNull(fUnitSquareVertexBuffer);
+    delete fVertexPool;
+    fVertexPool = NULL;
+    delete fIndexPool;
+    fIndexPool = NULL;
+}
+
+void GrGpu::insertResource(GrResource* resource) {
+    GrAssert(NULL != resource);
+    GrAssert(this == resource->getGpu());
+    GrAssert(NULL == resource->fNext);
+    GrAssert(NULL == resource->fPrevious);
+
+    resource->fNext = fResourceHead;
+    if (NULL != fResourceHead) {
+        GrAssert(NULL == fResourceHead->fPrevious);
+        fResourceHead->fPrevious = resource;
+    }
+    fResourceHead = resource;
+}
+
+void GrGpu::removeResource(GrResource* resource) {
+    GrAssert(NULL != resource);
+    GrAssert(NULL != fResourceHead);
+
+    if (fResourceHead == resource) {
+        GrAssert(NULL == resource->fPrevious);
+        fResourceHead = resource->fNext;
+    } else {
+        GrAssert(NULL != fResourceHead);
+        resource->fPrevious->fNext = resource->fNext;
+    }
+    if (NULL != resource->fNext) {
+        resource->fNext->fPrevious = resource->fPrevious;
+    }
+    resource->fNext = NULL;
+    resource->fPrevious = NULL;
+}
+
+
 void GrGpu::unimpl(const char msg[]) {
 #if GR_DEBUG
     GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 6833a31..bb71255 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -232,7 +232,7 @@
     fMSFBOType = kNone_MSFBO;
     if (GR_GL_SUPPORT_ES) {
        if (has_gl_extension("GL_CHROMIUM_framebuffer_multisample")) {
-           // chrome's extension is equivalent to the EXT msaa 
+           // chrome's extension is equivalent to the EXT msaa
            // and fbo_blit extensions.
             fMSFBOType = kDesktopEXT_MSFBO;
        } else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
@@ -552,7 +552,7 @@
     rtIDs.fRTFBOID  = (GrGLuint)platformRenderTarget;
     rtIDs.fTexFBOID = (GrGLuint)platformRenderTarget;
 
-    return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
+    return new GrGLRenderTarget(this, rtIDs, NULL, stencilBits, viewport, NULL);
 }
 
 GrRenderTarget* GrGpuGL::createRenderTargetFrom3DApiStateHelper() {
@@ -571,7 +571,7 @@
 
     rtIDs.fOwnIDs = false;
 
-    return new GrGLRenderTarget(rtIDs, NULL, stencilBits, viewport, NULL, this);
+    return new GrGLRenderTarget(this, rtIDs, NULL, stencilBits, viewport, NULL);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -833,7 +833,7 @@
         GR_GL(GenFramebuffers(1, &rtIDs.fTexFBOID));
         GrAssert(rtIDs.fTexFBOID);
 
-        // If we are using multisampling and we will create two FBOS We render 
+        // If we are using multisampling and we will create two FBOS We render
         // to one and then resolve to the texture bound to the other.
         if (samples > 1 && kNone_MSFBO != fMSFBOType) {
             GR_GL(GenFramebuffers(1, &rtIDs.fRTFBOID));
@@ -997,7 +997,7 @@
     GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
              tex->fTextureID, width, height, tex->fUploadByteCount);
 #endif
-    GrGLTexture* tex = new GrGLTexture(glDesc, rtIDs, DEFAULT_PARAMS, this);
+    GrGLTexture* tex = new GrGLTexture(this, glDesc, rtIDs, DEFAULT_PARAMS);
 
     if (0 != rtIDs.fTexFBOID) {
         GrRenderTarget* rt = tex->asRenderTarget();
@@ -1032,7 +1032,7 @@
             fHWGeometryState.fVertexBuffer = NULL;
             return NULL;
         }
-        GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(id, this,
+        GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(this, id,
                                                               size, dynamic);
         fHWGeometryState.fVertexBuffer = vertexBuffer;
         return vertexBuffer;
@@ -1055,7 +1055,7 @@
             fHWGeometryState.fIndexBuffer = NULL;
             return NULL;
         }
-        GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(id, this,
+        GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(this, id,
                                                          size, dynamic);
         fHWGeometryState.fIndexBuffer = indexBuffer;
         return indexBuffer;
diff --git a/gpu/src/GrResource.cpp b/gpu/src/GrResource.cpp
new file mode 100644
index 0000000..70e87d5
--- /dev/null
+++ b/gpu/src/GrResource.cpp
@@ -0,0 +1,41 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include "GrResource.h"
+#include "GrGpu.h"
+
+GrResource::GrResource(GrGpu* gpu) {
+    fGpu        = gpu;
+    fNext       = NULL;
+    fPrevious   = NULL;
+    fGpu->insertResource(this);
+}
+
+void GrResource::release() {
+    if (NULL != fGpu) {
+        this->onRelease();
+        fGpu->removeResource(this);
+        fGpu = NULL;
+    }
+}
+
+void GrResource::abandon() {
+    if (NULL != fGpu) {
+        this->onAbandon();
+        fGpu->removeResource(this);
+        fGpu = NULL;
+    }
+}
diff --git a/gpu/src/GrTextStrike.cpp b/gpu/src/GrTextStrike.cpp
index 6cdb61c..a245997 100644
--- a/gpu/src/GrTextStrike.cpp
+++ b/gpu/src/GrTextStrike.cpp
@@ -58,19 +58,12 @@
     return strike;
 }
 
-void GrFontCache::abandonAll() {
-    fCache.deleteAll();
-    if (fAtlasMgr) {
-        fAtlasMgr->abandonAll();
-        delete fAtlasMgr;
-        fAtlasMgr = NULL;
-    }
-}
-
 void GrFontCache::freeAll() {
     fCache.deleteAll();
     delete fAtlasMgr;
     fAtlasMgr = NULL;
+    fHead = NULL;
+    fTail = NULL;
 }
 
 void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
diff --git a/gpu/src/GrTextureCache.cpp b/gpu/src/GrTextureCache.cpp
index fe3ff68..c3a61ac 100644
--- a/gpu/src/GrTextureCache.cpp
+++ b/gpu/src/GrTextureCache.cpp
@@ -55,7 +55,7 @@
 GrTextureCache::~GrTextureCache() {
     GrAutoTextureCacheValidate atcv(this);
 
-    this->deleteAll(kFreeTexture_DeleteMode);
+    this->removeAll();
 }
 
 void GrTextureCache::getLimits(int* maxTextures, size_t* maxTextureBytes) const{
@@ -237,7 +237,7 @@
     }
 }
 
-void GrTextureCache::deleteAll(DeleteMode mode) {
+void GrTextureCache::removeAll() {
     GrAssert(!fClientDetachedCount);
     GrAssert(!fClientDetachedBytes);
 
@@ -246,9 +246,6 @@
         GrAssert(!entry->isLocked());
 
         GrTextureEntry* next = entry->fNext;
-        if (kAbandonTexture_DeleteMode == mode) {
-            entry->texture()->abandon();
-        }
         delete entry;
         entry = next;
     }
diff --git a/gyp/skia.gyp b/gyp/skia.gyp
index b46cd82..a9c4600 100644
--- a/gyp/skia.gyp
+++ b/gyp/skia.gyp
@@ -886,6 +886,7 @@
         '../gpu/include/GrRect.h',
         '../gpu/include/GrRectanizer.h',
         '../gpu/include/GrRefCnt.h',
+        '../gpu/include/GrResource.h',
         '../gpu/include/GrSamplerState.h',
         '../gpu/include/GrScalar.h',
         '../gpu/include/GrStencil.h',
@@ -936,6 +937,7 @@
         '../gpu/src/GrPrintf_printf.cpp',
         '../gpu/src/GrRectanizer.cpp',
         '../gpu/src/GrRedBlackTree.h',
+        '../gpu/src/GrResource.cpp',
         '../gpu/src/GrStencil.cpp',
         #'../gpu/src/GrTesselatedPathRenderer.cpp',
         '../gpu/src/GrTextContext.cpp',
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index 223923b..49dac74 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -156,14 +156,6 @@
         unsigned a = SkGetPackedA32(pm);
         return GrColorPackRGBA(r, g, b, a);
     }
-
-    /**
-     *  This abandons all texture caches (for bitmaps and text) associated with
-     *  the gpu, and frees any associated skia caches. It differs from
-     *  deleteAllTextures in that it assumes that the gpu has lots its context,
-     *  and thus the associated HW textures are no longer valid
-     */
-    static void AbandonAllTextures(GrContext*);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index c71326b..983a910 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -342,13 +342,20 @@
 
 #if defined(SK_SUPPORT_GL)
     if (attachGL()) {
-#if 0
         if (NULL != fGrContext) {
+        // various gr lifecycle tests
+        #if   0
+            fGrContext->freeGpuResources();
+        #elif 0
+            // this will leak resources.
+            fGrContext->contextLost();
+        #elif 0
             GrAssert(1 == fGrContext->refcnt());
             fGrContext->unref();
             fGrContext = NULL;
+        #endif
         }
-#endif
+
         if (NULL == fGrContext) {
         #if defined(SK_USE_SHADERS)
             fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index ec4fc1d..630c3f4 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -235,8 +235,3 @@
     }
 }
 
-void SkGr::AbandonAllTextures(GrContext* ctx) {
-    ctx->abandonAllTextures();
-}
-
-
diff --git a/xcode/gpu/gpu.xcodeproj/project.pbxproj b/xcode/gpu/gpu.xcodeproj/project.pbxproj
index d7a682d..a852a0b 100644
--- a/xcode/gpu/gpu.xcodeproj/project.pbxproj
+++ b/xcode/gpu/gpu.xcodeproj/project.pbxproj
@@ -91,6 +91,8 @@
 		7D66934C132ABD8F003AC2F5 /* GrGLInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D66934B132ABD8F003AC2F5 /* GrGLInterface.h */; };
 		7D66934E132ABDA7003AC2F5 /* GrGLPlatformIncludes.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D66934D132ABDA7003AC2F5 /* GrGLPlatformIncludes.h */; };
 		7D6EBF5A13330E8400AEAADD /* GrGLDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D6EBF5913330E8400AEAADD /* GrGLDefines.h */; };
+		D5134DB1134281FD0041146E /* GrResource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5134DB0134281FD0041146E /* GrResource.cpp */; };
+		D5134DB5134282410041146E /* GrResource.h in Headers */ = {isa = PBXBuildFile; fileRef = D5134DB4134282410041146E /* GrResource.h */; };
 		D51B4C3C1342649500718A57 /* GrPathUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D51B4C3A1342649500718A57 /* GrPathUtils.cpp */; };
 		D51B4C3D1342649500718A57 /* GrPathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = D51B4C3B1342649500718A57 /* GrPathUtils.h */; };
 		D539049B12EA01E30025F3D6 /* GrContext_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = D539049A12EA01E30025F3D6 /* GrContext_impl.h */; };
@@ -193,6 +195,8 @@
 		7D66934D132ABDA7003AC2F5 /* GrGLPlatformIncludes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrGLPlatformIncludes.h; path = ../../gpu/include/GrGLPlatformIncludes.h; sourceTree = SOURCE_ROOT; };
 		7D6EBF5913330E8400AEAADD /* GrGLDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrGLDefines.h; path = ../../gpu/include/GrGLDefines.h; sourceTree = SOURCE_ROOT; };
 		D2AAC046055464E500DB518D /* libgpu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgpu.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		D5134DB0134281FD0041146E /* GrResource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrResource.cpp; path = ../../gpu/src/GrResource.cpp; sourceTree = SOURCE_ROOT; };
+		D5134DB4134282410041146E /* GrResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrResource.h; path = ../../gpu/include/GrResource.h; sourceTree = SOURCE_ROOT; };
 		D51B4C3A1342649500718A57 /* GrPathUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrPathUtils.cpp; path = ../../gpu/src/GrPathUtils.cpp; sourceTree = SOURCE_ROOT; };
 		D51B4C3B1342649500718A57 /* GrPathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrPathUtils.h; path = ../../gpu/src/GrPathUtils.h; sourceTree = SOURCE_ROOT; };
 		D539049A12EA01E30025F3D6 /* GrContext_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrContext_impl.h; path = ../../gpu/include/GrContext_impl.h; sourceTree = SOURCE_ROOT; };
@@ -223,6 +227,7 @@
 		00115E3712C116B7008296FE /* include */ = {
 			isa = PBXGroup;
 			children = (
+				D5134DB4134282410041146E /* GrResource.h */,
 				D59BD3F3133BBB49003B546A /* GrPathRenderer.h */,
 				7D6EBF5913330E8400AEAADD /* GrGLDefines.h */,
 				7D66934D132ABDA7003AC2F5 /* GrGLPlatformIncludes.h */,
@@ -301,6 +306,7 @@
 		08FB7795FE84155DC02AAC07 /* Source */ = {
 			isa = PBXGroup;
 			children = (
+				D5134DB0134281FD0041146E /* GrResource.cpp */,
 				D51B4C3A1342649500718A57 /* GrPathUtils.cpp */,
 				D51B4C3B1342649500718A57 /* GrPathUtils.h */,
 				D59BD412133BD384003B546A /* GrCreatePathRenderer_none.cpp */,
@@ -433,6 +439,7 @@
 				7D6EBF5A13330E8400AEAADD /* GrGLDefines.h in Headers */,
 				D59BD3F4133BBB49003B546A /* GrPathRenderer.h in Headers */,
 				D51B4C3D1342649500718A57 /* GrPathUtils.h in Headers */,
+				D5134DB5134282410041146E /* GrResource.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -515,6 +522,7 @@
 				7D669346132ABD5D003AC2F5 /* GrGLInterface.cpp in Sources */,
 				D59BD413133BD384003B546A /* GrCreatePathRenderer_none.cpp in Sources */,
 				D51B4C3C1342649500718A57 /* GrPathUtils.cpp in Sources */,
+				D5134DB1134281FD0041146E /* GrResource.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};