Remove static effects from the effect memory pool.
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 23 Apr 2013 15:37:27 +0000 (15:37 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 23 Apr 2013 15:37:27 +0000 (15:37 +0000)
Review URL: https://codereview.chromium.org/14081016

git-svn-id: http://skia.googlecode.com/svn/trunk@8828 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkTemplates.h
include/gpu/GrEffect.h
src/gpu/GrAAConvexPathRenderer.cpp
src/gpu/GrAAHairLinePathRenderer.cpp
src/gpu/GrAARectRenderer.cpp
src/gpu/GrOvalRenderer.cpp

index 9078bd2036894d22bd40b899bab8140e932d2f34..24705dbed0ee5e2000aea75ede95092c5952b6d2 100644 (file)
@@ -119,6 +119,24 @@ private:
     T*  fObj;
 };
 
+// Calls ~T() in the destructor.
+template <typename T> class SkAutoTDestroy : SkNoncopyable {
+public:
+    SkAutoTDestroy(T* obj = NULL) : fObj(obj) {}
+    ~SkAutoTDestroy() {
+        if (NULL != fObj) {
+            fObj->~T();
+        }
+    }
+
+    T* get() const { return fObj; }
+    T& operator*() const { SkASSERT(fObj); return *fObj; }
+    T* operator->() const { SkASSERT(fObj); return fObj; }
+
+private:
+    T*  fObj;
+};
+
 template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
 public:
     SkAutoTDeleteArray(T array[]) : fArray(array) {}
index 08f34e0364bc2969b18d0c2e8d9cbfcac3462447..4cef4308ea3441dbb41ccde2118c738f8219c278 100644 (file)
@@ -27,10 +27,15 @@ class SkString;
  * GrEffectRef ref count reaches zero the scratch GrResources owned by the effect can be recycled
  * in service of later draws. However, the deferred draw queue may still own direct references to
  * the underlying GrEffect.
