Make GrLayerCache use multiple plots in its atlas
authorrobertphillips <robertphillips@google.com>
Thu, 17 Jul 2014 15:26:44 +0000 (08:26 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 17 Jul 2014 15:26:44 +0000 (08:26 -0700)
Until we have a recycling Rectanizer the atlas purging must occur at the GrPlot level. This CL breaks the atlas into four plots to give some room for purging (without trashing the entire atlas).

This is calved off of (Add atlased layer purging - https://codereview.chromium.org/367073002/)

R=jvanverth@google.com

Author: robertphillips@google.com

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

src/gpu/GrLayerCache.cpp
src/gpu/GrLayerCache.h

index 9688cac..ff26750 100644 (file)
@@ -41,8 +41,33 @@ private:
     int      fLayerID;
 };
 
+/**
+ *  PictureKey just wraps a picture's unique ID for GrTHashTable. It is used to
+ *  look up a picture's GrPictureInfo (i.e., its GrPlot usage).
+ */
+class GrLayerCache::PictureKey {
+public:
+    PictureKey(uint32_t pictureID) : fPictureID(pictureID) { }
+
+    uint32_t pictureID() const { return fPictureID; }
+
+    uint32_t getHash() const { return fPictureID; }
+
+    static bool LessThan(const GrPictureInfo& pictInfo, const PictureKey& key) {
+        return pictInfo.fPictureID < key.pictureID();
+    }
+
+    static bool Equals(const GrPictureInfo& pictInfo, const PictureKey& key) {
+        return pictInfo.fPictureID == key.pictureID();
+
+    }
+
+private:
+    uint32_t fPictureID;
+};
+
 #ifdef SK_DEBUG
-void GrCachedLayer::validate(GrTexture* backingTexture) const {
+void GrCachedLayer::validate(const GrTexture* backingTexture) const {
     SkASSERT(SK_InvalidGenID != fPictureID);
     SkASSERT(-1 != fLayerID);
 
@@ -55,6 +80,14 @@ void GrCachedLayer::validate(GrTexture* backingTexture) const {
         }
     } else {
         SkASSERT(fRect.isEmpty());
+        SkASSERT(NULL == fPlot);
+    }
+
+    if (NULL != fPlot) {
+        // If a layer has a plot (i.e., is atlased) then it must point to
+        // the backing texture. Additionally, its rect should be non-empty.
+        SkASSERT(NULL != fTexture && backingTexture == fTexture);
+        SkASSERT(!fRect.isEmpty());
     }
 }
 
@@ -72,9 +105,13 @@ public:
             fLayer->validate(fBackingTexture);
         }
     }
+    void setBackingTexture(GrTexture* backingTexture) {
+        SkASSERT(NULL == fBackingTexture || fBackingTexture == backingTexture);
+        fBackingTexture = backingTexture;
+    }
 
 private:
-    GrTexture* fBackingTexture;
+    const GrTexture* fBackingTexture;
     const GrCachedLayer* fLayer;
 };
 #endif
@@ -106,7 +143,7 @@ void GrLayerCache::initAtlas() {
     SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
     fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
                                       kRenderTarget_GrTextureFlagBit,
-                                      textureSize, 1, 1, false)));
+                                      textureSize, kNumPlotsX, kNumPlotsY, false)));
 }
 
 void GrLayerCache::freeAll() {
@@ -165,14 +202,26 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {
     }
 
 #if USE_ATLAS
-    SkIPoint16 loc;
-    GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, desc.fWidth, desc.fHeight, NULL, &loc);
-    if (NULL != plot) {
-        GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, 
-                                               SkToS16(desc.fWidth), SkToS16(desc.fHeight));
-        layer->setTexture(fAtlas->getTexture(), bounds);
-        layer->setAtlased(true);
-        return false;
+    {
+        GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(layer->pictureID()));
+        if (NULL == pictInfo) {
+            pictInfo = SkNEW_ARGS(GrPictureInfo, (layer->pictureID()));
+            fPictureHash.insert(PictureKey(layer->pictureID()), pictInfo);
+        }
+
+        SkIPoint16 loc;
+        GrPlot* plot = fAtlas->addToAtlas(&pictInfo->fPlotUsage, 
+                                          desc.fWidth, desc.fHeight, 
+                                          NULL, &loc);
+        // addToAtlas can allocate the backing texture
+        SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture()));
+        if (NULL != plot) {
+            GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
+                                                   SkToS16(desc.fWidth), SkToS16(desc.fHeight));
+            layer->setTexture(fAtlas->getTexture(), bounds);
+            layer->setPlot(plot);
+            return false;
+        }
     }
 #endif
 
