Add GrResourceCache2.
authorbsalomon <bsalomon@google.com>
Thu, 21 Aug 2014 20:02:13 +0000 (13:02 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 21 Aug 2014 20:02:13 +0000 (13:02 -0700)
Currently it just replaces GrGpu as the owner of the linked list of resources.

Committed: https://skia.googlesource.com/skia/+/94ce9ac8624dbb45656b8f5c992fad9c9ff3ee5f

R=mtklein@google.com, robertphillips@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/481443002

17 files changed:
gyp/gpu.gypi
include/gpu/GrContext.h
include/gpu/GrGpuResource.h
src/gpu/GrClipMaskCache.h
src/gpu/GrClipMaskManager.cpp
src/gpu/GrClipMaskManager.h
src/gpu/GrContext.cpp
src/gpu/GrGpu.cpp
src/gpu/GrGpu.h
src/gpu/GrGpuResource.cpp
src/gpu/GrLayerCache.cpp
src/gpu/GrResourceCache.cpp
src/gpu/GrResourceCache2.cpp [new file with mode: 0644]
src/gpu/GrResourceCache2.h [new file with mode: 0644]
src/gpu/gl/GrGpuGL.cpp
src/gpu/gl/GrGpuGL.h
src/gpu/gl/GrGpuGL_program.cpp

index ec2a07fc97001c241415617ae0ff265b6d3c7d2e..56ef4b5a6307c63fcd23aaa532b034271a6e20ea 100644 (file)
       '<(skia_src_path)/gpu/GrReducedClip.h',
       '<(skia_src_path)/gpu/GrResourceCache.cpp',
       '<(skia_src_path)/gpu/GrResourceCache.h',
+      '<(skia_src_path)/gpu/GrResourceCache2.cpp',
+      '<(skia_src_path)/gpu/GrResourceCache2.h',
       '<(skia_src_path)/gpu/GrStencil.cpp',
       '<(skia_src_path)/gpu/GrStencil.h',
       '<(skia_src_path)/gpu/GrStencilAndCoverPathRenderer.cpp',
index d6245100d6c947165dfe9b85b08ae14f0817b268..4f9b642b23d86d048ddb7e6101a9092a061494e8 100644 (file)
@@ -35,6 +35,7 @@ class GrPath;
 class GrPathRenderer;
 class GrResourceEntry;
 class GrResourceCache;
+class GrResourceCache2;
 class GrStencilBuffer;
 class GrTestTarget;
 class GrTextContext;
@@ -926,6 +927,7 @@ public:
     GrDrawTarget* getTextTarget();
     const GrIndexBuffer* getQuadIndexBuffer() const;
     GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
+    GrResourceCache2* getResourceCache2() { return fResourceCache2; }
 
     // Called by tests that draw directly to the context via GrDrawTarget
     void getTestTarget(GrTestTarget*);
@@ -973,6 +975,7 @@ private:
     GrDrawState*                    fDrawState;
 
     GrResourceCache*                fResourceCache;
+    GrResourceCache2*               fResourceCache2;
     GrFontCache*                    fFontCache;
     SkAutoTDelete<GrLayerCache>     fLayerCache;
 
index 127f64b903027732436e2898c9c832eca9ec2867..8b162823bf6e65f3f6904bc4d20d391559b8d220 100644 (file)
@@ -12,6 +12,7 @@
 #include "SkTInternalLList.h"
 
 class GrResourceCacheEntry;
+class GrResourceCache2;
 class GrGpu;
 class GrContext;
 
@@ -118,12 +119,13 @@ private:
 
     static uint32_t CreateUniqueID();
 
-    // We're in an internal doubly linked list
+    // We're in an internal doubly linked list owned by GrResourceCache2
     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrGpuResource);
 