+ *
+ * GrEffectRefs created by new are placed in a per-thread managed pool. The pool is destroyed when
+ * the thread ends. Therefore, all dynamically allocated GrEffectRefs must be unreffed before thread
+ * termination.
  */
 class GrEffectRef : public SkRefCnt {
 public:
     SK_DECLARE_INST_COUNT(GrEffectRef);
+    virtual ~GrEffectRef();
 
     GrEffect* get() { return fEffect; }
     const GrEffect* get() const { return fEffect; }
@@ -41,13 +46,18 @@ public:
     void* operator new(size_t size);
     void operator delete(void* target);
 
+    void* operator new(size_t size, void* placement) {
+        return ::operator new(size, placement);
+    }
+    void operator delete(void* target, void* placement) {
+        ::operator delete(target, placement);
+    }
+
 private:
     friend class GrEffect; // to construct these
 
     explicit GrEffectRef(GrEffect* effect);
 
-    virtual ~GrEffectRef();
-
     GrEffect* fEffect;
 
     typedef SkRefCnt INHERITED;
@@ -63,8 +73,12 @@ private:
     There is no public way to wrap a GrEffect in a GrEffectRef. Thus, a factory should be a static
     member function of a GrEffect subclass.
 
-    Because almost no code should ever handle a GrEffect outside of a GrEffectRef, we privately
-    inherit from GrRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
+    Because almost no code should ever handle a GrEffect directly outside of a GrEffectRef, we
+    privately inherit from GrRefCnt to help prevent accidental direct ref'ing/unref'ing of effects.
+
+    Dynamically allocated GrEffects and their corresponding GrEffectRefs are managed by a per-thread
+    memory pool. The ref count of an effect must reach 0 before the thread terminates and the pool
+    is destroyed. To create a static effect use the macro GR_CREATE_STATIC_EFFECT declared below.
   */
 class GrEffect : private GrRefCnt {
 public:
@@ -159,6 +173,13 @@ public:
     void* operator new(size_t size);
     void operator delete(void* target);
 
+    void* operator new(size_t size, void* placement) {
+        return ::operator new(size, placement);
+    }
+    void operator delete(void* target, void* placement) {
+        ::operator delete(target, placement);
+    }
+
     /** These functions are used when recording effects into a deferred drawing queue. The inc call
         keeps the effect alive outside of GrEffectRef while allowing any resources owned by the
         effect to be returned to the cache for reuse. The dec call must balance the inc call. */
@@ -209,6 +230,14 @@ protected:
         return CreateEffectRef(const_cast<GrEffect*>(effect));
     }
 
+    /** Used by GR_CREATE_STATIC_EFFECT below */
+    static GrEffectRef* CreateStaticEffectRef(void* refStorage, GrEffect* effect) {
+        GrAssert(NULL == effect->fEffectRef);
+        effect->fEffectRef = SkNEW_PLACEMENT_ARGS(refStorage, GrEffectRef, (effect));
+        return effect->fEffectRef;
+    }
+
+
     /** Helper used in subclass factory functions to unref the effect after it has been wrapped in a
         GrEffectRef. E.g.:
 
@@ -285,4 +314,21 @@ inline GrEffectRef::GrEffectRef(GrEffect* effect) {
     fEffect = effect;
 }
 
+/**
+ * This creates an effect outside of the effect memory pool. The effect's destructor will be called
+ * at global destruction time. NAME will be the name of the created GrEffectRef.
+ */
+#define GR_CREATE_STATIC_EFFECT(NAME, EFFECT_CLASS, ARGS)                                         \
+enum {                                                                                            \
+    k_##NAME##_EffectRefOffset = GR_CT_ALIGN_UP(sizeof(EFFECT_CLASS), 8),                         \
+    k_##NAME##_StorageSize = k_##NAME##_EffectRefOffset + sizeof(GrEffectRef)                     \
+};                                                                                                \
+static SkAlignedSStorage<k_##NAME##_StorageSize> g_##NAME##_Storage;                              \
+static void* NAME##_RefLocation = (char*)g_##NAME##_Storage.get() + k_##NAME##_EffectRefOffset;   \
+static GrEffect* NAME##_Effect SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS);\
+static SkAutoTDestroy<GrEffect> NAME##_ad(NAME##_Effect);                                         \
+static GrEffectRef* NAME(GrEffect::CreateStaticEffectRef(NAME##_RefLocation, NAME##_Effect));     \
+static SkAutoTDestroy<GrEffectRef> NAME##_Ref_ad(NAME)
+
+
 #endif
index d7d19a355f06557410d648888221ebc58976fde7..eb52b61923ef4adc7a925d240e6f0ee8f0076368 100644 (file)
@@ -450,12 +450,9 @@ class QuadEdgeEffect : public GrEffect {
 public:
 
     static GrEffectRef* Create() {
-        // we go through this so we only have one copy of each effect
-        static SkAutoTUnref<GrEffectRef> gQuadEdgeEffectRef(
-                    CreateEffectRef(AutoEffectUnref(SkNEW(QuadEdgeEffect))));
-
-        gQuadEdgeEffectRef.get()->ref();
-        return gQuadEdgeEffectRef;
+        GR_CREATE_STATIC_EFFECT(gQuadEdgeEffect, QuadEdgeEffect, ());
+        gQuadEdgeEffect->ref();
+        return gQuadEdgeEffect;
     }
 
     virtual ~QuadEdgeEffect() {}
index 0a19d6ca2ef8a4cbc2a942c87baa58045ad0f1ba..a857dc4e99eef68ff192a3aa678c08ba86b7bb01 100644 (file)
@@ -508,12 +508,9 @@ class HairQuadEdgeEffect : public GrEffect {
 public:
 
     static GrEffectRef* Create() {
-        // we go through this so we only have one copy of each effect
-        static SkAutoTUnref<GrEffectRef> gHairQuadEdgeEffectRef(
-                         CreateEffectRef(AutoEffectUnref(SkNEW(HairQuadEdgeEffect))));
-
-        gHairQuadEdgeEffectRef.get()->ref();
-        return gHairQuadEdgeEffectRef;
+        GR_CREATE_STATIC_EFFECT(gHairQuadEdgeEffect, HairQuadEdgeEffect, ());
+        gHairQuadEdgeEffect->ref();
+        return gHairQuadEdgeEffect;
     }
 
     virtual ~HairQuadEdgeEffect() {}
@@ -609,12 +606,9 @@ class HairLineEdgeEffect : public GrEffect {
 public:
 
     static GrEffectRef* Create() {
-        // we go through this so we only have one copy of each effect
-        static SkAutoTUnref<GrEffectRef> gHairLineEdgeEffectRef(
-                            CreateEffectRef(AutoEffectUnref(SkNEW(HairLineEdgeEffect))));
-
-        gHairLineEdgeEffectRef.get()->ref();
-        return gHairLineEdgeEffectRef;
+        GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ());
+        gHairLineEdge->ref();
+        return gHairLineEdge;
     }
 
     virtual ~HairLineEdgeEffect() {}
index eacd3f1ec9ab7c8d8196be93adddc567ecac86e1..418d80d713859e6f0aabf2ae5531fc291cc7d73f 100644 (file)
@@ -30,10 +30,9 @@ class GrGLRectEffect;
 class GrRectEffect : public GrEffect {
 public:
     static GrEffectRef* Create() {
-        static SkAutoTUnref<GrEffectRef> gRectEffectRef(
-                        CreateEffectRef(AutoEffectUnref(SkNEW(GrRectEffect))));
-        gRectEffectRef.get()->ref();
-        return gRectEffectRef;
+        GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
+        gRectEffect->ref();
+        return gRectEffect;
     }
 
     virtual ~GrRectEffect() {}
index f217262536a70e112d53cc9b750b85f311b911b1..4b795287afdb92382779a088a28b9ef07ed81f3c 100644 (file)
@@ -51,18 +51,15 @@ inline bool circle_stays_circle(const SkMatrix& m) {
 class CircleEdgeEffect : public GrEffect {
 public:
     static GrEffectRef* Create(bool stroke) {
-        // we go through this so we only have one copy of each effect (stroked/filled)
-        static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef(
-                        CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEffect, (true)))));
-        static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef(
-                        CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEffect, (false)))));
+        GR_CREATE_STATIC_EFFECT(gCircleStrokeEdge, CircleEdgeEffect, (true));
+        GR_CREATE_STATIC_EFFECT(gCircleFillEdge, CircleEdgeEffect, (false));
 
         if (stroke) {
-            gCircleStrokeEdgeEffectRef.get()->ref();
-            return gCircleStrokeEdgeEffectRef;
+            gCircleStrokeEdge->ref();
+            return gCircleStrokeEdge;
         } else {
-            gCircleFillEdgeEffectRef.get()->ref();
-            return gCircleFillEdgeEffectRef;
+            gCircleFillEdge->ref();
+            return gCircleFillEdge;
         }
     }
 
@@ -162,18 +159,15 @@ GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random,
 class EllipseEdgeEffect : public GrEffect {
 public:
     static GrEffectRef* Create(bool stroke) {
-        // we go through this so we only have one copy of each effect (stroked/filled)
-        static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef(
-                        CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEffect, (true)))));
-        static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef(
-                        CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEffect, (false)))));
+        GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true));
+        GR_CREATE_STATIC_EFFECT(gEllipseFillEdge, EllipseEdgeEffect, (false));
 
         if (stroke) {
-            gEllipseStrokeEdgeEffectRef.get()->ref();
-            return gEllipseStrokeEdgeEffectRef;
+            gEllipseStrokeEdge->ref();
+            return gEllipseStrokeEdge;
         } else {
-            gEllipseFillEdgeEffectRef.get()->ref();
-            return gEllipseFillEdgeEffectRef;
+            gEllipseFillEdge->ref();
+            return gEllipseFillEdge;
         }
     }