@@ -192,9 +241,13 @@ void GrLayerCache::unlock(GrCachedLayer* layer) {
     }
 
     if (layer->isAtlased()) {
-        // The atlas doesn't currently use a scratch texture (and we would have
-        // to free up space differently anyways)
-        // TODO: unlock atlas space when a recycling rectanizer is available
+        SkASSERT(layer->texture() == fAtlas->getTexture());
+
+        GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(layer->pictureID()));
+        SkASSERT(NULL != pictInfo);
+        pictInfo->fPlotUsage.isEmpty(); // just to silence compiler warnings for the time being
+
+        // TODO: purging from atlas goes here
     } else {
         fContext->unlockScratchTexture(layer->texture());
         layer->setTexture(NULL, GrIRect16::MakeEmpty());
@@ -247,4 +300,10 @@ void GrLayerCache::purge(const SkPicture* picture) {
         fLayerHash.remove(key, toBeRemoved[i]);
         SkDELETE(toBeRemoved[i]);
     }
+
+    GrPictureInfo* pictInfo = fPictureHash.find(PictureKey(picture->uniqueID()));
+    if (NULL != pictInfo) {
+        fPictureHash.remove(PictureKey(picture->uniqueID()), pictInfo);
+        SkDELETE(pictInfo);
+    }
 }
index 566a738..347fa23 100644 (file)
 #include "GrPictureUtils.h"
 #include "GrRect.h"
 
-class GrGpu;
 class SkPicture;
 
+// GrPictureInfo stores the atlas plots used by a single picture. A single 
+// plot may be used to store layers from multiple pictures.
+struct GrPictureInfo {
+public:
+    GrPictureInfo(uint32_t pictureID) : fPictureID(pictureID) { }
+
+    uint32_t fPictureID;
+
+    GrAtlas::ClientPlotUsage  fPlotUsage;
+};
+
 // GrCachedLayer encapsulates the caching information for a single saveLayer.
 //
 // Atlased layers get a ref to the backing GrTexture while non-atlased layers
 // get a ref to the GrTexture in which they reside. In both cases 'fRect' 
 // contains the layer's extent in its texture.
-//
-// TODO: can we easily reuse the empty space in the non-atlased GrTexture's?
+// Atlased layers also get a pointer to the plot in which they reside.
 struct GrCachedLayer {
 public:
     GrCachedLayer(uint32_t pictureID, int layerID) 
-        : fAtlased(false) {
+        : fPlot(NULL) {
         fPictureID = pictureID;
         fLayerID = layerID;
         fTexture = NULL;
@@ -51,10 +60,15 @@ public:
     GrTexture* texture() { return fTexture; }
     const GrIRect16& rect() const { return fRect; }
 
-    void setAtlased(bool atlased) { fAtlased = atlased; }
-    bool isAtlased() const { return fAtlased; }
+    void setPlot(GrPlot* plot) {
+        SkASSERT(NULL == fPlot);
+        fPlot = plot;
+    }
+    GrPlot* plot() { return fPlot; }
+
+    bool isAtlased() const { return NULL != fPlot; }
 
-    SkDEBUGCODE(void validate(GrTexture* backingTexture) const;)
+    SkDEBUGCODE(void validate(const GrTexture* backingTexture) const;)
 
 private:
     // ID of the picture of which this layer is a part
@@ -69,13 +83,14 @@ private:
     // non-NULL, that means that the texture is locked in the texture cache.
     GrTexture*      fTexture;
 
-    // True if this layer is in an atlas; false otherwise.
-    bool            fAtlased;
-
     // For both atlased and non-atlased layers 'fRect' contains the  bound of
     // the layer in whichever texture it resides. It is empty when 'fTexture'
     // is NULL.
     GrIRect16       fRect;
+
+    // For atlased layers, fPlot stores the atlas plot in which the layer rests.
+    // It is always NULL for non-atlased layers.
+    GrPlot*         fPlot;
 };
 
 // The GrLayerCache caches pre-computed saveLayers for later rendering.
@@ -112,9 +127,19 @@ public:
     SkDEBUGCODE(void validate() const;)
 
 private:
+    static const int kNumPlotsX = 2;
+    static const int kNumPlotsY = 2;
+
     GrContext*                fContext;  // pointer back to owning context
     SkAutoTDelete<GrAtlas>    fAtlas;    // TODO: could lazily allocate
-    GrAtlas::ClientPlotUsage  fPlotUsage;
+
+    // We cache this information here (rather then, say, on the owning picture)
+    // because we want to be able to clean it up as needed (e.g., if a picture
+    // is leaked and never cleans itself up we still want to be able to 
+    // remove the GrPictureInfo once its layers are purged from all the atlas
+    // plots).
+    class PictureKey;
+    GrTHashTable<GrPictureInfo, PictureKey, 7> fPictureHash;
 
     class PictureLayerKey;
     GrTHashTable<GrCachedLayer, PictureLayerKey, 7> fLayerHash;