-    GrGpu*              fGpu;               // not reffed. The GrGpu can be deleted while there
-                                            // are still live GrGpuResources. It will call
-                                            // release() on all such objects in its destructor.
+    // This is not ref'ed but abandon() or release() will be called before the GrGpu object
+    // is destroyed. Those calls set will this to NULL.
+    GrGpu* fGpu;
+
     enum Flags {
         /**
          * This object wraps a GPU object given to us by the user.
index b332c7be9b96e2daf8537344b1527bbdb414492f..6b484e8af83e15918b63a53704f34ab26de42378 100644 (file)
@@ -41,6 +41,7 @@ public:
         // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
         // an offset to the caller.
         if (back->fLastMask.texture() &&
+            !back->fLastMask.texture()->wasDestroyed() &&
             back->fLastBound == bounds &&
             back->fLastClipGenID == clipGenID) {
             return true;
@@ -179,8 +180,8 @@ public:
         return fContext;
     }
 
-    void releaseResources() {
-
+    //  TODO: Remove this when we hold cache keys instead of refs to textures.
+    void purgeResources() {
         SkDeque::F2BIter iter(fStack);
         for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
                 frame != NULL;
@@ -219,7 +220,8 @@ private:
 
         int32_t                 fLastClipGenID;
         // The mask's width & height values are used by GrClipMaskManager to correctly scale the
-        // texture coords for the geometry drawn with this mask.
+        // texture coords for the geometry drawn with this mask. TODO: This should be a cache key
+        // and not a hard ref to a texture.
         GrAutoScratchTexture    fLastMask;
         // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
         // used by GrClipMaskManager to position a rect and compute texture coords for the mask.
index 7cafdf7d563b05a32a033098a1c5be6dad40b796..d4ab0b74f953cf11757b5844ffa91a31ae5e189c 100644 (file)
@@ -1112,8 +1112,8 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-void GrClipMaskManager::releaseResources() {
-    fAACache.releaseResources();
+void GrClipMaskManager::purgeResources() {
+    fAACache.purgeResources();
 }
 
 void GrClipMaskManager::setGpu(GrGpu* gpu) {
index c3a21fd8a2b1e9d6771ebde48bbdaa2731b28b85..ea16fc842b5b283502d93ed87c4f8a5726019fc8 100644 (file)
@@ -53,7 +53,11 @@ public:
     bool setupClipping(const GrClipData* clipDataIn, GrDrawState::AutoRestoreEffects*,
                        const SkRect* devBounds);
 
-    void releaseResources();
+    /**
+     * Purge resources to free up memory. TODO: This class shouldn't hold any long lived refs
+     * which will allow ResourceCache2 to automatically purge anything this class has created.
+     */
+    void purgeResources();
 
     bool isClipInStencil() const {
         return kStencil_ClipMaskType == fCurrClipMaskType;
index 091c4a899e401595fe26c4fa7f5053391d02e2cd..b420df2bc806c0b06fcb7aeff9f18ff5e61e0c1c 100755 (executable)
@@ -25,6 +25,7 @@
 #include "GrPathRenderer.h"
 #include "GrPathUtils.h"
 #include "GrResourceCache.h"
+#include "GrResourceCache2.h"
 #include "GrSoftwarePathRenderer.h"
 #include "GrStencilBuffer.h"
 #include "GrStencilAndCoverTextContext.h"
@@ -108,6 +109,7 @@ GrContext::GrContext(const Options& opts) : fOptions(opts) {
     fPathRendererChain = NULL;
     fSoftwarePathRenderer = NULL;
     fResourceCache = NULL;
+    fResourceCache2 = NULL;
     fFontCache = NULL;
     fDrawBuffer = NULL;
     fDrawBufferVBAllocPool = NULL;
@@ -133,6 +135,7 @@ bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
     fResourceCache = SkNEW_ARGS(GrResourceCache, (MAX_RESOURCE_CACHE_COUNT,
                                                   MAX_RESOURCE_CACHE_BYTES));
     fResourceCache->setOverbudgetCallback(OverbudgetCB, this);
+    fResourceCache2 = SkNEW(GrResourceCache2);
 
     fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
 
@@ -161,10 +164,8 @@ GrContext::~GrContext() {
         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
     }
 
-    // Since the gpu can hold scratch textures, give it a chance to let go
-    // of them before freeing the texture cache
-    fGpu->purgeResources();
-
+    delete fResourceCache2;
+    fResourceCache2 = NULL;
     delete fResourceCache;
     fResourceCache = NULL;
     delete fFontCache;
@@ -184,7 +185,9 @@ GrContext::~GrContext() {
 void GrContext::abandonContext() {
     // abandon first to so destructors
     // don't try to free the resources in the API.
-    fGpu->abandonResources();
+    fResourceCache2->abandonAll();
+
+    fGpu->contextAbandonded();
 
     // a path renderer may be holding onto resources that
     // are now unusable
@@ -207,7 +210,6 @@ void GrContext::abandonContext() {
 
     fFontCache->freeAll();
     fLayerCache->freeAll();
-    fGpu->markContextDirty();
 }
 
 void GrContext::resetContext(uint32_t state) {
@@ -218,6 +220,9 @@ void GrContext::freeGpuResources() {
     this->flush();
 
     fGpu->purgeResources();
+    if (NULL != fDrawBuffer) {
+        fDrawBuffer->purgeResources();
+    }
 
     fAARectRenderer->reset();
     fOvalRenderer->reset();
@@ -540,6 +545,15 @@ void GrContext::addExistingTextureToCache(GrTexture* texture) {
 }
 
 void GrContext::unlockScratchTexture(GrTexture* texture) {
+    if (texture->wasDestroyed()) {
+        if (texture->getCacheEntry()->key().isScratch()) {
+            // This texture was detached from the cache but the cache still had a ref to it but
+            // not a pointer to it.
+            texture->unref();
+        }
+        return;
+    }
+
     ASSERT_OWNED_RESOURCE(texture);
     SkASSERT(NULL != texture->getCacheEntry());
 
index 74df26002d17c5692458cda6e9ba60a1a79d98ac..6ada03b62dab0ddc799219948e6d0a81a91b8a6a 100644 (file)
@@ -50,18 +50,6 @@ GrGpu::GrGpu(GrContext* context)
 }
 
 GrGpu::~GrGpu() {
-    this->releaseResources();
-}
-
-void GrGpu::abandonResources() {
-
-    fClipMaskManager.releaseResources();
-
-    while (NULL != fObjectList.head()) {
-        fObjectList.head()->abandon();
-    }
-
-    SkASSERT(NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed());
     SkSafeSetNull(fQuadIndexBuffer);
     delete fVertexPool;
     fVertexPool = NULL;
@@ -69,42 +57,7 @@ void GrGpu::abandonResources() {
     fIndexPool = NULL;
 }
 
-void GrGpu::releaseResources() {
-
-    fClipMaskManager.releaseResources();
-
-    while (NULL != fObjectList.head()) {
-        fObjectList.head()->release();
-    }
-
-    SkASSERT(NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed());
-    SkSafeSetNull(fQuadIndexBuffer);
-    delete fVertexPool;
-    fVertexPool = NULL;
-    delete fIndexPool;
-    fIndexPool = NULL;
-}
-
-void GrGpu::insertObject(GrGpuResource* object) {
-    SkASSERT(NULL != object);
-    SkASSERT(this == object->getGpu());
-
-    fObjectList.addToHead(object);
-}
-
-void GrGpu::removeObject(GrGpuResource* object) {
-    SkASSERT(NULL != object);
-    SkASSERT(this == object->getGpu());
-
-    fObjectList.remove(object);
-}
-
-
-void GrGpu::unimpl(const char msg[]) {
-#ifdef SK_DEBUG
-    GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
-#endif
-}
+void GrGpu::contextAbandonded() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -318,7 +271,8 @@ static inline void fill_indices(uint16_t* indices, int quadCount) {
 }
 
 const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
-    if (NULL == fQuadIndexBuffer) {
+    if (NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed()) {
+        SkSafeUnref(fQuadIndexBuffer);
         static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
         GrGpu* me = const_cast<GrGpu*>(this);
         fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
index 5020bddb399fe1ec9ffc1626601dcc6c17b10b55..353ec33437f24382eea8dcd37b21a9bff663956d 100644 (file)
@@ -59,6 +59,12 @@ public:
         return fPathRendering.get();
     }
 
+    // Called by GrContext when the underlying backend context has been destroyed.
+    // GrGpu should use this to ensure that no backend API calls will be made from
+    // here onward, including in its destructor. Subclasses should call
+    // INHERITED::contextAbandonded() if they override this.
+    virtual void contextAbandonded();
+
     /**
      * The GrGpu object normally assumes that no outsider is setting state
      * within the underlying 3D API's context/device/whatever. This call informs
@@ -253,30 +259,6 @@ public:
                             GrPixelConfig config, const void* buffer,
                             size_t rowBytes);
 
-    /**
-     * Called to tell GrGpu that all GrGpuResources have been lost and should
-     * be abandoned. Overrides must call INHERITED::abandonResources().
-     */
-    virtual void abandonResources();
-
-    /**
-     * Called to tell GrGpu to release all GrGpuResources. Overrides must call
-     * INHERITED::releaseResources().
-     */
-    void releaseResources();
-
-    /**
-     * Add object to list of objects. Should only be called by GrGpuResource.
-     * @param resource  the resource to add.
-     */
-    void insertObject(GrGpuResource* object);
-
-    /**
-     * Remove object from list of objects. Should only be called by GrGpuResource.
-     * @param resource  the resource to remove.
-     */
-    void removeObject(GrGpuResource* object);
-
     // GrDrawTarget overrides
     virtual void clear(const SkIRect* rect,
                        GrColor color,
@@ -286,7 +268,7 @@ public:
     virtual void purgeResources() SK_OVERRIDE {
         // The clip mask manager can rebuild all its clip masks so just
         // get rid of them all.
-        fClipMaskManager.releaseResources();
+        fClipMaskManager.purgeResources();
     }
 
     // After the client interacts directly with the 3D context state the GrGpu
@@ -523,7 +505,6 @@ private:
     enum {
         kPreallocGeomPoolStateStackCnt = 4,
     };
-    typedef SkTInternalLList<GrGpuResource> ObjectList;
     SkSTArray<kPreallocGeomPoolStateStackCnt, GeometryPoolState, true>  fGeomPoolStateStack;
     ResetTimestamp                                                      fResetTimestamp;
     uint32_t                                                            fResetBits;
@@ -534,9 +515,6 @@ private:
     int                                                                 fIndexPoolUseCnt;
     // these are mutable so they can be created on-demand
     mutable GrIndexBuffer*                                              fQuadIndexBuffer;
-    // Used to abandon/release all resources created by this GrGpu. TODO: Move this
-    // functionality to GrResourceCache.
-    ObjectList                                                          fObjectList;
 
     typedef GrDrawTarget INHERITED;
 };
index 8c2dc4508009a10fa181fd477636c35743b94a1d..7a19c25e46dcf5806db47955b7f22818d75f95a5 100644 (file)
@@ -8,19 +8,27 @@
 
 
 #include "GrGpuResource.h"
+#include "GrResourceCache2.h"
 #include "GrGpu.h"
 
+static inline GrResourceCache2* get_resource_cache2(GrGpu* gpu) {
+    SkASSERT(NULL != gpu);
+    SkASSERT(NULL != gpu->getContext());
+    SkASSERT(NULL != gpu->getContext()->getResourceCache2());
+    return gpu->getContext()->getResourceCache2();
+}
+
 GrGpuResource::GrGpuResource(GrGpu* gpu, bool isWrapped)
-    : fRefCnt(1)
+    : fGpu(gpu)
+    , fRefCnt(1)
     , fCacheEntry(NULL)
     , fUniqueID(CreateUniqueID()) {
-    fGpu              = gpu;
     if (isWrapped) {
         fFlags = kWrapped_FlagBit;
     } else {
         fFlags = 0;
     }
-    fGpu->insertObject(this);
+    get_resource_cache2(fGpu)->insertResource(this);
 }
 
 GrGpuResource::~GrGpuResource() {
@@ -32,7 +40,7 @@ GrGpuResource::~GrGpuResource() {
 void GrGpuResource::release() {
     if (NULL != fGpu) {
         this->onRelease();
-        fGpu->removeObject(this);
+        get_resource_cache2(fGpu)->removeResource(this);
         fGpu = NULL;
     }
 }
@@ -40,7 +48,7 @@ void GrGpuResource::release() {
 void GrGpuResource::abandon() {
     if (NULL != fGpu) {
         this->onAbandon();
-        fGpu->removeObject(this);
+        get_resource_cache2(fGpu)->removeResource(this);
         fGpu = NULL;
     }
 }
index c0510c0365873f6a2d753ac755275a0487b4744a..9325497997fe3470f048d908cc9011c36bb99e0a 100644 (file)
@@ -112,7 +112,7 @@ void GrLayerCache::freeAll() {
     fAtlas.free();
     // GrLayerCache always assumes an atlas exists so recreate it. The atlas 
     // lazily allocates a replacement texture so reallocating a new 
-    // atlas here won't disrupt a GrContext::contextDestroyed or freeGpuResources.
+    // atlas here won't disrupt a GrContext::abandonContext or freeGpuResources.
     // TODO: Make GrLayerCache lazily allocate the atlas manager?
     this->initAtlas();
 }
index e3a17f05c5fa6a88ce05a3ddfeb070ec88f1d556..8a21002e1c5fe17575548281dd7917911011db44 100644 (file)
@@ -267,7 +267,7 @@ void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) {
 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) {
     // If the resource went invalid while it was detached then purge it
     // This can happen when a 3D context was lost,
-    // the client called GrContext::contextDestroyed() to notify Gr,
+    // the client called GrContext::abandonContext() to notify Gr,
     // and then later an SkGpuDevice's destructor releases its backing
     // texture (which was invalidated at contextDestroyed time).
     // TODO: Safely delete the GrResourceCacheEntry as well.
diff --git a/src/gpu/GrResourceCache2.cpp b/src/gpu/GrResourceCache2.cpp
new file mode 100644 (file)
index 0000000..0b6944e
--- /dev/null
@@ -0,0 +1,47 @@
+
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrResourceCache2.h"
+#include "GrGpuResource.h"
+
+GrResourceCache2::~GrResourceCache2() {
+    this->releaseAll();
+}
+
+void GrResourceCache2::insertResource(GrGpuResource* resource) {
+    SkASSERT(NULL != resource);
+    SkASSERT(!resource->wasDestroyed());
+    fResources.addToHead(resource);
+    ++fCount;
+}
+
+void GrResourceCache2::removeResource(GrGpuResource* resource) {
+    fResources.remove(resource);
+    --fCount;
+}
+
+void GrResourceCache2::abandonAll() {
+    while (GrGpuResource* head = fResources.head()) {
+        SkASSERT(!head->wasDestroyed());
+        head->abandon();
+        // abandon should have already removed this from the list.
+        SkASSERT(head != fResources.head());
+    }
+    SkASSERT(!fCount);
+}
+
+void GrResourceCache2::releaseAll() {
+    while (GrGpuResource* head = fResources.head()) {
+        SkASSERT(!head->wasDestroyed());
+        head->release();
+        // release should have already removed this from the list.
+        SkASSERT(head != fResources.head());
+    }
+    SkASSERT(!fCount);
+}
diff --git a/src/gpu/GrResourceCache2.h b/src/gpu/GrResourceCache2.h
new file mode 100644 (file)
index 0000000..1262c80
--- /dev/null
@@ -0,0 +1,40 @@
+
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrResourceCache2_DEFINED
+#define GrResourceCache2_DEFINED
+
+#include "GrTypes.h"
+#include "SkTInternalLList.h"
+
+class GrGpuResource;
+
+/**
+ *  Eventual replacement for GrResourceCache. Currently it simply holds a list
+ *  of all GrGpuResource objects for a GrContext. It is used to invalidate all
+ *  the resources when necessary.
+ */
+class GrResourceCache2 {
+public:
+    GrResourceCache2() : fCount(0) {};
+    ~GrResourceCache2();
+
+    void insertResource(GrGpuResource* resource);
+
+    void removeResource(GrGpuResource* resource);
+
+    void abandonAll();
+
+    void releaseAll();
+
+private:
+    int                             fCount;
+    SkTInternalLList<GrGpuResource> fResources;
+};
+
+#endif
index e7daa6b6592bf777d5ca213f98b64957dd9bd0be..418f5913011a9e1bf745af1e88a5be9f1c3a2205 100644 (file)
@@ -164,9 +164,15 @@ GrGpuGL::~GrGpuGL() {
 
     // This must be called by before the GrDrawTarget destructor
     this->releaseGeometry();
-    // This subclass must do this before the base class destructor runs
-    // since we will unref the GrGLInterface.
-    this->releaseResources();
+}
+
+void GrGpuGL::contextAbandonded() {
+    INHERITED::contextAbandonded();
+    fProgramCache->abandon();
+    fHWProgramID = 0;
+    if (this->glCaps().pathRenderingSupport()) {
+        this->glPathRendering()->abandonGpuResources();
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index 964f5c870ce89190b9a7356e1c81e36fb41c3b4b..110a6671baff4c6e828da84627ff894318655c1c 100644 (file)
@@ -30,6 +30,8 @@ public:
     GrGpuGL(const GrGLContext& ctx, GrContext* context);
     virtual ~GrGpuGL();
 
+    virtual void contextAbandonded() SK_OVERRIDE;
+
     const GrGLContext& glContext() const { return fGLContext; }
 
     const GrGLInterface* glInterface() const { return fGLContext.interface(); }
@@ -75,8 +77,6 @@ public:
 
     virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
 
-    virtual void abandonResources() SK_OVERRIDE;
-
     // These functions should be used to bind GL objects. They track the GL state and skip redundant
     // bindings. Making the equivalent glBind calls directly will confuse the state tracking.
     void bindVertexArray(GrGLuint id) {
index c4011e73142116d6156ccaca204468aa9f856efd..dac7443d17123535c5e4fd9595c6b3f5fd38d53e 100644 (file)
@@ -199,17 +199,6 @@ GrGLProgram* GrGpuGL::ProgramCache::getProgram(const GrGLProgramDesc& desc,
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGpuGL::abandonResources(){
-    INHERITED::abandonResources();
-    fProgramCache->abandon();
-    fHWProgramID = 0;
-    if (this->glCaps().pathRenderingSupport()) {
-        this->glPathRendering()->abandonGpuResources();
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
 
 bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstCopy) {