Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / GrLayerCache.cpp
index 11a97e4..d4f8b70 100644 (file)
@@ -8,14 +8,14 @@
 #include "GrAtlas.h"
 #include "GrGpu.h"
 #include "GrLayerCache.h"
+#include "GrSurfacePriv.h"
 
 DECLARE_SKMESSAGEBUS_MESSAGE(GrPictureDeletedMessage);
 
 #ifdef SK_DEBUG
 void GrCachedLayer::validate(const GrTexture* backingTexture) const {
     SkASSERT(SK_InvalidGenID != fKey.pictureID());
-    SkASSERT(fKey.start() > 0 && fKey.stop() > 0);
-
+    SkASSERT(fKey.start() >= 0);
 
     if (fTexture) {
         // If the layer is in some texture then it must occupy some rectangle
@@ -43,6 +43,15 @@ void GrCachedLayer::validate(const GrTexture* backingTexture) const {
         SkASSERT(fTexture);
         SkASSERT(!fRect.isEmpty());
     }
+
+    // Unfortunately there is a brief time where a layer can be locked
+    // but not used, so we can only check the "used implies locked"
+    // invariant.
+    if (fUses > 0) {
+        SkASSERT(fLocked);
+    } else {
+        SkASSERT(0 == fUses);
+    }
 }
 
 class GrAutoValidateLayer : ::SkNoncopyable {
@@ -72,7 +81,6 @@ private:
 
 GrLayerCache::GrLayerCache(GrContext* context)
     : fContext(context) {
-    this->initAtlas();
     memset(fPlotLocks, 0, sizeof(fPlotLocks));
 }
 
@@ -81,20 +89,24 @@ GrLayerCache::~GrLayerCache() {
     SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
     for (; !iter.done(); ++iter) {
         GrCachedLayer* layer = &(*iter);
+        SkASSERT(0 == layer->uses());
         this->unlock(layer);
         SkDELETE(layer);
     }
 
+    SkASSERT(0 == fPictureHash.count());
+
     // The atlas only lets go of its texture when the atlas is deleted. 
     fAtlas.free();    
 }
 
 void GrLayerCache::initAtlas() {
     SkASSERT(NULL == fAtlas.get());
+    GR_STATIC_ASSERT(kNumPlotsX*kNumPlotsX == GrPictureInfo::kNumPlots);
 
     SkISize textureSize = SkISize::Make(kAtlasTextureWidth, kAtlasTextureHeight);
     fAtlas.reset(SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kSkia8888_GrPixelConfig,
-                                      kRenderTarget_GrTextureFlagBit,
+                                      kRenderTarget_GrSurfaceFlag,
                                       textureSize, kNumPlotsX, kNumPlotsY, false)));
 }
 
@@ -110,70 +122,73 @@ void GrLayerCache::freeAll() {
 
     // The atlas only lets go of its texture when the atlas is deleted. 
     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::abandonContext or freeGpuResources.
-    // TODO: Make GrLayerCache lazily allocate the atlas manager?
-    this->initAtlas();
 }
 
 GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID, 
                                          int start, int stop, 
-                                         const SkIPoint& offset,
+                                         const SkIRect& bounds,
                                          const SkMatrix& ctm,
                                          const SkPaint* paint) {
-    SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0);
+    SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0);
 
-    GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop, offset, ctm, paint));
+    GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop, bounds, ctm, paint));
     fLayerHash.add(layer);
     return layer;
 }
 
 GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID,
-                                       int start, int stop, 
-                                       const SkIPoint& offset,
+                                       int start, 
+                                       const SkIRect& bounds,
                                        const SkMatrix& ctm) {
-    SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0);
-    return fLayerHash.find(GrCachedLayer::Key(pictureID, start, stop, offset, ctm));
+    SkASSERT(pictureID != SK_InvalidGenID && start > 0);
+    return fLayerHash.find(GrCachedLayer::Key(pictureID, start, bounds, ctm));
 }
 
 GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID,
                                                int start, int stop,
-                                               const SkIPoint& offset,
+                                               const SkIRect& bounds,
                                                const SkMatrix& ctm,
                                                const SkPaint* paint) {
-    SkASSERT(pictureID != SK_InvalidGenID && start > 0 && stop > 0);
-    GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, start, stop, offset, ctm));
+    SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0);
+    GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, start, bounds, ctm));
     if (NULL == layer) {
-        layer = this->createLayer(pictureID, start, stop, offset, ctm, paint);
+        layer = this->createLayer(pictureID, start, stop, bounds, ctm, paint);
     }
 
     return layer;
 }
 
-bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool dontAtlas) {
-    SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
+bool GrLayerCache::tryToAtlas(GrCachedLayer* layer, 
+                              const GrSurfaceDesc& desc, 
+                              bool* needsRendering) {
+    SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
+
+    SkASSERT(PlausiblyAtlasable(desc.fWidth, desc.fHeight));
 
     if (layer->locked()) {
         // This layer is already locked
-#ifdef SK_DEBUG
-        if (layer->isAtlased()) {
-            // It claims to be atlased
-            SkASSERT(!dontAtlas);
-            SkASSERT(layer->rect().width() == desc.fWidth);
-            SkASSERT(layer->rect().height() == desc.fHeight);
-        }
-#endif
-        return false;
+        SkASSERT(fAtlas);
+        SkASSERT(layer->isAtlased());
+        SkASSERT(layer->rect().width() == desc.fWidth);
+        SkASSERT(layer->rect().height() == desc.fHeight);
+        *needsRendering = false;
+        return true;
     }
 
     if (layer->isAtlased()) {
+        SkASSERT(fAtlas);
         // Hooray it is still in the atlas - make sure it stays there
-        SkASSERT(!dontAtlas);
         layer->setLocked(true);
-        fPlotLocks[layer->plot()->id()]++;
-        return false;
-    } else if (!dontAtlas && PlausiblyAtlasable(desc.fWidth, desc.fHeight)) {
+        this->incPlotLock(layer->plot()->id());
+        *needsRendering = false;
+        return true;
+    } else {
+        if (!fAtlas) {
+            this->initAtlas();
+            if (!fAtlas) {
+                return false;
+            }
+        }
         // Not in the atlas - will it fit?
         GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
         if (NULL == pictInfo) {
@@ -189,6 +204,9 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool do
             // addToAtlas can allocate the backing texture
             SkDEBUGCODE(avl.setBackingTexture(fAtlas->getTexture()));
             if (plot) {
+#if !GR_CACHE_HOISTED_LAYERS
+                pictInfo->incPlotUsage(plot->id());
+#endif
                 // The layer was successfully added to the atlas
                 GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY,
                                                        SkToS16(desc.fWidth),
@@ -196,7 +214,8 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool do
                 layer->setTexture(fAtlas->getTexture(), bounds);
                 layer->setPlot(plot);
                 layer->setLocked(true);
-                fPlotLocks[layer->plot()->id()]++;
+                this->incPlotLock(layer->plot()->id());
+                *needsRendering = true;
                 return true;
             }
 
@@ -208,19 +227,31 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc, bool do
         }
     }
 
-    // The texture wouldn't fit in the cache - give it it's own texture.
-    // This path always uses a new scratch texture and (thus) doesn't cache anything.
-    // This can yield a lot of re-rendering
-    SkAutoTUnref<GrTexture> tex(fContext->lockAndRefScratchTexture(desc,
-                                                        GrContext::kApprox_ScratchTexMatch));
+    return false;
+}
+
+bool GrLayerCache::lock(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* needsRendering) {
+    if (layer->locked()) {
+        // This layer is already locked
+        *needsRendering = false;
+        return true;
+    }
+
+    SkAutoTUnref<GrTexture> tex(
+        fContext->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
+
+    if (!tex) {
+        return false;
+    }
 
     layer->setTexture(tex, GrIRect16::MakeWH(SkToS16(desc.fWidth), SkToS16(desc.fHeight)));
     layer->setLocked(true);
+    *needsRendering = true;
     return true;
 }
 
 void GrLayerCache::unlock(GrCachedLayer* layer) {
-    SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas->getTexture(), layer);)
+    SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
 
     if (NULL == layer || !layer->locked()) {
         // invalid or not locked
@@ -230,25 +261,32 @@ void GrLayerCache::unlock(GrCachedLayer* layer) {
     if (layer->isAtlased()) {
         const int plotID = layer->plot()->id();
 
-        SkASSERT(fPlotLocks[plotID] > 0);
-        fPlotLocks[plotID]--;
+        this->decPlotLock(plotID);
         // At this point we could aggressively clear out un-locked plots but
         // by delaying we may be able to reuse some of the atlased layers later.
-#if DISABLE_CACHING
+#if !GR_CACHE_HOISTED_LAYERS
         // This testing code aggressively removes the atlased layers. This
         // can be used to separate the performance contribution of less
         // render target pingponging from that due to the re-use of cached layers
         GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
         SkASSERT(pictInfo);
-        
-        GrAtlas::RemovePlot(&pictInfo->fPlotUsage, layer->plot());
+
+        pictInfo->decPlotUsage(plotID);
+
+        if (0 == pictInfo->plotUsage(plotID)) {
+            GrAtlas::RemovePlot(&pictInfo->fPlotUsage, layer->plot());
+
+            if (pictInfo->fPlotUsage.isEmpty()) {
+                fPictureHash.remove(pictInfo->fPictureID);
+                SkDELETE(pictInfo);
+            }
+        }
         
         layer->setPlot(NULL);
         layer->setTexture(NULL, GrIRect16::MakeEmpty());
 #endif
 
     } else {
-        fContext->unlockScratchTexture(layer->texture());
         layer->setTexture(NULL, GrIRect16::MakeEmpty());
     }
 
@@ -264,17 +302,11 @@ void GrLayerCache::validate() const {
     for (; !iter.done(); ++iter) {
         const GrCachedLayer* layer = &(*iter);
 
-        layer->validate(fAtlas->getTexture());
+        layer->validate(fAtlas.get() ? fAtlas->getTexture() : NULL);
 
         const GrPictureInfo* pictInfo = fPictureHash.find(layer->pictureID());
-        if (pictInfo) {
-            // In aggressive cleanup mode a picture info should only exist if
-            // it has some atlased layers
-#if !DISABLE_CACHING
-            SkASSERT(!pictInfo->fPlotUsage.isEmpty());
-#endif
-        } else {
-            // If there is no picture info for this layer then all of its
+        if (!pictInfo) {
+            // If there is no picture info for this picture then all of its
             // layers should be non-atlased.
             SkASSERT(!layer->isAtlased());
         }
@@ -284,6 +316,9 @@ void GrLayerCache::validate() const {
             SkASSERT(pictInfo->fPictureID == layer->pictureID());
 
             SkASSERT(pictInfo->fPlotUsage.contains(layer->plot()));
+#if !GR_CACHE_HOISTED_LAYERS
+            SkASSERT(pictInfo->plotUsage(layer->plot()->id()) > 0);
+#endif
 
             if (layer->locked()) {
                 plotLocks[layer->plot()->id()]++;
@@ -325,6 +360,7 @@ void GrLayerCache::purge(uint32_t pictureID) {
     }
 
     for (int i = 0; i < toBeRemoved.count(); ++i) {
+        SkASSERT(0 == toBeRemoved[i]->uses());
         this->unlock(toBeRemoved[i]);
         fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
         SkDELETE(toBeRemoved[i]);
@@ -339,6 +375,7 @@ void GrLayerCache::purge(uint32_t pictureID) {
 
 bool GrLayerCache::purgePlot() {
     SkDEBUGCODE(GrAutoValidateCache avc(this);)
+    SkASSERT(fAtlas);
 
     GrAtlas::PlotIter iter;
     GrPlot* plot;
@@ -370,27 +407,38 @@ void GrLayerCache::purgePlot(GrPlot* plot) {
     }
 
     for (int i = 0; i < toBeRemoved.count(); ++i) {
+        SkASSERT(0 == toBeRemoved[i]->uses());
         SkASSERT(!toBeRemoved[i]->locked());
 
-        GrPictureInfo* pictInfo = fPictureHash.find(toBeRemoved[i]->pictureID());
-        SkASSERT(pictInfo);
-
-        GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot);
+        uint32_t pictureIDToRemove = toBeRemoved[i]->pictureID();
 
-        // Aggressively remove layers and, if now totally uncached, picture info
+        // Aggressively remove layers and, if it becomes totally uncached, delete the picture info
         fLayerHash.remove(GrCachedLayer::GetKey(*toBeRemoved[i]));
         SkDELETE(toBeRemoved[i]);
 
-        if (pictInfo->fPlotUsage.isEmpty()) {
-            fPictureHash.remove(pictInfo->fPictureID);
-            SkDELETE(pictInfo);
+        GrPictureInfo* pictInfo = fPictureHash.find(pictureIDToRemove);
+        if (pictInfo) {
+#if !GR_CACHE_HOISTED_LAYERS
+            SkASSERT(0 == pictInfo->plotUsage(plot->id()));
+#endif
+            GrAtlas::RemovePlot(&pictInfo->fPlotUsage, plot);
+
+            if (pictInfo->fPlotUsage.isEmpty()) {
+                fPictureHash.remove(pictInfo->fPictureID);
+                SkDELETE(pictInfo);
+            }
         }
     }
 
     plot->resetRects();
 }
 
+#if !GR_CACHE_HOISTED_LAYERS
 void GrLayerCache::purgeAll() {
+    if (!fAtlas) {
+        return;
+    }
+
     GrAtlas::PlotIter iter;
     GrPlot* plot;
     for (plot = fAtlas->iterInit(&iter, GrAtlas::kLRUFirst_IterOrder);
@@ -400,7 +448,12 @@ void GrLayerCache::purgeAll() {
 
         this->purgePlot(plot);
     }
+
+    SkASSERT(0 == fPictureHash.count());
+
+    fContext->discardRenderTarget(fAtlas->getTexture()->asRenderTarget());
 }
+#endif
 
 class GrPictureDeletionListener : public SkPicture::DeletionListener {
     virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{
@@ -426,3 +479,31 @@ void GrLayerCache::processDeletedPictures() {
     }
 }
 
+#ifdef SK_DEVELOPER
+void GrLayerCache::writeLayersToDisk(const SkString& dirName) {
+
+    if (fAtlas) {
+        GrTexture* atlasTexture = fAtlas->getTexture();
+        if (NULL != atlasTexture) {
+            SkString fileName(dirName);
+            fileName.append("\\atlas.png");
+
+            atlasTexture->surfacePriv().savePixels(fileName.c_str());
+        }
+    }
+
+    SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key>::Iter iter(&fLayerHash);
+    for (; !iter.done(); ++iter) {
+        GrCachedLayer* layer = &(*iter);
+
+        if (layer->isAtlased() || !layer->texture()) {
+            continue;
+        }
+
+        SkString fileName(dirName);
+        fileName.appendf("\\%d-%d.png", layer->fKey.pictureID(), layer->fKey.start());
+
+        layer->texture()->surfacePriv().savePixels(fileName.c_str());
+    }
+}
+#endif